summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzr-mysql/default.conf8
-rw-r--r--.bzrignore1356
-rwxr-xr-xBUILD/SETUP.sh1
-rwxr-xr-xBUILD/compile-amd64-gprof-no-ndb7
-rwxr-xr-xBUILD/compile-dist1
-rwxr-xr-xBitKeeper/triggers/post-commit10
-rwxr-xr-xBitKeeper/triggers/pre-delta15
-rwxr-xr-xCMakeLists.txt14
-rw-r--r--KNOWN_BUGS.txt86
-rw-r--r--Makefile.am11
-rw-r--r--client/client_priv.h1
-rw-r--r--client/get_password.c4
-rw-r--r--client/mysql.cc38
-rw-r--r--client/mysqladmin.cc4
-rw-r--r--client/mysqlslap.c15
-rw-r--r--client/mysqltest.cc9
-rw-r--r--cmd-line-utils/readline/bind.c2
-rw-r--r--cmd-line-utils/readline/chardefs.h1
-rw-r--r--cmd-line-utils/readline/display.c12
-rw-r--r--cmd-line-utils/readline/histexpand.c3
-rw-r--r--cmd-line-utils/readline/history.c2
-rw-r--r--cmd-line-utils/readline/readline.c15
-rw-r--r--cmd-line-utils/readline/text.c7
-rw-r--r--config/ac-macros/plugins.m46
-rw-r--r--configure.in81
-rw-r--r--dbug/.cvsignore3
-rw-r--r--[-rwxr-xr-x]dbug/CMakeLists.txt0
-rw-r--r--dbug/Makefile.am13
-rw-r--r--dbug/dbug.c805
-rwxr-xr-xdbug/dbug_add_tags.pl4
-rw-r--r--dbug/doinstall.sh15
-rw-r--r--dbug/install.sh64
-rw-r--r--dbug/mklintlib.sh30
-rw-r--r--dbug/qmake.cmd4
-rwxr-xr-xdbug/remove_function_from_trace.pl26
-rwxr-xr-xdbug/tests-t.pl496
-rw-r--r--dbug/tests.c87
-rw-r--r--dbug/user.r39
-rw-r--r--dbug/vargs.h139
-rw-r--r--extra/Makefile.am4
-rw-r--r--extra/replace.c1
-rw-r--r--include/Makefile.am10
-rw-r--r--include/atomic/gcc_builtins.h3
-rw-r--r--include/atomic/generic-msvc.h108
-rw-r--r--include/atomic/nolock.h33
-rw-r--r--include/atomic/rwlock.h24
-rw-r--r--include/atomic/x86-gcc.h31
-rw-r--r--include/atomic/x86-msvc.h96
-rw-r--r--include/config-win.h10
-rw-r--r--include/ft_global.h11
-rw-r--r--include/hash.h2
-rw-r--r--include/keycache.h3
-rw-r--r--include/lf.h262
-rw-r--r--include/m_string.h14
-rw-r--r--include/maria.h476
-rw-r--r--include/my_alloc.h4
-rw-r--r--include/my_atomic.h238
-rw-r--r--include/my_base.h41
-rw-r--r--include/my_dbug.h121
-rw-r--r--include/my_global.h88
-rw-r--r--include/my_handler.h30
-rw-r--r--include/my_pthread.h155
-rw-r--r--include/my_sys.h54
-rw-r--r--include/my_tree.h5
-rw-r--r--include/myisam.h255
-rw-r--r--include/myisamchk.h176
-rw-r--r--include/myisampack.h220
-rw-r--r--include/mysql.h.pp19
-rw-r--r--include/mysql/plugin.h5
-rw-r--r--include/mysql/plugin.h.pp3
-rw-r--r--include/mysql_com.h21
-rw-r--r--include/mysys_err.h3
-rw-r--r--include/thr_lock.h3
-rw-r--r--include/waiting_threads.h130
-rw-r--r--include/wqueue.h27
-rwxr-xr-xlibmysql/CMakeLists.txt4
-rw-r--r--libmysql/Makefile.shared2
-rw-r--r--libmysql/libmysql.c1
-rw-r--r--libmysqld/CMakeLists.txt7
-rw-r--r--mysql-test/extra/rpl_tests/rpl_flsh_tbls.test4
-rw-r--r--mysql-test/extra/rpl_tests/rpl_insert_delayed.test2
-rw-r--r--mysql-test/include/have_maria.inc4
-rw-r--r--mysql-test/include/maria_empty_logs.inc84
-rw-r--r--mysql-test/include/maria_make_snapshot.inc49
-rw-r--r--mysql-test/include/maria_make_snapshot_for_comparison.inc31
-rw-r--r--mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc38
-rw-r--r--mysql-test/include/maria_verify_recovery.inc97
-rw-r--r--mysql-test/include/mysqladmin_shutdown.inc7
-rw-r--r--mysql-test/include/ps_conv.inc2
-rw-r--r--mysql-test/include/varchar.inc5
-rw-r--r--mysql-test/include/wait_for_status_var.inc68
-rw-r--r--mysql-test/include/wait_until_connected_again.inc8
-rw-r--r--mysql-test/include/wait_until_disconnected.inc11
-rw-r--r--mysql-test/lib/mtr_cases.pm45
-rw-r--r--mysql-test/lib/mtr_report.pm3
-rwxr-xr-xmysql-test/mysql-test-run.pl127
-rw-r--r--mysql-test/r/alter_table.result2
-rw-r--r--mysql-test/r/change_user.result6
-rw-r--r--mysql-test/r/create.result4
-rw-r--r--mysql-test/r/ctype_utf8.result2
-rw-r--r--mysql-test/r/delayed.result6
-rw-r--r--mysql-test/r/fulltext.result8
-rw-r--r--mysql-test/r/innodb.result14
-rw-r--r--mysql-test/r/insert.result4
-rw-r--r--mysql-test/r/merge.result2
-rw-r--r--mysql-test/r/mix2_myisam.result28
-rw-r--r--mysql-test/r/myisam.result37
-rw-r--r--mysql-test/r/mysqldump.result6
-rw-r--r--mysql-test/r/old-mode.result18
-rw-r--r--mysql-test/r/ps_2myisam.result2
-rw-r--r--mysql-test/r/ps_3innodb.result2
-rw-r--r--mysql-test/r/ps_4heap.result2
-rw-r--r--mysql-test/r/ps_5merge.result4
-rw-r--r--mysql-test/r/query_cache.result6
-rw-r--r--mysql-test/r/row-checksum-old.result85
-rw-r--r--mysql-test/r/row-checksum.result85
-rw-r--r--mysql-test/r/subselect.result9
-rw-r--r--mysql-test/r/subselect_debug.result3
-rw-r--r--mysql-test/r/variables-big.result10
-rw-r--r--mysql-test/suite/funcs_1/datadict/is_routines.inc1
-rw-r--r--mysql-test/suite/funcs_1/datadict/is_triggers.inc1
-rw-r--r--mysql-test/suite/funcs_1/datadict/is_views.inc1
-rw-r--r--mysql-test/suite/funcs_1/datadict/processlist_priv.inc3
-rw-r--r--mysql-test/suite/funcs_1/datadict/processlist_val.inc1
-rw-r--r--mysql-test/suite/funcs_1/datadict/tables2.inc1
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_events.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_routines.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_tables_is.result64
-rw-r--r--mysql-test/suite/funcs_1/r/is_tables_myisam.result561
-rw-r--r--mysql-test/suite/funcs_1/r/is_tables_mysql.result56
-rw-r--r--mysql-test/suite/funcs_1/r/is_triggers.result2
-rw-r--r--mysql-test/suite/funcs_1/r/is_views.result2
-rw-r--r--mysql-test/suite/funcs_1/r/processlist_priv_no_prot.result4
-rw-r--r--mysql-test/suite/funcs_1/r/processlist_priv_ps.result4
-rw-r--r--mysql-test/suite/funcs_1/r/processlist_val_no_prot.result271
-rw-r--r--mysql-test/suite/funcs_1/r/processlist_val_ps.result271
-rw-r--r--mysql-test/suite/funcs_1/t/is_columns.test1
-rw-r--r--mysql-test/suite/funcs_1/t/is_events.test1
-rw-r--r--mysql-test/suite/maria/r/maria-autozerofill.result20
-rw-r--r--mysql-test/suite/maria/r/maria-big.result222
-rw-r--r--mysql-test/suite/maria/r/maria-big2.result6
-rw-r--r--mysql-test/suite/maria/r/maria-connect.result23
-rw-r--r--mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result1500
-rw-r--r--mysql-test/suite/maria/r/maria-gis-rtree-trans.result1491
-rw-r--r--mysql-test/suite/maria/r/maria-gis-rtree.result1491
-rw-r--r--mysql-test/suite/maria/r/maria-mvcc.result172
-rw-r--r--mysql-test/suite/maria/r/maria-no-logging.result51
-rw-r--r--mysql-test/suite/maria/r/maria-page-checksum.result940
-rw-r--r--mysql-test/suite/maria/r/maria-preload.result163
-rw-r--r--mysql-test/suite/maria/r/maria-purge.result93
-rw-r--r--mysql-test/suite/maria/r/maria-recover.result38
-rw-r--r--mysql-test/suite/maria/r/maria-recovery-big.result79
-rw-r--r--mysql-test/suite/maria/r/maria-recovery-bitmap.result46
-rw-r--r--mysql-test/suite/maria/r/maria-recovery-rtree-ft.result161
-rw-r--r--mysql-test/suite/maria/r/maria-recovery.result242
-rw-r--r--mysql-test/suite/maria/r/maria-recovery2.result147
-rw-r--r--mysql-test/suite/maria/r/maria-recovery3.result94
-rw-r--r--mysql-test/suite/maria/r/maria.result2597
-rw-r--r--mysql-test/suite/maria/r/maria2.result59
-rw-r--r--mysql-test/suite/maria/r/maria3.result553
-rw-r--r--mysql-test/suite/maria/r/maria_notembedded.result56
-rw-r--r--mysql-test/suite/maria/r/maria_partition.result35
-rw-r--r--mysql-test/suite/maria/r/maria_showlog_error.result5
-rw-r--r--mysql-test/suite/maria/r/ps_maria.result3144
-rw-r--r--mysql-test/suite/maria/t/maria-autozerofill.test81
-rw-r--r--mysql-test/suite/maria/t/maria-big.test71
-rw-r--r--mysql-test/suite/maria/t/maria-big2.test4077
-rw-r--r--mysql-test/suite/maria/t/maria-connect.test40
-rw-r--r--mysql-test/suite/maria/t/maria-gis-rtree-dynamic.test891
-rw-r--r--mysql-test/suite/maria/t/maria-gis-rtree-trans.test891
-rw-r--r--mysql-test/suite/maria/t/maria-gis-rtree.test888
-rw-r--r--mysql-test/suite/maria/t/maria-mvcc.test108
-rw-r--r--mysql-test/suite/maria/t/maria-no-logging.test83
-rw-r--r--mysql-test/suite/maria/t/maria-page-checksum.test1559
-rw-r--r--mysql-test/suite/maria/t/maria-preload-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-preload.test124
-rw-r--r--mysql-test/suite/maria/t/maria-purge.test118
-rw-r--r--mysql-test/suite/maria/t/maria-recover-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recover.test65
-rw-r--r--mysql-test/suite/maria/t/maria-recovery-big-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recovery-big.test69
-rw-r--r--mysql-test/suite/maria/t/maria-recovery-bitmap-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recovery-bitmap.test75
-rw-r--r--mysql-test/suite/maria/t/maria-recovery-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recovery-rtree-ft-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recovery-rtree-ft.test217
-rw-r--r--mysql-test/suite/maria/t/maria-recovery.test203
-rw-r--r--mysql-test/suite/maria/t/maria-recovery2-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recovery2.test162
-rw-r--r--mysql-test/suite/maria/t/maria-recovery3-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recovery3.test118
-rw-r--r--mysql-test/suite/maria/t/maria.test1872
-rw-r--r--mysql-test/suite/maria/t/maria2.test110
-rw-r--r--mysql-test/suite/maria/t/maria3.test491
-rw-r--r--mysql-test/suite/maria/t/maria_notembedded.test99
-rw-r--r--mysql-test/suite/maria/t/maria_partition.test57
-rw-r--r--mysql-test/suite/maria/t/maria_showlog_error.test30
-rw-r--r--mysql-test/suite/maria/t/ps_maria.test46
-rw-r--r--mysql-test/suite/ndb/r/ndb_auto_increment.result2
-rw-r--r--mysql-test/suite/ndb/r/ps_7ndb.result2
-rw-r--r--mysql-test/suite/ndb/t/ndb_auto_increment.test2
-rw-r--r--mysql-test/suite/parts/r/partition_alter2_1_maria.result37434
-rw-r--r--mysql-test/suite/parts/r/partition_alter2_2_maria.result37643
-rw-r--r--mysql-test/suite/parts/r/partition_auto_increment_maria.result868
-rw-r--r--mysql-test/suite/parts/t/partition_alter2_1_maria.test83
-rw-r--r--mysql-test/suite/parts/t/partition_alter2_2_maria.test83
-rw-r--r--mysql-test/suite/parts/t/partition_auto_increment_maria.test35
-rw-r--r--mysql-test/suite/rpl/r/rpl_insert.result2
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result8
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_insert_delayed.result2
-rw-r--r--mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result8
-rw-r--r--mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result4
-rw-r--r--mysql-test/suite/rpl/r/rpl_stm_maria.result51
-rw-r--r--mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result2
-rw-r--r--mysql-test/suite/rpl/t/rpl_innodb_bug28430.test1
-rw-r--r--mysql-test/suite/rpl/t/rpl_insert.test2
-rw-r--r--mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test2
-rw-r--r--mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test2
-rw-r--r--mysql-test/suite/rpl/t/rpl_stm_maria.test51
-rw-r--r--mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test2
-rw-r--r--mysql-test/suite/sys_vars/r/sync_frm_basic.result4
-rw-r--r--mysql-test/suite/sys_vars/t/slow_query_log_file_basic-master.opt2
-rw-r--r--mysql-test/suite/sys_vars/t/slow_query_log_file_func-master.opt2
-rw-r--r--mysql-test/suite/sys_vars/t/sync_frm_basic.test4
-rw-r--r--mysql-test/t/alter_table.test2
-rw-r--r--mysql-test/t/bootstrap.test1
-rw-r--r--mysql-test/t/change_user.test5
-rw-r--r--mysql-test/t/crash_commit_before-master.opt1
-rw-r--r--mysql-test/t/create.test2
-rw-r--r--mysql-test/t/ctype_utf8.test2
-rw-r--r--mysql-test/t/delayed.test15
-rw-r--r--mysql-test/t/events_logs_tests-master.opt2
-rw-r--r--mysql-test/t/events_logs_tests.test2
-rw-r--r--mysql-test/t/fulltext.test9
-rw-r--r--mysql-test/t/insert.test2
-rw-r--r--mysql-test/t/log_tables-big-master.opt2
-rw-r--r--mysql-test/t/log_tables-master.opt2
-rw-r--r--mysql-test/t/merge.test15
-rw-r--r--mysql-test/t/multi_statement-master.opt3
-rw-r--r--mysql-test/t/myisam.test23
-rw-r--r--mysql-test/t/mysqldump.test6
-rw-r--r--mysql-test/t/old-mode-master.opt1
-rw-r--r--mysql-test/t/old-mode.test17
-rw-r--r--mysql-test/t/ps-master.opt2
-rw-r--r--mysql-test/t/query_cache.test6
-rw-r--r--mysql-test/t/query_cache_debug.test1
-rw-r--r--mysql-test/t/query_cache_merge.test2
-rw-r--r--mysql-test/t/row-checksum-old-master.opt1
-rw-r--r--mysql-test/t/row-checksum-old.test4
-rw-r--r--mysql-test/t/row-checksum.test62
-rw-r--r--mysql-test/t/show_check-master.opt2
-rw-r--r--mysql-test/t/subselect.test10
-rw-r--r--mysql-test/t/subselect_debug.test3
-rw-r--r--mysql-test/t/union-master.opt2
-rw-r--r--mysql-test/t/variables-big.test6
-rw-r--r--mysql-test/valgrind.supp95
-rw-r--r--[-rwxr-xr-x]mysys/CMakeLists.txt10
-rw-r--r--mysys/Makefile.am34
-rw-r--r--mysys/array.c85
-rw-r--r--mysys/checksum.c14
-rw-r--r--mysys/errors.c4
-rw-r--r--mysys/hash.c70
-rw-r--r--mysys/lf_alloc-pin.c535
-rw-r--r--mysys/lf_dynarray.c208
-rw-r--r--mysys/lf_hash.c506
-rw-r--r--mysys/mf_iocache.c11
-rw-r--r--mysys/mf_iocache2.c4
-rw-r--r--mysys/mf_keycache.c9
-rw-r--r--mysys/mf_keycaches.c277
-rw-r--r--mysys/my_bitmap.c4
-rw-r--r--mysys/my_chmod.c48
-rw-r--r--mysys/my_compress.c4
-rw-r--r--mysys/my_error.c32
-rw-r--r--mysys/my_fopen.c2
-rw-r--r--mysys/my_getncpus.c24
-rw-r--r--mysys/my_getopt.c28
-rw-r--r--mysys/my_getsystime.c1
-rw-r--r--mysys/my_handler.c130
-rw-r--r--mysys/my_handler_errors.h15
-rw-r--r--mysys/my_init.c18
-rw-r--r--mysys/my_lock.c16
-rw-r--r--mysys/my_pread.c39
-rw-r--r--mysys/my_pthread.c6
-rw-r--r--mysys/my_read.c11
-rw-r--r--mysys/my_realloc.c1
-rw-r--r--mysys/my_rnd.c55
-rw-r--r--mysys/my_safehash.c297
-rw-r--r--mysys/my_safehash.h58
-rw-r--r--mysys/my_seek.c4
-rw-r--r--mysys/my_sleep.c2
-rw-r--r--mysys/my_static.c17
-rw-r--r--mysys/my_sync.c2
-rw-r--r--mysys/my_thr_init.c153
-rw-r--r--mysys/my_uuid.c243
-rw-r--r--mysys/my_wincond.c2
-rw-r--r--mysys/my_winthread.c22
-rw-r--r--mysys/my_write.c2
-rw-r--r--mysys/mysys_priv.h3
-rw-r--r--mysys/safemalloc.c1
-rw-r--r--mysys/test_thr_mutex.c162
-rw-r--r--mysys/thr_lock.c125
-rw-r--r--mysys/thr_mutex.c472
-rw-r--r--mysys/thr_rwlock.c2
-rw-r--r--mysys/waiting_threads.c1153
-rw-r--r--mysys/wqueue.c225
-rw-r--r--plugin/daemon_example/daemon_example.cc4
-rw-r--r--scripts/Makefile.am3
-rw-r--r--scripts/mysql_fix_privilege_tables.sh8
-rwxr-xr-xserver-tools/instance-manager/CMakeLists.txt2
-rw-r--r--server-tools/instance-manager/listener.cc6
-rw-r--r--server-tools/instance-manager/mysql_connection.cc9
-rw-r--r--server-tools/instance-manager/mysql_connection.h3
-rw-r--r--server-tools/instance-manager/parse.cc2
-rw-r--r--server-tools/instance-manager/thread_registry.cc1
-rw-r--r--sql-bench/example9
-rw-r--r--sql-bench/myisam.cnf3
-rw-r--r--sql-common/client.c2
-rwxr-xr-xsql/CMakeLists.txt3
-rw-r--r--sql/event_data_objects.cc1
-rw-r--r--sql/event_queue.cc7
-rw-r--r--sql/event_scheduler.cc8
-rw-r--r--sql/events.cc8
-rw-r--r--sql/field.cc17
-rw-r--r--sql/field.h6
-rw-r--r--sql/filesort.cc10
-rw-r--r--sql/ha_ndbcluster.cc6
-rw-r--r--sql/ha_ndbcluster.h2
-rw-r--r--sql/ha_ndbcluster_binlog.cc4
-rw-r--r--sql/ha_partition.cc18
-rw-r--r--sql/ha_partition.h2
-rw-r--r--sql/handler.cc28
-rw-r--r--sql/handler.h45
-rw-r--r--sql/item.cc24
-rw-r--r--sql/item.h13
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_create.cc2
-rw-r--r--sql/item_func.cc26
-rw-r--r--sql/item_func.h3
-rw-r--r--sql/item_strfunc.cc151
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/item_subselect.cc12
-rw-r--r--sql/item_xmlfunc.cc2
-rw-r--r--sql/lex.h2
-rw-r--r--sql/lock.cc8
-rw-r--r--sql/log.cc32
-rw-r--r--sql/log_event.cc13
-rw-r--r--sql/log_event_old.cc4
-rw-r--r--sql/my_lock.c45
-rw-r--r--sql/mysql_priv.h22
-rw-r--r--sql/mysqld.cc445
-rw-r--r--sql/opt_sum.cc10
-rw-r--r--sql/partition_info.cc2
-rw-r--r--sql/password.c42
-rw-r--r--sql/protocol.cc11
-rw-r--r--sql/rpl_filter.cc2
-rw-r--r--sql/rpl_injector.cc1
-rw-r--r--sql/rpl_injector.h2
-rw-r--r--sql/rpl_mi.cc19
-rw-r--r--sql/rpl_rli.cc2
-rw-r--r--sql/set_var.cc61
-rw-r--r--sql/sp_cache.cc6
-rw-r--r--sql/sp_cache.h1
-rw-r--r--sql/spatial.cc2
-rw-r--r--sql/sql_acl.cc2
-rw-r--r--sql/sql_base.cc33
-rw-r--r--sql/sql_cache.cc10
-rw-r--r--sql/sql_class.cc162
-rw-r--r--sql/sql_class.h86
-rw-r--r--sql/sql_crypt.cc2
-rw-r--r--sql/sql_crypt.h2
-rw-r--r--sql/sql_delete.cc15
-rw-r--r--sql/sql_insert.cc103
-rw-r--r--sql/sql_load.cc7
-rw-r--r--sql/sql_parse.cc92
-rw-r--r--sql/sql_plugin.cc4
-rw-r--r--sql/sql_prepare.cc3
-rw-r--r--sql/sql_profile.cc3
-rw-r--r--sql/sql_profile.h21
-rw-r--r--sql/sql_repl.cc2
-rw-r--r--sql/sql_select.cc367
-rw-r--r--sql/sql_select.h5
-rw-r--r--sql/sql_show.cc268
-rw-r--r--sql/sql_sort.h12
-rw-r--r--sql/sql_table.cc138
-rw-r--r--sql/sql_tablespace.cc13
-rw-r--r--sql/sql_union.cc4
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_view.cc1
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/table.cc5
-rw-r--r--sql/time.cc2
-rw-r--r--sql/unireg.cc5
-rw-r--r--storage/archive/ha_archive.cc2
-rw-r--r--storage/archive/ha_archive.h2
-rw-r--r--storage/csv/ha_tina.cc14
-rw-r--r--storage/csv/ha_tina.h4
-rw-r--r--storage/federated/ha_federated.cc4
-rw-r--r--storage/federated/ha_federated.h2
-rw-r--r--storage/heap/hp_write.c2
-rw-r--r--storage/innobase/handler/ha_innodb.cc12
-rw-r--r--storage/maria/CMakeLists.txt91
-rw-r--r--storage/maria/Makefile.am197
-rw-r--r--storage/maria/file_formats.txt71
-rw-r--r--storage/maria/ft_maria.c48
-rw-r--r--storage/maria/ha_maria.cc3323
-rw-r--r--storage/maria/ha_maria.h167
-rw-r--r--storage/maria/lockman.c785
-rw-r--r--storage/maria/lockman.h76
-rw-r--r--storage/maria/ma_bitmap.c2808
-rw-r--r--storage/maria/ma_blockrec.c7173
-rw-r--r--storage/maria/ma_blockrec.h285
-rw-r--r--storage/maria/ma_cache.c107
-rw-r--r--storage/maria/ma_changed.c33
-rw-r--r--storage/maria/ma_check.c6692
-rw-r--r--storage/maria/ma_check_standalone.h106
-rw-r--r--storage/maria/ma_checkpoint.c1235
-rw-r--r--storage/maria/ma_checkpoint.h92
-rw-r--r--storage/maria/ma_checksum.c89
-rw-r--r--storage/maria/ma_close.c207
-rw-r--r--storage/maria/ma_commit.c129
-rw-r--r--storage/maria/ma_commit.h18
-rw-r--r--storage/maria/ma_control_file.c606
-rw-r--r--storage/maria/ma_control_file.h74
-rw-r--r--storage/maria/ma_create.c1419
-rw-r--r--storage/maria/ma_dbug.c202
-rw-r--r--storage/maria/ma_delete.c1537
-rw-r--r--storage/maria/ma_delete_all.c192
-rw-r--r--storage/maria/ma_delete_table.c107
-rw-r--r--storage/maria/ma_dynrec.c2043
-rw-r--r--storage/maria/ma_extra.c615
-rw-r--r--storage/maria/ma_ft_boolean_search.c1013
-rw-r--r--storage/maria/ma_ft_eval.c254
-rw-r--r--storage/maria/ma_ft_eval.h41
-rw-r--r--storage/maria/ma_ft_nlq_search.c377
-rw-r--r--storage/maria/ma_ft_parser.c433
-rw-r--r--storage/maria/ma_ft_stem.c18
-rw-r--r--storage/maria/ma_ft_test1.c317
-rw-r--r--storage/maria/ma_ft_test1.h420
-rw-r--r--storage/maria/ma_ft_update.c373
-rw-r--r--storage/maria/ma_ftdefs.h153
-rw-r--r--storage/maria/ma_fulltext.h27
-rw-r--r--storage/maria/ma_info.c142
-rw-r--r--storage/maria/ma_init.c104
-rw-r--r--storage/maria/ma_key.c733
-rw-r--r--storage/maria/ma_key_recover.c1300
-rw-r--r--storage/maria/ma_key_recover.h119
-rw-r--r--storage/maria/ma_keycache.c164
-rw-r--r--storage/maria/ma_locking.c553
-rw-r--r--storage/maria/ma_loghandler.c8804
-rw-r--r--storage/maria/ma_loghandler.h460
-rw-r--r--storage/maria/ma_loghandler_lsn.h111
-rw-r--r--storage/maria/ma_open.c1913
-rw-r--r--storage/maria/ma_packrec.c1723
-rw-r--r--storage/maria/ma_page.c540
-rw-r--r--storage/maria/ma_pagecache.c5100
-rw-r--r--storage/maria/ma_pagecache.h325
-rw-r--r--storage/maria/ma_pagecaches.c104
-rw-r--r--storage/maria/ma_pagecrc.c378
-rw-r--r--storage/maria/ma_panic.c140
-rw-r--r--storage/maria/ma_preload.c116
-rw-r--r--storage/maria/ma_range.c313
-rw-r--r--storage/maria/ma_recovery.c3591
-rw-r--r--storage/maria/ma_recovery.h33
-rw-r--r--storage/maria/ma_recovery_util.c138
-rw-r--r--storage/maria/ma_recovery_util.h37
-rw-r--r--storage/maria/ma_rename.c135
-rw-r--r--storage/maria/ma_rfirst.c26
-rw-r--r--storage/maria/ma_rkey.c200
-rw-r--r--storage/maria/ma_rlast.c26
-rw-r--r--storage/maria/ma_rnext.c125
-rw-r--r--storage/maria/ma_rnext_same.c108
-rw-r--r--storage/maria/ma_rprev.c86
-rw-r--r--storage/maria/ma_rrnd.c44
-rw-r--r--storage/maria/ma_rsame.c78
-rw-r--r--storage/maria/ma_rsamepos.c63
-rw-r--r--storage/maria/ma_rt_index.c1352
-rw-r--r--storage/maria/ma_rt_index.h59
-rw-r--r--storage/maria/ma_rt_key.c121
-rw-r--r--storage/maria/ma_rt_key.h32
-rw-r--r--storage/maria/ma_rt_mbr.c817
-rw-r--r--storage/maria/ma_rt_mbr.h41
-rw-r--r--storage/maria/ma_rt_split.c563
-rw-r--r--storage/maria/ma_rt_test.c692
-rw-r--r--storage/maria/ma_scan.c74
-rw-r--r--storage/maria/ma_search.c2352
-rw-r--r--storage/maria/ma_sort.c1076
-rw-r--r--storage/maria/ma_sp_defs.h48
-rw-r--r--storage/maria/ma_sp_key.c305
-rw-r--r--storage/maria/ma_sp_test.c568
-rw-r--r--storage/maria/ma_state.c720
-rw-r--r--storage/maria/ma_state.h85
-rw-r--r--storage/maria/ma_static.c107
-rw-r--r--storage/maria/ma_statrec.c302
-rw-r--r--storage/maria/ma_test1.c899
-rw-r--r--storage/maria/ma_test2.c1240
-rw-r--r--storage/maria/ma_test3.c501
-rw-r--r--storage/maria/ma_test_all.res14
-rwxr-xr-xstorage/maria/ma_test_all.sh19
-rw-r--r--storage/maria/ma_test_big.sh22
-rwxr-xr-xstorage/maria/ma_test_force_start.pl237
-rwxr-xr-xstorage/maria/ma_test_recovery8
-rw-r--r--storage/maria/ma_unique.c245
-rw-r--r--storage/maria/ma_update.c253
-rw-r--r--storage/maria/ma_write.c2330
-rw-r--r--storage/maria/maria_chk.c1964
-rw-r--r--storage/maria/maria_def.h1221
-rw-r--r--storage/maria/maria_ftdump.c280
-rw-r--r--storage/maria/maria_pack.c3243
-rw-r--r--storage/maria/maria_read_log.c278
-rwxr-xr-xstorage/maria/maria_rename.sh17
-rw-r--r--storage/maria/plug.in21
-rw-r--r--storage/maria/tablockman.c674
-rw-r--r--storage/maria/tablockman.h87
-rwxr-xr-xstorage/maria/test_pack10
-rw-r--r--storage/maria/trnman.c972
-rw-r--r--storage/maria/trnman.h67
-rw-r--r--storage/maria/trnman_public.h85
-rw-r--r--storage/maria/unittest/CMakeLists.txt98
-rw-r--r--storage/maria/unittest/Makefile.am115
-rw-r--r--storage/maria/unittest/lockman-t.c308
-rw-r--r--storage/maria/unittest/lockman1-t.c334
-rw-r--r--storage/maria/unittest/lockman2-t.c361
-rw-r--r--storage/maria/unittest/ma_control_file-t.c592
-rw-r--r--storage/maria/unittest/ma_loghandler_examples.c65
-rw-r--r--storage/maria/unittest/ma_maria_log_cleanup.c64
-rw-r--r--storage/maria/unittest/ma_pagecache_consist.c498
-rw-r--r--storage/maria/unittest/ma_pagecache_rwconsist.c362
-rw-r--r--storage/maria/unittest/ma_pagecache_rwconsist2.c358
-rw-r--r--storage/maria/unittest/ma_pagecache_single.c765
-rwxr-xr-xstorage/maria/unittest/ma_test_all-t710
-rw-r--r--storage/maria/unittest/ma_test_loghandler-t.c663
-rw-r--r--storage/maria/unittest/ma_test_loghandler_first_lsn-t.c160
-rw-r--r--storage/maria/unittest/ma_test_loghandler_max_lsn-t.c156
-rw-r--r--storage/maria/unittest/ma_test_loghandler_multigroup-t.c746
-rw-r--r--storage/maria/unittest/ma_test_loghandler_multithread-t.c556
-rw-r--r--storage/maria/unittest/ma_test_loghandler_noflush-t.c146
-rw-r--r--storage/maria/unittest/ma_test_loghandler_nologs-t.c195
-rw-r--r--storage/maria/unittest/ma_test_loghandler_pagecache-t.c200
-rw-r--r--storage/maria/unittest/ma_test_loghandler_purge-t.c192
-rw-r--r--storage/maria/unittest/ma_test_recovery.expected1578
-rwxr-xr-xstorage/maria/unittest/ma_test_recovery.pl481
-rw-r--r--storage/maria/unittest/sequence_storage.c110
-rw-r--r--storage/maria/unittest/sequence_storage.h28
-rw-r--r--storage/maria/unittest/test_file.c118
-rw-r--r--storage/maria/unittest/test_file.h29
-rw-r--r--storage/maria/unittest/trnman-t.c175
-rwxr-xr-xstorage/myisam/CMakeLists.txt16
-rw-r--r--storage/myisam/Makefile.am4
-rw-r--r--storage/myisam/ft_boolean_search.c4
-rw-r--r--storage/myisam/ft_myisam.c36
-rw-r--r--storage/myisam/ft_static.c14
-rw-r--r--storage/myisam/ft_stopwords.c17
-rw-r--r--storage/myisam/fulltext.h10
-rw-r--r--storage/myisam/ha_myisam.cc143
-rw-r--r--storage/myisam/ha_myisam.h13
-rw-r--r--storage/myisam/mi_cache.c4
-rw-r--r--storage/myisam/mi_check.c219
-rw-r--r--storage/myisam/mi_checksum.c27
-rw-r--r--storage/myisam/mi_close.c1
-rw-r--r--storage/myisam/mi_create.c48
-rw-r--r--storage/myisam/mi_dbug.c3
-rw-r--r--storage/myisam/mi_delete.c19
-rw-r--r--storage/myisam/mi_dynrec.c12
-rw-r--r--storage/myisam/mi_extra.c7
-rw-r--r--storage/myisam/mi_key.c2
-rw-r--r--storage/myisam/mi_locking.c58
-rw-r--r--storage/myisam/mi_log.c2
-rw-r--r--storage/myisam/mi_open.c50
-rw-r--r--storage/myisam/mi_packrec.c5
-rw-r--r--storage/myisam/mi_page.c2
-rw-r--r--storage/myisam/mi_range.c6
-rw-r--r--storage/myisam/mi_rkey.c2
-rw-r--r--storage/myisam/mi_search.c20
-rw-r--r--storage/myisam/mi_test1.c4
-rw-r--r--storage/myisam/mi_test2.c33
-rw-r--r--storage/myisam/mi_test3.c10
-rw-r--r--storage/myisam/mi_update.c2
-rw-r--r--storage/myisam/mi_write.c12
-rw-r--r--storage/myisam/myisamchk.c43
-rw-r--r--storage/myisam/myisamdef.h844
-rw-r--r--storage/myisam/myisamlog.c2
-rw-r--r--storage/myisam/myisampack.c2
-rw-r--r--storage/myisam/plug.in12
-rw-r--r--storage/myisam/rt_index.c4
-rw-r--r--storage/myisam/rt_test.c23
-rw-r--r--storage/myisam/sort.c14
-rw-r--r--storage/myisammrg/ha_myisammrg.cc15
-rw-r--r--storage/myisammrg/ha_myisammrg.h4
-rw-r--r--storage/myisammrg/myrg_create.c2
-rwxr-xr-xstrings/CMakeLists.txt3
-rw-r--r--strings/bmove512.c2
-rw-r--r--strings/ctype.c4
-rw-r--r--strings/llstr.c1
-rw-r--r--strings/strmake.c46
-rw-r--r--support-files/compiler_warnings.supp6
-rw-r--r--support-files/magic15
-rw-r--r--support-files/mysql.spec.sh39
-rw-r--r--tests/mysql_client_test.c13
-rw-r--r--unittest/Makefile.am4
-rw-r--r--unittest/mysys/CMakeLists.txt34
-rw-r--r--unittest/mysys/Makefile.am10
-rw-r--r--unittest/mysys/lf-t.c178
-rw-r--r--unittest/mysys/my_atomic-t.c155
-rw-r--r--unittest/mysys/thr_template.c92
-rw-r--r--unittest/mysys/waiting_threads-t.c273
-rw-r--r--unittest/mytap/CMakeLists.txt20
-rw-r--r--unittest/mytap/Makefile.am2
-rw-r--r--unittest/mytap/tap.c35
-rw-r--r--unittest/mytap/tap.h43
-rw-r--r--unittest/unit.pl18
-rw-r--r--win/configure.js16
612 files changed, 211422 insertions, 5970 deletions
diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf
index f044f8e62da..ad9b1e0a259 100644
--- a/.bzr-mysql/default.conf
+++ b/.bzr-mysql/default.conf
@@ -1,4 +1,6 @@
[MYSQL]
-post_commit_to = "commits@lists.mysql.com"
-post_push_to = "commits@lists.mysql.com"
-tree_name = "mysql-5.1"
+tree_location = bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-maria/
+post_commit_to = maria@lists.mysql.com
+post_commit_url = bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-maria/
+tree_name = mysql-maria
+project_name = MySQL/Maria
diff --git a/.bzrignore b/.bzrignore
index 01ef6f2ffef..d22056caf01 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1,6 +1,7 @@
*-t
*.Plo
*.Po
+*.Tpo
*.a
*.bb
*.bbg
@@ -9,11 +10,14 @@
*.core
*.d
*.da
+*.dll
*.exe
+*.exp
*.gcda
*.gcno
*.gcov
*.idb
+*.ilk
*.la
*.lai
*.lib
@@ -33,6 +37,9 @@
*.user
*.vcproj
*.vcproj.cmake
+*.dsp
+*.Po
+*.Plo
*/*.dir/*
*/*_pure_*warnings
*/.deps
@@ -86,6 +93,9 @@ BitKeeper/post-commit-manual
BitKeeper/tmp/*
BitKeeper/tmp/bkr3sAHD
BitKeeper/tmp/gone
+BitKeeper/tmp
+BitKeeper/log
+BitKeeper/etc/SCCS
CMakeFiles/*
COPYING
COPYING.LIB
@@ -147,7 +157,6 @@ Makefile.in
Makefile.in'
PENDING/*
TAGS
-VC++Files/client/mysql_amd64.dsp
ac_available_languages_fragment
acinclude.m4
aclocal.m4
@@ -156,6 +165,7 @@ autom4te-2.53.cache/*
autom4te-2.53.cache/output.0
autom4te-2.53.cache/requests
autom4te-2.53.cache/traces.0
+autom4te.cache
autom4te.cache/*
autom4te.cache/output.0
autom4te.cache/requests
@@ -168,37 +178,9 @@ bdb/build_unix/*
bdb/build_vxworks/db.h
bdb/build_vxworks/db_int.h
bdb/build_win32/db.h
-bdb/build_win32/db_archive.dsp
-bdb/build_win32/db_checkpoint.dsp
bdb/build_win32/db_config.h
bdb/build_win32/db_cxx.h
-bdb/build_win32/db_deadlock.dsp
-bdb/build_win32/db_dll.dsp
-bdb/build_win32/db_dump.dsp
bdb/build_win32/db_int.h
-bdb/build_win32/db_java.dsp
-bdb/build_win32/db_load.dsp
-bdb/build_win32/db_perf.dsp
-bdb/build_win32/db_printlog.dsp
-bdb/build_win32/db_recover.dsp
-bdb/build_win32/db_stat.dsp
-bdb/build_win32/db_static.dsp
-bdb/build_win32/db_tcl.dsp
-bdb/build_win32/db_test.dsp
-bdb/build_win32/db_upgrade.dsp
-bdb/build_win32/db_verify.dsp
-bdb/build_win32/ex_access.dsp
-bdb/build_win32/ex_btrec.dsp
-bdb/build_win32/ex_env.dsp
-bdb/build_win32/ex_lock.dsp
-bdb/build_win32/ex_mpool.dsp
-bdb/build_win32/ex_tpcb.dsp
-bdb/build_win32/excxx_access.dsp
-bdb/build_win32/excxx_btrec.dsp
-bdb/build_win32/excxx_env.dsp
-bdb/build_win32/excxx_lock.dsp
-bdb/build_win32/excxx_mpool.dsp
-bdb/build_win32/excxx_tpcb.dsp
bdb/build_win32/include.tcl
bdb/build_win32/libdb.def
bdb/build_win32/libdb.rc
@@ -311,48 +293,7 @@ build_tags.sh
client/#mysql.cc#
client/*.ds?
client/*.vcproj
-client/.deps/base64.Po
-client/.deps/completion_hash.Po
-client/.deps/dummy.Po
-client/.deps/mf_tempdir.Po
-client/.deps/my_bit.Po
-client/.deps/my_bitmap.Po
-client/.deps/my_getsystime.Po
-client/.deps/my_new.Po
-client/.deps/my_user.Po
-client/.deps/my_vle.Po
-client/.deps/mysql.Po
-client/.deps/mysql_upgrade.Po
-client/.deps/mysqladmin.Po
-client/.deps/mysqlbinlog.Po
-client/.deps/mysqlcheck.Po
-client/.deps/mysqldump.Po
-client/.deps/mysqlimport.Po
-client/.deps/mysqlshow.Po
-client/.deps/mysqlslap.Po
-client/.deps/mysqltest.Po
-client/.deps/readline.Po
-client/.deps/sql_string.Po
client/.libs -prune
-client/.libs/lt-mysql
-client/.libs/lt-mysqladmin
-client/.libs/lt-mysqlbinlog
-client/.libs/lt-mysqlcheck
-client/.libs/lt-mysqldump
-client/.libs/lt-mysqlimport
-client/.libs/lt-mysqlshow
-client/.libs/lt-mysqlslap
-client/.libs/lt-mysqltest
-client/.libs/mysql
-client/.libs/mysql_upgrade
-client/.libs/mysqladmin
-client/.libs/mysqlbinlog
-client/.libs/mysqlcheck
-client/.libs/mysqldump
-client/.libs/mysqlimport
-client/.libs/mysqlshow
-client/.libs/mysqlslap
-client/.libs/mysqltest
client/completion_hash.cpp
client/decimal.c
client/insert_test
@@ -402,66 +343,9 @@ client_debug/*
client_release/*
client_test
cmake_install.cmake
-cmd-line-utils/libedit/.deps/chared.Po
-cmd-line-utils/libedit/.deps/common.Po
-cmd-line-utils/libedit/.deps/el.Po
-cmd-line-utils/libedit/.deps/emacs.Po
-cmd-line-utils/libedit/.deps/fcns.Po
-cmd-line-utils/libedit/.deps/fgetln.Po
-cmd-line-utils/libedit/.deps/help.Po
-cmd-line-utils/libedit/.deps/hist.Po
-cmd-line-utils/libedit/.deps/history.Po
-cmd-line-utils/libedit/.deps/key.Po
-cmd-line-utils/libedit/.deps/map.Po
-cmd-line-utils/libedit/.deps/parse.Po
-cmd-line-utils/libedit/.deps/prompt.Po
-cmd-line-utils/libedit/.deps/read.Po
-cmd-line-utils/libedit/.deps/readline.Po
-cmd-line-utils/libedit/.deps/refresh.Po
-cmd-line-utils/libedit/.deps/search.Po
-cmd-line-utils/libedit/.deps/sig.Po
-cmd-line-utils/libedit/.deps/strlcat.Po
-cmd-line-utils/libedit/.deps/strlcpy.Po
-cmd-line-utils/libedit/.deps/term.Po
-cmd-line-utils/libedit/.deps/tokenizer.Po
-cmd-line-utils/libedit/.deps/tty.Po
-cmd-line-utils/libedit/.deps/unvis.Po
-cmd-line-utils/libedit/.deps/vi.Po
-cmd-line-utils/libedit/.deps/vis.Po
cmd-line-utils/libedit/common.h
cmd-line-utils/libedit/makelist
-cmd-line-utils/readline/.deps/bind.Po
-cmd-line-utils/readline/.deps/callback.Po
-cmd-line-utils/readline/.deps/compat.Po
-cmd-line-utils/readline/.deps/complete.Po
-cmd-line-utils/readline/.deps/display.Po
-cmd-line-utils/readline/.deps/funmap.Po
-cmd-line-utils/readline/.deps/histexpand.Po
-cmd-line-utils/readline/.deps/histfile.Po
-cmd-line-utils/readline/.deps/history.Po
-cmd-line-utils/readline/.deps/histsearch.Po
-cmd-line-utils/readline/.deps/input.Po
-cmd-line-utils/readline/.deps/isearch.Po
-cmd-line-utils/readline/.deps/keymaps.Po
-cmd-line-utils/readline/.deps/kill.Po
-cmd-line-utils/readline/.deps/macro.Po
-cmd-line-utils/readline/.deps/mbutil.Po
-cmd-line-utils/readline/.deps/misc.Po
-cmd-line-utils/readline/.deps/nls.Po
-cmd-line-utils/readline/.deps/parens.Po
-cmd-line-utils/readline/.deps/readline.Po
-cmd-line-utils/readline/.deps/rltty.Po
-cmd-line-utils/readline/.deps/savestring.Po
-cmd-line-utils/readline/.deps/search.Po
-cmd-line-utils/readline/.deps/shell.Po
-cmd-line-utils/readline/.deps/signals.Po
-cmd-line-utils/readline/.deps/terminal.Po
-cmd-line-utils/readline/.deps/text.Po
-cmd-line-utils/readline/.deps/tilde.Po
-cmd-line-utils/readline/.deps/undo.Po
-cmd-line-utils/readline/.deps/util.Po
-cmd-line-utils/readline/.deps/vi_mode.Po
-cmd-line-utils/readline/.deps/xmalloc.Po
+comments
comon.h
comp_err/*.ds?
comp_err/*.vcproj
@@ -486,17 +370,13 @@ cscope.po.out
db-*.*.*
dbug/*.ds?
dbug/*.vcproj
-dbug/.deps/dbug.Po
-dbug/.deps/dbug_analyze.Po
-dbug/.deps/factorial.Po
-dbug/.deps/my_main.Po
-dbug/.deps/sanity.Po
dbug/dbug_analyze
dbug/example*.r
dbug/factorial
dbug/factorial.r
dbug/main.r
dbug/output*.r
+dbug/tests
dbug/user.ps
dbug/user.t
debian/control
@@ -506,15 +386,6 @@ emacs.h
examples/*.ds?
examples/*.vcproj
examples/udf_example/udf_example.def
-extra/.deps/charset2html.Po
-extra/.deps/comp_err.Po
-extra/.deps/innochecksum.Po
-extra/.deps/my_print_defaults.Po
-extra/.deps/mysql_waitpid.Po
-extra/.deps/perror.Po
-extra/.deps/replace.Po
-extra/.deps/resolve_stack_dump.Po
-extra/.deps/resolveip.Po
extra/charset2html
extra/comp_err
extra/created_include_files
@@ -531,54 +402,8 @@ extra/resolve_stack_dump
extra/resolveip
extra/sql_state.h
extra/tztime.cc
-extra/yassl/src/.deps/buffer.Plo
-extra/yassl/src/.deps/cert_wrapper.Plo
-extra/yassl/src/.deps/crypto_wrapper.Plo
-extra/yassl/src/.deps/handshake.Plo
-extra/yassl/src/.deps/lock.Plo
-extra/yassl/src/.deps/log.Plo
-extra/yassl/src/.deps/socket_wrapper.Plo
-extra/yassl/src/.deps/ssl.Plo
-extra/yassl/src/.deps/template_instnt.Plo
-extra/yassl/src/.deps/timer.Plo
-extra/yassl/src/.deps/yassl_error.Plo
-extra/yassl/src/.deps/yassl_imp.Plo
-extra/yassl/src/.deps/yassl_int.Plo
-extra/yassl/taocrypt/benchmark/.deps/benchmark-benchmark.Po
extra/yassl/taocrypt/benchmark/benchmark
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-aes.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-aestables.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-algebra.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-arc4.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-asn.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-bftables.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-blowfish.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-coding.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-des.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-dh.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-dsa.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-file.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-hash.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-integer.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-md2.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-md4.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-md5.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-misc.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-random.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-ripemd.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-rsa.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-sha.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-template_instnt.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-tftables.Plo
-extra/yassl/taocrypt/src/.deps/libtaocrypt_la-twofish.Plo
-extra/yassl/taocrypt/test/.deps/test-test.Po
extra/yassl/taocrypt/test/test
-extra/yassl/testsuite/.deps/testsuite-client.Po
-extra/yassl/testsuite/.deps/testsuite-echoclient.Po
-extra/yassl/testsuite/.deps/testsuite-echoserver.Po
-extra/yassl/testsuite/.deps/testsuite-server.Po
-extra/yassl/testsuite/.deps/testsuite-test.Po
-extra/yassl/testsuite/.deps/testsuite-testsuite.Po
extra/yassl/testsuite/testsuite
fcns.c
fcns.h
@@ -643,130 +468,6 @@ lib_release/*
libmysql/*.c
libmysql/*.ds?
libmysql/*.vcproj
-libmysql/.deps/array.Plo
-libmysql/.deps/bchange.Plo
-libmysql/.deps/bcmp.Plo
-libmysql/.deps/bmove.Plo
-libmysql/.deps/bmove_upp.Plo
-libmysql/.deps/charset-def.Plo
-libmysql/.deps/charset.Plo
-libmysql/.deps/client.Plo
-libmysql/.deps/conf_to_src.Po
-libmysql/.deps/ctype-big5.Plo
-libmysql/.deps/ctype-bin.Plo
-libmysql/.deps/ctype-cp932.Plo
-libmysql/.deps/ctype-czech.Plo
-libmysql/.deps/ctype-euc_kr.Plo
-libmysql/.deps/ctype-eucjpms.Plo
-libmysql/.deps/ctype-extra.Plo
-libmysql/.deps/ctype-gb2312.Plo
-libmysql/.deps/ctype-gbk.Plo
-libmysql/.deps/ctype-latin1.Plo
-libmysql/.deps/ctype-mb.Plo
-libmysql/.deps/ctype-simple.Plo
-libmysql/.deps/ctype-sjis.Plo
-libmysql/.deps/ctype-tis620.Plo
-libmysql/.deps/ctype-uca.Plo
-libmysql/.deps/ctype-ucs2.Plo
-libmysql/.deps/ctype-ujis.Plo
-libmysql/.deps/ctype-utf8.Plo
-libmysql/.deps/ctype-win1250ch.Plo
-libmysql/.deps/ctype.Plo
-libmysql/.deps/dbug.Plo
-libmysql/.deps/default.Plo
-libmysql/.deps/default_modify.Plo
-libmysql/.deps/errmsg.Plo
-libmysql/.deps/errors.Plo
-libmysql/.deps/get_password.Plo
-libmysql/.deps/hash.Plo
-libmysql/.deps/int2str.Plo
-libmysql/.deps/is_prefix.Plo
-libmysql/.deps/libmysql.Plo
-libmysql/.deps/list.Plo
-libmysql/.deps/llstr.Plo
-libmysql/.deps/longlong2str.Plo
-libmysql/.deps/manager.Plo
-libmysql/.deps/md5.Plo
-libmysql/.deps/mf_cache.Plo
-libmysql/.deps/mf_dirname.Plo
-libmysql/.deps/mf_fn_ext.Plo
-libmysql/.deps/mf_format.Plo
-libmysql/.deps/mf_iocache.Plo
-libmysql/.deps/mf_iocache2.Plo
-libmysql/.deps/mf_loadpath.Plo
-libmysql/.deps/mf_pack.Plo
-libmysql/.deps/mf_path.Plo
-libmysql/.deps/mf_tempfile.Plo
-libmysql/.deps/mf_unixpath.Plo
-libmysql/.deps/mf_wcomp.Plo
-libmysql/.deps/mulalloc.Plo
-libmysql/.deps/my_alloc.Plo
-libmysql/.deps/my_chsize.Plo
-libmysql/.deps/my_compress.Plo
-libmysql/.deps/my_create.Plo
-libmysql/.deps/my_delete.Plo
-libmysql/.deps/my_div.Plo
-libmysql/.deps/my_error.Plo
-libmysql/.deps/my_file.Plo
-libmysql/.deps/my_fopen.Plo
-libmysql/.deps/my_fstream.Plo
-libmysql/.deps/my_gethostbyname.Plo
-libmysql/.deps/my_getopt.Plo
-libmysql/.deps/my_getwd.Plo
-libmysql/.deps/my_init.Plo
-libmysql/.deps/my_lib.Plo
-libmysql/.deps/my_malloc.Plo
-libmysql/.deps/my_messnc.Plo
-libmysql/.deps/my_net.Plo
-libmysql/.deps/my_once.Plo
-libmysql/.deps/my_open.Plo
-libmysql/.deps/my_port.Plo
-libmysql/.deps/my_pread.Plo
-libmysql/.deps/my_pthread.Plo
-libmysql/.deps/my_read.Plo
-libmysql/.deps/my_realloc.Plo
-libmysql/.deps/my_rename.Plo
-libmysql/.deps/my_seek.Plo
-libmysql/.deps/my_sleep.Plo
-libmysql/.deps/my_static.Plo
-libmysql/.deps/my_strtoll10.Plo
-libmysql/.deps/my_symlink.Plo
-libmysql/.deps/my_thr_init.Plo
-libmysql/.deps/my_time.Plo
-libmysql/.deps/my_vsnprintf.Plo
-libmysql/.deps/my_write.Plo
-libmysql/.deps/net.Plo
-libmysql/.deps/pack.Plo
-libmysql/.deps/password.Plo
-libmysql/.deps/safemalloc.Plo
-libmysql/.deps/sha1.Plo
-libmysql/.deps/str2int.Plo
-libmysql/.deps/str_alloc.Plo
-libmysql/.deps/strcend.Plo
-libmysql/.deps/strcont.Plo
-libmysql/.deps/strend.Plo
-libmysql/.deps/strfill.Plo
-libmysql/.deps/string.Plo
-libmysql/.deps/strinstr.Plo
-libmysql/.deps/strmake.Plo
-libmysql/.deps/strmov.Plo
-libmysql/.deps/strnlen.Plo
-libmysql/.deps/strnmov.Plo
-libmysql/.deps/strtod.Plo
-libmysql/.deps/strtoll.Plo
-libmysql/.deps/strtoull.Plo
-libmysql/.deps/strxmov.Plo
-libmysql/.deps/strxnmov.Plo
-libmysql/.deps/thr_mutex.Plo
-libmysql/.deps/typelib.Plo
-libmysql/.deps/vio.Plo
-libmysql/.deps/viosocket.Plo
-libmysql/.deps/viossl.Plo
-libmysql/.deps/viosslfactories.Plo
-libmysql/.deps/xml.Plo
-libmysql/.libs/libmysqlclient.lai
-libmysql/.libs/libmysqlclient.so.15
-libmysql/.libs/libmysqlclient.so.15.0.0
libmysql/conf_to_src
libmysql/debug/libmysql.exp
libmysql/libmysql.ver
@@ -779,130 +480,6 @@ libmysql/release/libmysql.exp
libmysql/vio_priv.h
libmysql/viosocket.o.6WmSJk
libmysql_r/*.c
-libmysql_r/.deps/array.Plo
-libmysql_r/.deps/bchange.Plo
-libmysql_r/.deps/bcmp.Plo
-libmysql_r/.deps/bmove.Plo
-libmysql_r/.deps/bmove_upp.Plo
-libmysql_r/.deps/charset-def.Plo
-libmysql_r/.deps/charset.Plo
-libmysql_r/.deps/client.Plo
-libmysql_r/.deps/conf_to_src.Po
-libmysql_r/.deps/ctype-big5.Plo
-libmysql_r/.deps/ctype-bin.Plo
-libmysql_r/.deps/ctype-cp932.Plo
-libmysql_r/.deps/ctype-czech.Plo
-libmysql_r/.deps/ctype-euc_kr.Plo
-libmysql_r/.deps/ctype-eucjpms.Plo
-libmysql_r/.deps/ctype-extra.Plo
-libmysql_r/.deps/ctype-gb2312.Plo
-libmysql_r/.deps/ctype-gbk.Plo
-libmysql_r/.deps/ctype-latin1.Plo
-libmysql_r/.deps/ctype-mb.Plo
-libmysql_r/.deps/ctype-simple.Plo
-libmysql_r/.deps/ctype-sjis.Plo
-libmysql_r/.deps/ctype-tis620.Plo
-libmysql_r/.deps/ctype-uca.Plo
-libmysql_r/.deps/ctype-ucs2.Plo
-libmysql_r/.deps/ctype-ujis.Plo
-libmysql_r/.deps/ctype-utf8.Plo
-libmysql_r/.deps/ctype-win1250ch.Plo
-libmysql_r/.deps/ctype.Plo
-libmysql_r/.deps/dbug.Plo
-libmysql_r/.deps/default.Plo
-libmysql_r/.deps/default_modify.Plo
-libmysql_r/.deps/errmsg.Plo
-libmysql_r/.deps/errors.Plo
-libmysql_r/.deps/get_password.Plo
-libmysql_r/.deps/hash.Plo
-libmysql_r/.deps/int2str.Plo
-libmysql_r/.deps/is_prefix.Plo
-libmysql_r/.deps/libmysql.Plo
-libmysql_r/.deps/list.Plo
-libmysql_r/.deps/llstr.Plo
-libmysql_r/.deps/longlong2str.Plo
-libmysql_r/.deps/manager.Plo
-libmysql_r/.deps/md5.Plo
-libmysql_r/.deps/mf_cache.Plo
-libmysql_r/.deps/mf_dirname.Plo
-libmysql_r/.deps/mf_fn_ext.Plo
-libmysql_r/.deps/mf_format.Plo
-libmysql_r/.deps/mf_iocache.Plo
-libmysql_r/.deps/mf_iocache2.Plo
-libmysql_r/.deps/mf_loadpath.Plo
-libmysql_r/.deps/mf_pack.Plo
-libmysql_r/.deps/mf_path.Plo
-libmysql_r/.deps/mf_tempfile.Plo
-libmysql_r/.deps/mf_unixpath.Plo
-libmysql_r/.deps/mf_wcomp.Plo
-libmysql_r/.deps/mulalloc.Plo
-libmysql_r/.deps/my_alloc.Plo
-libmysql_r/.deps/my_chsize.Plo
-libmysql_r/.deps/my_compress.Plo
-libmysql_r/.deps/my_create.Plo
-libmysql_r/.deps/my_delete.Plo
-libmysql_r/.deps/my_div.Plo
-libmysql_r/.deps/my_error.Plo
-libmysql_r/.deps/my_file.Plo
-libmysql_r/.deps/my_fopen.Plo
-libmysql_r/.deps/my_fstream.Plo
-libmysql_r/.deps/my_gethostbyname.Plo
-libmysql_r/.deps/my_getopt.Plo
-libmysql_r/.deps/my_getwd.Plo
-libmysql_r/.deps/my_init.Plo
-libmysql_r/.deps/my_lib.Plo
-libmysql_r/.deps/my_malloc.Plo
-libmysql_r/.deps/my_messnc.Plo
-libmysql_r/.deps/my_net.Plo
-libmysql_r/.deps/my_once.Plo
-libmysql_r/.deps/my_open.Plo
-libmysql_r/.deps/my_port.Plo
-libmysql_r/.deps/my_pread.Plo
-libmysql_r/.deps/my_pthread.Plo
-libmysql_r/.deps/my_read.Plo
-libmysql_r/.deps/my_realloc.Plo
-libmysql_r/.deps/my_rename.Plo
-libmysql_r/.deps/my_seek.Plo
-libmysql_r/.deps/my_sleep.Plo
-libmysql_r/.deps/my_static.Plo
-libmysql_r/.deps/my_strtoll10.Plo
-libmysql_r/.deps/my_symlink.Plo
-libmysql_r/.deps/my_thr_init.Plo
-libmysql_r/.deps/my_time.Plo
-libmysql_r/.deps/my_vsnprintf.Plo
-libmysql_r/.deps/my_write.Plo
-libmysql_r/.deps/net.Plo
-libmysql_r/.deps/pack.Plo
-libmysql_r/.deps/password.Plo
-libmysql_r/.deps/safemalloc.Plo
-libmysql_r/.deps/sha1.Plo
-libmysql_r/.deps/str2int.Plo
-libmysql_r/.deps/str_alloc.Plo
-libmysql_r/.deps/strcend.Plo
-libmysql_r/.deps/strcont.Plo
-libmysql_r/.deps/strend.Plo
-libmysql_r/.deps/strfill.Plo
-libmysql_r/.deps/string.Plo
-libmysql_r/.deps/strinstr.Plo
-libmysql_r/.deps/strmake.Plo
-libmysql_r/.deps/strmov.Plo
-libmysql_r/.deps/strnlen.Plo
-libmysql_r/.deps/strnmov.Plo
-libmysql_r/.deps/strtod.Plo
-libmysql_r/.deps/strtoll.Plo
-libmysql_r/.deps/strtoull.Plo
-libmysql_r/.deps/strxmov.Plo
-libmysql_r/.deps/strxnmov.Plo
-libmysql_r/.deps/thr_mutex.Plo
-libmysql_r/.deps/typelib.Plo
-libmysql_r/.deps/vio.Plo
-libmysql_r/.deps/viosocket.Plo
-libmysql_r/.deps/viossl.Plo
-libmysql_r/.deps/viosslfactories.Plo
-libmysql_r/.deps/xml.Plo
-libmysql_r/.libs/libmysqlclient_r.lai
-libmysql_r/.libs/libmysqlclient_r.so.15
-libmysql_r/.libs/libmysqlclient_r.so.15.0.0
libmysql_r/acconfig.h
libmysql_r/client_settings.h
libmysql_r/conf_to_src
@@ -912,123 +489,6 @@ libmysql_r/mysys_priv.h
libmysql_r/vio_priv.h
libmysqld/*.ds?
libmysqld/*.vcproj
-libmysqld/.deps/client.Po
-libmysqld/.deps/derror.Po
-libmysqld/.deps/discover.Po
-libmysqld/.deps/emb_qcache.Po
-libmysqld/.deps/errmsg.Po
-libmysqld/.deps/event_data_objects.Po
-libmysqld/.deps/event_db_repository.Po
-libmysqld/.deps/event_queue.Po
-libmysqld/.deps/event_scheduler.Po
-libmysqld/.deps/events.Po
-libmysqld/.deps/field.Po
-libmysqld/.deps/field_conv.Po
-libmysqld/.deps/filesort.Po
-libmysqld/.deps/get_password.Po
-libmysqld/.deps/gstream.Po
-libmysqld/.deps/ha_berkeley.Po
-libmysqld/.deps/ha_federated.Po
-libmysqld/.deps/ha_heap.Po
-libmysqld/.deps/ha_innodb.Po
-libmysqld/.deps/ha_myisam.Po
-libmysqld/.deps/ha_myisammrg.Po
-libmysqld/.deps/ha_ndbcluster.Po
-libmysqld/.deps/ha_ndbcluster_binlog.Po
-libmysqld/.deps/ha_partition.Po
-libmysqld/.deps/handler.Po
-libmysqld/.deps/hash_filo.Po
-libmysqld/.deps/hostname.Po
-libmysqld/.deps/init.Po
-libmysqld/.deps/item.Po
-libmysqld/.deps/item_buff.Po
-libmysqld/.deps/item_cmpfunc.Po
-libmysqld/.deps/item_create.Po
-libmysqld/.deps/item_func.Po
-libmysqld/.deps/item_geofunc.Po
-libmysqld/.deps/item_row.Po
-libmysqld/.deps/item_strfunc.Po
-libmysqld/.deps/item_subselect.Po
-libmysqld/.deps/item_sum.Po
-libmysqld/.deps/item_timefunc.Po
-libmysqld/.deps/item_uniq.Po
-libmysqld/.deps/item_xmlfunc.Po
-libmysqld/.deps/key.Po
-libmysqld/.deps/lib_sql.Po
-libmysqld/.deps/libmysql.Po
-libmysqld/.deps/libmysqld.Po
-libmysqld/.deps/lock.Po
-libmysqld/.deps/log.Po
-libmysqld/.deps/log_event.Po
-libmysqld/.deps/my_decimal.Po
-libmysqld/.deps/my_time.Po
-libmysqld/.deps/my_user.Po
-libmysqld/.deps/net_serv.Po
-libmysqld/.deps/opt_range.Po
-libmysqld/.deps/opt_sum.Po
-libmysqld/.deps/pack.Po
-libmysqld/.deps/parse_file.Po
-libmysqld/.deps/partition_info.Po
-libmysqld/.deps/password.Po
-libmysqld/.deps/procedure.Po
-libmysqld/.deps/protocol.Po
-libmysqld/.deps/records.Po
-libmysqld/.deps/rpl_filter.Po
-libmysqld/.deps/rpl_injector.Po
-libmysqld/.deps/set_var.Po
-libmysqld/.deps/sp.Po
-libmysqld/.deps/sp_cache.Po
-libmysqld/.deps/sp_head.Po
-libmysqld/.deps/sp_pcontext.Po
-libmysqld/.deps/sp_rcontext.Po
-libmysqld/.deps/spatial.Po
-libmysqld/.deps/sql_acl.Po
-libmysqld/.deps/sql_analyse.Po
-libmysqld/.deps/sql_base.Po
-libmysqld/.deps/sql_builtin.Po
-libmysqld/.deps/sql_cache.Po
-libmysqld/.deps/sql_class.Po
-libmysqld/.deps/sql_crypt.Po
-libmysqld/.deps/sql_cursor.Po
-libmysqld/.deps/sql_db.Po
-libmysqld/.deps/sql_delete.Po
-libmysqld/.deps/sql_derived.Po
-libmysqld/.deps/sql_do.Po
-libmysqld/.deps/sql_error.Po
-libmysqld/.deps/sql_handler.Po
-libmysqld/.deps/sql_help.Po
-libmysqld/.deps/sql_insert.Po
-libmysqld/.deps/sql_lex.Po
-libmysqld/.deps/sql_list.Po
-libmysqld/.deps/sql_load.Po
-libmysqld/.deps/sql_manager.Po
-libmysqld/.deps/sql_map.Po
-libmysqld/.deps/sql_parse.Po
-libmysqld/.deps/sql_partition.Po
-libmysqld/.deps/sql_plugin.Po
-libmysqld/.deps/sql_prepare.Po
-libmysqld/.deps/sql_rename.Po
-libmysqld/.deps/sql_select.Po
-libmysqld/.deps/sql_show.Po
-libmysqld/.deps/sql_state.Po
-libmysqld/.deps/sql_string.Po
-libmysqld/.deps/sql_table.Po
-libmysqld/.deps/sql_tablespace.Po
-libmysqld/.deps/sql_test.Po
-libmysqld/.deps/sql_trigger.Po
-libmysqld/.deps/sql_udf.Po
-libmysqld/.deps/sql_union.Po
-libmysqld/.deps/sql_update.Po
-libmysqld/.deps/sql_view.Po
-libmysqld/.deps/sql_yacc.Po
-libmysqld/.deps/stacktrace.Po
-libmysqld/.deps/strfunc.Po
-libmysqld/.deps/table.Po
-libmysqld/.deps/thr_malloc.Po
-libmysqld/.deps/time.Po
-libmysqld/.deps/tztime.Po
-libmysqld/.deps/uniques.Po
-libmysqld/.deps/unireg.Po
libmysqld/backup_dir
libmysqld/client.c
libmysqld/client_settings.h
@@ -1046,11 +506,6 @@ libmysqld/event_queue.cc
libmysqld/event_scheduler.cc
libmysqld/event_timed.cc
libmysqld/events.cc
-libmysqld/examples/.deps/completion_hash.Po
-libmysqld/examples/.deps/mysql.Po
-libmysqld/examples/.deps/mysql_client_test.Po
-libmysqld/examples/.deps/mysqltest.Po
-libmysqld/examples/.deps/readline.Po
libmysqld/examples/client_test.c
libmysqld/examples/client_test.cc
libmysqld/examples/completion_hash.cc
@@ -1083,6 +538,7 @@ libmysqld/ha_innobase.cc
libmysqld/ha_innodb.cc
libmysqld/ha_isam.cc
libmysqld/ha_isammrg.cc
+libmysqld/ha_maria.cc
libmysqld/ha_myisam.cc
libmysqld/ha_myisammrg.cc
libmysqld/ha_ndbcluster.cc
@@ -1224,7 +680,11 @@ linked_server_sources
linked_tools_sources
locked
ltmain.sh
+ma_test_recovery.output
man/*.1
+maria-win.patch
+maria_log.00000*
+maria_log_control
merge/*.ds?
merge/*.vcproj
missing
@@ -1287,7 +747,6 @@ mysql-test/*.vcproj
mysql-test/.DS_Store
mysql-test/funcs_1.log
mysql-test/funcs_1.tar
-mysql-test/gmon.out
mysql-test/install_test_db
mysql-test/lib/My/SafeProcess/my_safe_process
mysql-test/lib/init_db.sql
@@ -1423,120 +882,6 @@ mysqlserver/*.vcproj
mysys/#mf_iocache.c#
mysys/*.ds?
mysys/*.vcproj
-mysys/.deps/array.Po
-mysys/.deps/base64.Po
-mysys/.deps/charset-def.Po
-mysys/.deps/charset.Po
-mysys/.deps/checksum.Po
-mysys/.deps/default.Po
-mysys/.deps/default_modify.Po
-mysys/.deps/errors.Po
-mysys/.deps/hash.Po
-mysys/.deps/list.Po
-mysys/.deps/md5.Po
-mysys/.deps/mf_brkhant.Po
-mysys/.deps/mf_cache.Po
-mysys/.deps/mf_dirname.Po
-mysys/.deps/mf_fn_ext.Po
-mysys/.deps/mf_format.Po
-mysys/.deps/mf_getdate.Po
-mysys/.deps/mf_iocache.Po
-mysys/.deps/mf_iocache2.Po
-mysys/.deps/mf_keycache.Po
-mysys/.deps/mf_keycaches.Po
-mysys/.deps/mf_loadpath.Po
-mysys/.deps/mf_pack.Po
-mysys/.deps/mf_path.Po
-mysys/.deps/mf_qsort.Po
-mysys/.deps/mf_qsort2.Po
-mysys/.deps/mf_radix.Po
-mysys/.deps/mf_same.Po
-mysys/.deps/mf_sort.Po
-mysys/.deps/mf_strip.Po
-mysys/.deps/mf_tempdir.Po
-mysys/.deps/mf_tempfile.Po
-mysys/.deps/mf_unixpath.Po
-mysys/.deps/mf_wcomp.Po
-mysys/.deps/mf_wfile.Po
-mysys/.deps/mulalloc.Po
-mysys/.deps/my_access.Po
-mysys/.deps/my_aes.Po
-mysys/.deps/my_alarm.Po
-mysys/.deps/my_alloc.Po
-mysys/.deps/my_append.Po
-mysys/.deps/my_atomic.Po
-mysys/.deps/my_bit.Po
-mysys/.deps/my_bitmap.Po
-mysys/.deps/my_chsize.Po
-mysys/.deps/my_clock.Po
-mysys/.deps/my_compress.Po
-mysys/.deps/my_copy.Po
-mysys/.deps/my_crc32.Po
-mysys/.deps/my_create.Po
-mysys/.deps/my_delete.Po
-mysys/.deps/my_div.Po
-mysys/.deps/my_dup.Po
-mysys/.deps/my_error.Po
-mysys/.deps/my_file.Po
-mysys/.deps/my_fopen.Po
-mysys/.deps/my_fstream.Po
-mysys/.deps/my_gethostbyname.Po
-mysys/.deps/my_gethwaddr.Po
-mysys/.deps/my_getncpus.Po
-mysys/.deps/my_getopt.Po
-mysys/.deps/my_getsystime.Po
-mysys/.deps/my_getwd.Po
-mysys/.deps/my_handler.Po
-mysys/.deps/my_init.Po
-mysys/.deps/my_largepage.Po
-mysys/.deps/my_lib.Po
-mysys/.deps/my_libwrap.Po
-mysys/.deps/my_lock.Po
-mysys/.deps/my_lockmem.Po
-mysys/.deps/my_lread.Po
-mysys/.deps/my_lwrite.Po
-mysys/.deps/my_malloc.Po
-mysys/.deps/my_memmem.Po
-mysys/.deps/my_messnc.Po
-mysys/.deps/my_mkdir.Po
-mysys/.deps/my_mmap.Po
-mysys/.deps/my_net.Po
-mysys/.deps/my_netware.Po
-mysys/.deps/my_new.Po
-mysys/.deps/my_once.Po
-mysys/.deps/my_open.Po
-mysys/.deps/my_port.Po
-mysys/.deps/my_pread.Po
-mysys/.deps/my_pthread.Po
-mysys/.deps/my_quick.Po
-mysys/.deps/my_read.Po
-mysys/.deps/my_realloc.Po
-mysys/.deps/my_redel.Po
-mysys/.deps/my_rename.Po
-mysys/.deps/my_seek.Po
-mysys/.deps/my_semaphore.Po
-mysys/.deps/my_sleep.Po
-mysys/.deps/my_static.Po
-mysys/.deps/my_symlink.Po
-mysys/.deps/my_symlink2.Po
-mysys/.deps/my_sync.Po
-mysys/.deps/my_thr_init.Po
-mysys/.deps/my_vle.Po
-mysys/.deps/my_windac.Po
-mysys/.deps/my_write.Po
-mysys/.deps/ptr_cmp.Po
-mysys/.deps/queues.Po
-mysys/.deps/rijndael.Po
-mysys/.deps/safemalloc.Po
-mysys/.deps/sha1.Po
-mysys/.deps/string.Po
-mysys/.deps/thr_alarm.Po
-mysys/.deps/thr_lock.Po
-mysys/.deps/thr_mutex.Po
-mysys/.deps/thr_rwlock.Po
-mysys/.deps/tree.Po
-mysys/.deps/trie.Po
-mysys/.deps/typelib.Po
mysys/charset2html
mysys/getopt.c
mysys/getopt1.c
@@ -1679,48 +1024,16 @@ ndb/lib/libNEWTON_BASICTEST_COMMON.so
ndb/lib/libREP_API.so
ndb/lib/libndbclient.so
ndb/lib/libndbclient_extra.so
-ndb/src/common/debugger/libtrace.dsp
-ndb/src/common/debugger/signaldata/libsignaldataprint.dsp
-ndb/src/common/logger/liblogger.dsp
-ndb/src/common/mgmcommon/libmgmsrvcommon.dsp
ndb/src/common/mgmcommon/printConfig/*.d
-ndb/src/common/portlib/libportlib.dsp
-ndb/src/common/transporter/libtransporter.dsp
-ndb/src/common/util/libgeneral.dsp
ndb/src/common/util/testBitmask.cpp
ndb/src/cw/cpcd/ndb_cpcd
ndb/src/dummy.cpp
-ndb/src/kernel/blocks/backup/libbackup.dsp
ndb/src/kernel/blocks/backup/restore/ndb_restore
-ndb/src/kernel/blocks/cmvmi/libcmvmi.dsp
-ndb/src/kernel/blocks/dbacc/libdbacc.dsp
-ndb/src/kernel/blocks/dbdict/libdbdict.dsp
-ndb/src/kernel/blocks/dbdih/libdbdih.dsp
-ndb/src/kernel/blocks/dblqh/libdblqh.dsp
-ndb/src/kernel/blocks/dbtc/libdbtc.dsp
-ndb/src/kernel/blocks/dbtup/libdbtup.dsp
-ndb/src/kernel/blocks/dbtux/libdbtux.dsp
-ndb/src/kernel/blocks/dbutil/libdbutil.dsp
-ndb/src/kernel/blocks/grep/libgrep.dsp
-ndb/src/kernel/blocks/ndbcntr/libndbcntr.dsp
-ndb/src/kernel/blocks/ndbfs/libndbfs.dsp
-ndb/src/kernel/blocks/qmgr/libqmgr.dsp
-ndb/src/kernel/blocks/suma/libsuma.dsp
-ndb/src/kernel/blocks/trix/libtrix.dsp
-ndb/src/kernel/error/liberror.dsp
ndb/src/kernel/ndbd
-ndb/src/kernel/ndbd.dsp
-ndb/src/kernel/vm/libkernel.dsp
ndb/src/libndb.ver
-ndb/src/libndbclient.dsp
-ndb/src/mgmapi/libmgmapi.dsp
-ndb/src/mgmclient/libndbmgmclient.dsp
ndb/src/mgmclient/ndb_mgm
-ndb/src/mgmclient/ndb_mgm.dsp
ndb/src/mgmclient/test_cpcd/*.d
ndb/src/mgmsrv/ndb_mgmd
-ndb/src/mgmsrv/ndb_mgmd.dsp
-ndb/src/ndbapi/libndbapi.dsp
ndb/test/ndbapi/bank/bankCreator
ndb/test/ndbapi/bank/bankMakeGL
ndb/test/ndbapi/bank/bankSumAccounts
@@ -1733,15 +1046,12 @@ ndb/test/ndbapi/create_tab
ndb/test/ndbapi/drop_all_tabs
ndb/test/ndbapi/flexAsynch
ndb/test/ndbapi/flexBench
-ndb/test/ndbapi/flexBench.dsp
ndb/test/ndbapi/flexHammer
ndb/test/ndbapi/flexTT
ndb/test/ndbapi/testBackup
ndb/test/ndbapi/testBasic
-ndb/test/ndbapi/testBasic.dsp
ndb/test/ndbapi/testBasicAsynch
ndb/test/ndbapi/testBlobs
-ndb/test/ndbapi/testBlobs.dsp
ndb/test/ndbapi/testDataBuffers
ndb/test/ndbapi/testDeadlock
ndb/test/ndbapi/testDict
@@ -1754,7 +1064,6 @@ ndb/test/ndbapi/testOperations
ndb/test/ndbapi/testRestartGci
ndb/test/ndbapi/testSRBank
ndb/test/ndbapi/testScan
-ndb/test/ndbapi/testScan.dsp
ndb/test/ndbapi/testScanInterpreter
ndb/test/ndbapi/testScanPerf
ndb/test/ndbapi/testSystemRestart
@@ -1762,7 +1071,6 @@ ndb/test/ndbapi/testTimeout
ndb/test/ndbapi/testTransactions
ndb/test/ndbapi/test_event
ndb/test/run-test/atrt
-ndb/test/src/libNDBT.dsp
ndb/test/tools/copy_tab
ndb/test/tools/create_index
ndb/test/tools/hugoCalculator
@@ -1780,23 +1088,15 @@ ndb/test/tools/restart
ndb/test/tools/verify_index
ndb/tools/ndb_config
ndb/tools/ndb_delete_all
-ndb/tools/ndb_delete_all.dsp
ndb/tools/ndb_desc
-ndb/tools/ndb_desc.dsp
ndb/tools/ndb_drop_index
-ndb/tools/ndb_drop_index.dsp
ndb/tools/ndb_drop_table
-ndb/tools/ndb_drop_table.dsp
ndb/tools/ndb_restore
ndb/tools/ndb_select_all
-ndb/tools/ndb_select_all.dsp
ndb/tools/ndb_select_count
-ndb/tools/ndb_select_count.dsp
ndb/tools/ndb_show_tables
-ndb/tools/ndb_show_tables.dsp
ndb/tools/ndb_test_platform
ndb/tools/ndb_waiter
-ndb/tools/ndb_waiter.dsp
ndbcluster-1186
ndbcluster-1186/SCCS
ndbcluster-1186/config.ini
@@ -1810,40 +1110,15 @@ ndbcluster-1186/ndb_3.pid
ndbcluster-1186/ndb_3_cluster.log
ndbcluster-1186/ndb_3_out.log
ndbcluster-1186/ndbcluster.pid
-netware/.deps/libmysqlmain.Po
-netware/.deps/my_manage.Po
-netware/.deps/mysql_install_db.Po
-netware/.deps/mysql_test_run.Po
-netware/.deps/mysqld_safe.Po
netware/init_db.sql
netware/libmysql.imp
netware/test_db.sql
pack_isam/*.ds?
perror/*.ds?
perror/*.vcproj
-plugin/fulltext/.deps/mypluglib_la-plugin_example.Plo
-plugin/fulltext/.libs/mypluglib.lai
-plugin/fulltext/.libs/mypluglib.so.0
-plugin/fulltext/.libs/mypluglib.so.0.0.0
-pstack/.deps/bucomm.Po
-pstack/.deps/debug.Po
-pstack/.deps/filemode.Po
-pstack/.deps/ieee.Po
-pstack/.deps/linuxthreads.Po
-pstack/.deps/pstack.Po
-pstack/.deps/rddbg.Po
-pstack/.deps/stabs.Po
pull.log
regex/*.ds?
regex/*.vcproj
-regex/.deps/debug.Po
-regex/.deps/main.Po
-regex/.deps/regcomp.Po
-regex/.deps/regerror.Po
-regex/.deps/regexec.Po
-regex/.deps/regfree.Po
-regex/.deps/reginit.Po
-regex/.deps/split.Po
regex/re
repl-tests/test-repl-ts/repl-timestamp.master.reject
repl-tests/test-repl/foo-dump-slave.master.
@@ -1888,28 +1163,6 @@ scripts/mysqlhotcopy
scripts/mysqlhotcopy.sh.rej
scripts/safe_mysqld
select_test
-server-tools/instance-manager/.deps/buffer.Po
-server-tools/instance-manager/.deps/command.Po
-server-tools/instance-manager/.deps/commands.Po
-server-tools/instance-manager/.deps/guardian.Po
-server-tools/instance-manager/.deps/instance.Po
-server-tools/instance-manager/.deps/instance_map.Po
-server-tools/instance-manager/.deps/instance_options.Po
-server-tools/instance-manager/.deps/liboptions_la-options.Plo
-server-tools/instance-manager/.deps/liboptions_la-priv.Plo
-server-tools/instance-manager/.deps/listener.Po
-server-tools/instance-manager/.deps/log.Po
-server-tools/instance-manager/.deps/manager.Po
-server-tools/instance-manager/.deps/messages.Po
-server-tools/instance-manager/.deps/mysql_connection.Po
-server-tools/instance-manager/.deps/mysqlmanager.Po
-server-tools/instance-manager/.deps/net_serv.Po
-server-tools/instance-manager/.deps/parse.Po
-server-tools/instance-manager/.deps/parse_output.Po
-server-tools/instance-manager/.deps/protocol.Po
-server-tools/instance-manager/.deps/thread_registry.Po
-server-tools/instance-manager/.deps/user_management_commands.Po
-server-tools/instance-manager/.deps/user_map.Po
server-tools/instance-manager/buffer.cpp
server-tools/instance-manager/client.c
server-tools/instance-manager/client_settings.h
@@ -1967,141 +1220,11 @@ sql-bench/test-wisconsin
sql/*.cpp
sql/*.ds?
sql/*.vcproj
-sql/.deps/client.Po
-sql/.deps/derror.Po
-sql/.deps/des_key_file.Po
-sql/.deps/discover.Po
-sql/.deps/event_data_objects.Po
-sql/.deps/event_db_repository.Po
-sql/.deps/event_queue.Po
-sql/.deps/event_scheduler.Po
-sql/.deps/events.Po
-sql/.deps/field.Po
-sql/.deps/field_conv.Po
-sql/.deps/filesort.Po
-sql/.deps/gen_lex_hash.Po
-sql/.deps/gstream.Po
-sql/.deps/ha_berkeley.Po
-sql/.deps/ha_federated.Po
-sql/.deps/ha_heap.Po
-sql/.deps/ha_innodb.Po
-sql/.deps/ha_myisam.Po
-sql/.deps/ha_myisammrg.Po
-sql/.deps/ha_ndbcluster.Po
-sql/.deps/ha_ndbcluster_binlog.Po
-sql/.deps/ha_partition.Po
-sql/.deps/handler.Po
-sql/.deps/hash_filo.Po
-sql/.deps/hostname.Po
-sql/.deps/init.Po
-sql/.deps/item.Po
-sql/.deps/item_buff.Po
-sql/.deps/item_cmpfunc.Po
-sql/.deps/item_create.Po
-sql/.deps/item_func.Po
-sql/.deps/item_geofunc.Po
-sql/.deps/item_row.Po
-sql/.deps/item_strfunc.Po
-sql/.deps/item_subselect.Po
-sql/.deps/item_sum.Po
-sql/.deps/item_timefunc.Po
-sql/.deps/item_uniq.Po
-sql/.deps/item_xmlfunc.Po
-sql/.deps/key.Po
-sql/.deps/lock.Po
-sql/.deps/log.Po
-sql/.deps/log_event.Po
-sql/.deps/mf_iocache.Po
-sql/.deps/mini_client_errors.Po
-sql/.deps/my_decimal.Po
-sql/.deps/my_lock.Po
-sql/.deps/my_time.Po
-sql/.deps/my_user.Po
-sql/.deps/mysql_tzinfo_to_sql.Po
-sql/.deps/mysqld.Po
-sql/.deps/net_serv.Po
-sql/.deps/opt_range.Po
-sql/.deps/opt_sum.Po
-sql/.deps/pack.Po
-sql/.deps/parse_file.Po
-sql/.deps/partition_info.Po
-sql/.deps/password.Po
-sql/.deps/procedure.Po
-sql/.deps/protocol.Po
-sql/.deps/records.Po
-sql/.deps/repl_failsafe.Po
-sql/.deps/rpl_filter.Po
-sql/.deps/rpl_injector.Po
-sql/.deps/rpl_tblmap.Po
-sql/.deps/set_var.Po
-sql/.deps/slave.Po
-sql/.deps/sp.Po
-sql/.deps/sp_cache.Po
-sql/.deps/sp_head.Po
-sql/.deps/sp_pcontext.Po
-sql/.deps/sp_rcontext.Po
-sql/.deps/spatial.Po
-sql/.deps/sql_acl.Po
-sql/.deps/sql_analyse.Po
-sql/.deps/sql_base.Po
-sql/.deps/sql_binlog.Po
-sql/.deps/sql_builtin.Po
-sql/.deps/sql_cache.Po
-sql/.deps/sql_class.Po
-sql/.deps/sql_client.Po
-sql/.deps/sql_crypt.Po
-sql/.deps/sql_cursor.Po
-sql/.deps/sql_db.Po
-sql/.deps/sql_delete.Po
-sql/.deps/sql_derived.Po
-sql/.deps/sql_do.Po
-sql/.deps/sql_error.Po
-sql/.deps/sql_handler.Po
-sql/.deps/sql_help.Po
-sql/.deps/sql_insert.Po
-sql/.deps/sql_lex.Po
-sql/.deps/sql_list.Po
-sql/.deps/sql_load.Po
-sql/.deps/sql_manager.Po
-sql/.deps/sql_map.Po
-sql/.deps/sql_olap.Po
-sql/.deps/sql_parse.Po
-sql/.deps/sql_partition.Po
-sql/.deps/sql_plugin.Po
-sql/.deps/sql_prepare.Po
-sql/.deps/sql_rename.Po
-sql/.deps/sql_repl.Po
-sql/.deps/sql_select.Po
-sql/.deps/sql_show.Po
-sql/.deps/sql_state.Po
-sql/.deps/sql_string.Po
-sql/.deps/sql_table.Po
-sql/.deps/sql_tablespace.Po
-sql/.deps/sql_test.Po
-sql/.deps/sql_trigger.Po
-sql/.deps/sql_udf.Po
-sql/.deps/sql_union.Po
-sql/.deps/sql_update.Po
-sql/.deps/sql_view.Po
-sql/.deps/sql_yacc.Po
-sql/.deps/stacktrace.Po
-sql/.deps/strfunc.Po
-sql/.deps/table.Po
-sql/.deps/thr_malloc.Po
-sql/.deps/time.Po
-sql/.deps/tztime.Po
-sql/.deps/udf_example.Plo
-sql/.deps/uniques.Po
-sql/.deps/unireg.Po
sql/.gdbinit
-sql/.libs/udf_example.lai
-sql/.libs/udf_example.so.0
-sql/.libs/udf_example.so.0.0.0
sql/client.c
sql/Doxyfile
sql/f.c
sql/gen_lex_hash
-sql/gmon.out
sql/handlerton.cc
sql/html
sql/latex
@@ -2126,13 +1249,33 @@ sql/new.cc
sql/pack.c
sql/safe_to_cache_query.txt
sql/share/*.sys
-sql/share/charsets/gmon.out
sql/share/fixerrmsg.pl
-sql/share/gmon.out
sql/share/iso639-2.txt
sql/share/mysql
-sql/share/norwegian-ny/errmsg.sys
-sql/share/norwegian/errmsg.sys
+sql/share/czech/
+sql/share/danish/
+sql/share/dutch/
+sql/share/english/
+sql/share/estonian/
+sql/share/french/
+sql/share/german/
+sql/share/greek/
+sql/share/hungarian/
+sql/share/italian/
+sql/share/japanese/
+sql/share/japanese-sjis/
+sql/share/korean/
+sql/share/norwegian/
+sql/share/norwegian-ny/
+sql/share/polish/
+sql/share/portuguese/
+sql/share/romanian/
+sql/share/russian/
+sql/share/serbian/
+sql/share/slovak/
+sql/share/spanish/
+sql/share/swedish/
+sql/share/ukrainian/
sql/sql_builtin.cc
sql/sql_select.cc.orig
sql/sql_yacc.cc
@@ -2152,12 +1295,6 @@ stamp-h2.in
stamp-h3
stamp-h4
start_mysqld.sh
-storage/archive/.deps/archive_test-archive_test.Po
-storage/archive/.deps/archive_test-azio.Po
-storage/archive/.deps/ha_archive_la-azio.Plo
-storage/archive/.deps/ha_archive_la-ha_archive.Plo
-storage/archive/.deps/libarchive_a-azio.Po
-storage/archive/.deps/libarchive_a-ha_archive.Po
storage/archive/archive_reader
storage/archive/archive_test
storage/bdb/*.ds?
@@ -2179,44 +1316,14 @@ storage/bdb/build_vxworks/db_int.h
storage/bdb/build_vxworks/dbdemo/dbdemo.c
storage/bdb/build_vxworks/dbdemo/dbdemo20.wpj
storage/bdb/build_vxworks/dbdemo/dbdemo22.wpj
-storage/bdb/build_win32/*.dsp
storage/bdb/build_win32/*.h
storage/bdb/build_win32/db.h
-storage/bdb/build_win32/db_archive.dsp
-storage/bdb/build_win32/db_checkpoint.dsp
storage/bdb/build_win32/db_config.h
storage/bdb/build_win32/db_cxx.h
-storage/bdb/build_win32/db_deadlock.dsp
-storage/bdb/build_win32/db_dll.dsp
-storage/bdb/build_win32/db_dump.dsp
storage/bdb/build_win32/db_int.h
-storage/bdb/build_win32/db_java.dsp
-storage/bdb/build_win32/db_load.dsp
-storage/bdb/build_win32/db_perf.dsp
-storage/bdb/build_win32/db_printlog.dsp
-storage/bdb/build_win32/db_recover.dsp
-storage/bdb/build_win32/db_stat.dsp
-storage/bdb/build_win32/db_static.dsp
-storage/bdb/build_win32/db_tcl.dsp
-storage/bdb/build_win32/db_test.dsp
-storage/bdb/build_win32/db_upgrade.dsp
-storage/bdb/build_win32/db_verify.dsp
-storage/bdb/build_win32/ex_access.dsp
-storage/bdb/build_win32/ex_btrec.dsp
-storage/bdb/build_win32/ex_env.dsp
-storage/bdb/build_win32/ex_lock.dsp
-storage/bdb/build_win32/ex_mpool.dsp
-storage/bdb/build_win32/ex_tpcb.dsp
-storage/bdb/build_win32/excxx_access.dsp
-storage/bdb/build_win32/excxx_btrec.dsp
-storage/bdb/build_win32/excxx_env.dsp
-storage/bdb/build_win32/excxx_lock.dsp
-storage/bdb/build_win32/excxx_mpool.dsp
-storage/bdb/build_win32/excxx_tpcb.dsp
storage/bdb/build_win32/include.tcl
storage/bdb/build_win32/libdb.def
storage/bdb/build_win32/libdb.rc
-storage/bdb/build_win64/*.dsp
storage/bdb/build_win64/*.dsw
storage/bdb/build_win64/*.h
storage/bdb/db/crdel_auto.c
@@ -2318,38 +1425,6 @@ storage/bdb/test/include.tcl
storage/bdb/test/logtrack.list
storage/bdb/txn/txn_auto.c
storage/bdb/txn/txn_autop.c
-storage/blackhole/.deps/ha_blackhole_la-ha_blackhole.Plo
-storage/blackhole/.deps/libblackhole_a-ha_blackhole.Po
-storage/csv/.deps/ha_csv_la-ha_tina.Plo
-storage/csv/.deps/libcsv_a-ha_tina.Po
-storage/example/.deps/ha_example_la-ha_example.Plo
-storage/example/.deps/libexample_a-ha_example.Po
-storage/heap/.deps/_check.Po
-storage/heap/.deps/_rectest.Po
-storage/heap/.deps/hp_block.Po
-storage/heap/.deps/hp_clear.Po
-storage/heap/.deps/hp_close.Po
-storage/heap/.deps/hp_create.Po
-storage/heap/.deps/hp_delete.Po
-storage/heap/.deps/hp_extra.Po
-storage/heap/.deps/hp_hash.Po
-storage/heap/.deps/hp_info.Po
-storage/heap/.deps/hp_open.Po
-storage/heap/.deps/hp_panic.Po
-storage/heap/.deps/hp_rename.Po
-storage/heap/.deps/hp_rfirst.Po
-storage/heap/.deps/hp_rkey.Po
-storage/heap/.deps/hp_rlast.Po
-storage/heap/.deps/hp_rnext.Po
-storage/heap/.deps/hp_rprev.Po
-storage/heap/.deps/hp_rrnd.Po
-storage/heap/.deps/hp_rsame.Po
-storage/heap/.deps/hp_scan.Po
-storage/heap/.deps/hp_static.Po
-storage/heap/.deps/hp_test1.Po
-storage/heap/.deps/hp_test2.Po
-storage/heap/.deps/hp_update.Po
-storage/heap/.deps/hp_write.Po
storage/heap/hp_test1
storage/heap/hp_test2
storage/innobase/autom4te-2.53.cache/*
@@ -2360,155 +1435,55 @@ storage/innobase/autom4te.cache/*
storage/innobase/autom4te.cache/output.0
storage/innobase/autom4te.cache/requests
storage/innobase/autom4te.cache/traces.0
-storage/innobase/btr/.deps/btr0btr.Po
-storage/innobase/btr/.deps/btr0cur.Po
-storage/innobase/btr/.deps/btr0pcur.Po
-storage/innobase/btr/.deps/btr0sea.Po
-storage/innobase/buf/.deps/buf0buf.Po
-storage/innobase/buf/.deps/buf0flu.Po
-storage/innobase/buf/.deps/buf0lru.Po
-storage/innobase/buf/.deps/buf0rea.Po
storage/innobase/configure.lineno
storage/innobase/conftest.s1
storage/innobase/conftest.subs
-storage/innobase/data/.deps/data0data.Po
-storage/innobase/data/.deps/data0type.Po
-storage/innobase/dict/.deps/dict0boot.Po
-storage/innobase/dict/.deps/dict0crea.Po
-storage/innobase/dict/.deps/dict0dict.Po
-storage/innobase/dict/.deps/dict0load.Po
-storage/innobase/dict/.deps/dict0mem.Po
-storage/innobase/dyn/.deps/dyn0dyn.Po
-storage/innobase/eval/.deps/eval0eval.Po
-storage/innobase/eval/.deps/eval0proc.Po
-storage/innobase/fil/.deps/fil0fil.Po
-storage/innobase/fsp/.deps/fsp0fsp.Po
-storage/innobase/fut/.deps/fut0fut.Po
-storage/innobase/fut/.deps/fut0lst.Po
-storage/innobase/ha/.deps/ha0ha.Po
-storage/innobase/ha/.deps/hash0hash.Po
storage/innobase/ib_config.h
storage/innobase/ib_config.h.in
-storage/innobase/ibuf/.deps/ibuf0ibuf.Po
-storage/innobase/lock/.deps/lock0lock.Po
-storage/innobase/log/.deps/log0log.Po
-storage/innobase/log/.deps/log0recv.Po
-storage/innobase/mach/.deps/mach0data.Po
-storage/innobase/mem/.deps/mem0mem.Po
-storage/innobase/mem/.deps/mem0pool.Po
storage/innobase/mkinstalldirs
-storage/innobase/mtr/.deps/mtr0log.Po
-storage/innobase/mtr/.deps/mtr0mtr.Po
-storage/innobase/os/.deps/os0file.Po
-storage/innobase/os/.deps/os0proc.Po
-storage/innobase/os/.deps/os0sync.Po
-storage/innobase/os/.deps/os0thread.Po
-storage/innobase/page/.deps/page0cur.Po
-storage/innobase/page/.deps/page0page.Po
-storage/innobase/pars/.deps/lexyy.Po
-storage/innobase/pars/.deps/pars0grm.Po
-storage/innobase/pars/.deps/pars0opt.Po
-storage/innobase/pars/.deps/pars0pars.Po
-storage/innobase/pars/.deps/pars0sym.Po
-storage/innobase/que/.deps/que0que.Po
-storage/innobase/read/.deps/read0read.Po
-storage/innobase/rem/.deps/rem0cmp.Po
-storage/innobase/rem/.deps/rem0rec.Po
-storage/innobase/row/.deps/row0ins.Po
-storage/innobase/row/.deps/row0mysql.Po
-storage/innobase/row/.deps/row0purge.Po
-storage/innobase/row/.deps/row0row.Po
-storage/innobase/row/.deps/row0sel.Po
-storage/innobase/row/.deps/row0uins.Po
-storage/innobase/row/.deps/row0umod.Po
-storage/innobase/row/.deps/row0undo.Po
-storage/innobase/row/.deps/row0upd.Po
-storage/innobase/row/.deps/row0vers.Po
-storage/innobase/srv/.deps/srv0que.Po
-storage/innobase/srv/.deps/srv0srv.Po
-storage/innobase/srv/.deps/srv0start.Po
storage/innobase/stamp-h1
-storage/innobase/sync/.deps/sync0arr.Po
-storage/innobase/sync/.deps/sync0rw.Po
-storage/innobase/sync/.deps/sync0sync.Po
-storage/innobase/thr/.deps/thr0loc.Po
-storage/innobase/trx/.deps/trx0purge.Po
-storage/innobase/trx/.deps/trx0rec.Po
-storage/innobase/trx/.deps/trx0roll.Po
-storage/innobase/trx/.deps/trx0rseg.Po
-storage/innobase/trx/.deps/trx0sys.Po
-storage/innobase/trx/.deps/trx0trx.Po
-storage/innobase/trx/.deps/trx0undo.Po
-storage/innobase/usr/.deps/usr0sess.Po
-storage/innobase/ut/.deps/ut0byte.Po
-storage/innobase/ut/.deps/ut0dbg.Po
-storage/innobase/ut/.deps/ut0list.Po
-storage/innobase/ut/.deps/ut0mem.Po
-storage/innobase/ut/.deps/ut0rnd.Po
-storage/innobase/ut/.deps/ut0ut.Po
-storage/innobase/ut/.deps/ut0vec.Po
-storage/innobase/ut/.deps/ut0wqueue.Po
-storage/myisam/.deps/ft_boolean_search.Po
-storage/myisam/.deps/ft_nlq_search.Po
-storage/myisam/.deps/ft_parser.Po
-storage/myisam/.deps/ft_static.Po
-storage/myisam/.deps/ft_stopwords.Po
-storage/myisam/.deps/ft_update.Po
-storage/myisam/.deps/mi_cache.Po
-storage/myisam/.deps/mi_changed.Po
-storage/myisam/.deps/mi_check.Po
-storage/myisam/.deps/mi_checksum.Po
-storage/myisam/.deps/mi_close.Po
-storage/myisam/.deps/mi_create.Po
-storage/myisam/.deps/mi_dbug.Po
-storage/myisam/.deps/mi_delete.Po
-storage/myisam/.deps/mi_delete_all.Po
-storage/myisam/.deps/mi_delete_table.Po
-storage/myisam/.deps/mi_dynrec.Po
-storage/myisam/.deps/mi_extra.Po
-storage/myisam/.deps/mi_info.Po
-storage/myisam/.deps/mi_key.Po
-storage/myisam/.deps/mi_keycache.Po
-storage/myisam/.deps/mi_locking.Po
-storage/myisam/.deps/mi_log.Po
-storage/myisam/.deps/mi_open.Po
-storage/myisam/.deps/mi_packrec.Po
-storage/myisam/.deps/mi_page.Po
-storage/myisam/.deps/mi_panic.Po
-storage/myisam/.deps/mi_preload.Po
-storage/myisam/.deps/mi_range.Po
-storage/myisam/.deps/mi_rename.Po
-storage/myisam/.deps/mi_rfirst.Po
-storage/myisam/.deps/mi_rkey.Po
-storage/myisam/.deps/mi_rlast.Po
-storage/myisam/.deps/mi_rnext.Po
-storage/myisam/.deps/mi_rnext_same.Po
-storage/myisam/.deps/mi_rprev.Po
-storage/myisam/.deps/mi_rrnd.Po
-storage/myisam/.deps/mi_rsame.Po
-storage/myisam/.deps/mi_rsamepos.Po
-storage/myisam/.deps/mi_scan.Po
-storage/myisam/.deps/mi_search.Po
-storage/myisam/.deps/mi_static.Po
-storage/myisam/.deps/mi_statrec.Po
-storage/myisam/.deps/mi_test1.Po
-storage/myisam/.deps/mi_test2.Po
-storage/myisam/.deps/mi_test3.Po
-storage/myisam/.deps/mi_unique.Po
-storage/myisam/.deps/mi_update.Po
-storage/myisam/.deps/mi_write.Po
-storage/myisam/.deps/myisam_ftdump.Po
-storage/myisam/.deps/myisamchk.Po
-storage/myisam/.deps/myisamlog.Po
-storage/myisam/.deps/myisampack.Po
-storage/myisam/.deps/rt_index.Po
-storage/myisam/.deps/rt_key.Po
-storage/myisam/.deps/rt_mbr.Po
-storage/myisam/.deps/rt_split.Po
-storage/myisam/.deps/rt_test.Po
-storage/myisam/.deps/sort.Po
-storage/myisam/.deps/sp_key.Po
-storage/myisam/.deps/sp_test.Po
+storage/maria/*.MAD
+storage/maria/*.MAI
+storage/maria/ma_rt_test
+storage/maria/ma_sp_test
+storage/maria/ma_test1
+storage/maria/ma_test2
+storage/maria/ma_test3
+storage/maria/ma_test_all
+storage/maria/maria.log
+storage/maria/maria_chk
+storage/maria/maria_control
+storage/maria/maria_dump_log
+storage/maria/maria_ftdump
+storage/maria/maria_log
+storage/maria/maria_log.*
+storage/maria/maria_pack
+storage/maria/maria_read_log
+storage/maria/tmp
+storage/maria/tmp/*
+storage/maria/unittest/ma_pagecache_consist_1k-t-big
+storage/maria/unittest/ma_pagecache_consist_1kHC-t-big
+storage/maria/unittest/ma_pagecache_consist_1kRD-t-big
+storage/maria/unittest/ma_pagecache_consist_1kWR-t-big
+storage/maria/unittest/ma_pagecache_consist_64k-t-big
+storage/maria/unittest/ma_pagecache_consist_64kHC-t-big
+storage/maria/unittest/ma_pagecache_consist_64kRD-t-big
+storage/maria/unittest/ma_pagecache_consist_64kWR-t-big
+storage/maria/unittest/ma_pagecache_single_64k-t-big
+storage/maria/unittest/ma_test_loghandler_long-t-big
+storage/maria/unittest/maria_control
+storage/maria/unittest/mf_pagecache_consist_1k-t-big
+storage/maria/unittest/mf_pagecache_consist_1kHC-t-big
+storage/maria/unittest/mf_pagecache_consist_1kRD-t-big
+storage/maria/unittest/mf_pagecache_consist_1kWR-t-big
+storage/maria/unittest/mf_pagecache_consist_64k-t-big
+storage/maria/unittest/mf_pagecache_consist_64kHC-t-big
+storage/maria/unittest/mf_pagecache_consist_64kRD-t-big
+storage/maria/unittest/mf_pagecache_consist_64kWR-t-big
+storage/maria/unittest/mf_pagecache_single_64k-t-big
+storage/maria/unittest/page_cache_test_file_1
+storage/maria/unittest/pagecache_debug.log
+storage/maria/unittest/tmp/*
storage/myisam/FT1.MYD
storage/myisam/FT1.MYI
storage/myisam/ft_dump
@@ -2534,27 +1509,6 @@ storage/myisam/test1.MYD
storage/myisam/test1.MYI
storage/myisam/test2.MYD
storage/myisam/test2.MYI
-storage/myisammrg/.deps/myrg_close.Po
-storage/myisammrg/.deps/myrg_create.Po
-storage/myisammrg/.deps/myrg_delete.Po
-storage/myisammrg/.deps/myrg_extra.Po
-storage/myisammrg/.deps/myrg_info.Po
-storage/myisammrg/.deps/myrg_locking.Po
-storage/myisammrg/.deps/myrg_open.Po
-storage/myisammrg/.deps/myrg_panic.Po
-storage/myisammrg/.deps/myrg_queue.Po
-storage/myisammrg/.deps/myrg_range.Po
-storage/myisammrg/.deps/myrg_rfirst.Po
-storage/myisammrg/.deps/myrg_rkey.Po
-storage/myisammrg/.deps/myrg_rlast.Po
-storage/myisammrg/.deps/myrg_rnext.Po
-storage/myisammrg/.deps/myrg_rnext_same.Po
-storage/myisammrg/.deps/myrg_rprev.Po
-storage/myisammrg/.deps/myrg_rrnd.Po
-storage/myisammrg/.deps/myrg_rsame.Po
-storage/myisammrg/.deps/myrg_static.Po
-storage/myisammrg/.deps/myrg_update.Po
-storage/myisammrg/.deps/myrg_write.Po
storage/ndb/bin/DbAsyncGenerator
storage/ndb/bin/DbCreate
storage/ndb/bin/acid
@@ -2690,53 +1644,21 @@ storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan
storage/ndb/ndbapi-examples/ndbapi_simple/ndbapi_simple
storage/ndb/ndbapi-examples/ndbapi_simple_dual/ndbapi_simple_dual
storage/ndb/ndbapi-examples/ndbapi_simple_index/ndbapi_simple_index
-storage/ndb/src/common/debugger/libtrace.dsp
-storage/ndb/src/common/debugger/signaldata/libsignaldataprint.dsp
-storage/ndb/src/common/logger/liblogger.dsp
-storage/ndb/src/common/mgmcommon/libmgmsrvcommon.dsp
storage/ndb/src/common/mgmcommon/printConfig/*.d
-storage/ndb/src/common/portlib/libportlib.dsp
-storage/ndb/src/common/transporter/libtransporter.dsp
-storage/ndb/src/common/util/libgeneral.dsp
storage/ndb/src/common/util/testBitmask.cpp
storage/ndb/src/cw/cpcd/ndb_cpcd
storage/ndb/src/dummy.cpp
-storage/ndb/src/kernel/blocks/backup/libbackup.dsp
storage/ndb/src/kernel/blocks/backup/ndb_print_backup_file
storage/ndb/src/kernel/blocks/backup/restore/ndb_restore
-storage/ndb/src/kernel/blocks/cmvmi/libcmvmi.dsp
-storage/ndb/src/kernel/blocks/dbacc/libdbacc.dsp
-storage/ndb/src/kernel/blocks/dbdict/libdbdict.dsp
storage/ndb/src/kernel/blocks/dbdict/ndb_print_schema_file
-storage/ndb/src/kernel/blocks/dbdih/libdbdih.dsp
storage/ndb/src/kernel/blocks/dbdih/ndb_print_sys_file
-storage/ndb/src/kernel/blocks/dblqh/libdblqh.dsp
-storage/ndb/src/kernel/blocks/dbtc/libdbtc.dsp
-storage/ndb/src/kernel/blocks/dbtup/libdbtup.dsp
storage/ndb/src/kernel/blocks/dbtup/test_varpage
-storage/ndb/src/kernel/blocks/dbtux/libdbtux.dsp
-storage/ndb/src/kernel/blocks/dbutil/libdbutil.dsp
-storage/ndb/src/kernel/blocks/grep/libgrep.dsp
storage/ndb/src/kernel/blocks/ndb_print_file
-storage/ndb/src/kernel/blocks/ndbcntr/libndbcntr.dsp
-storage/ndb/src/kernel/blocks/ndbfs/libndbfs.dsp
-storage/ndb/src/kernel/blocks/qmgr/libqmgr.dsp
-storage/ndb/src/kernel/blocks/suma/libsuma.dsp
-storage/ndb/src/kernel/blocks/trix/libtrix.dsp
-storage/ndb/src/kernel/error/liberror.dsp
storage/ndb/src/kernel/ndbd
-storage/ndb/src/kernel/ndbd.dsp
-storage/ndb/src/kernel/vm/libkernel.dsp
storage/ndb/src/libndb.ver
-storage/ndb/src/libndbclient.dsp
-storage/ndb/src/mgmapi/libmgmapi.dsp
-storage/ndb/src/mgmclient/libndbmgmclient.dsp
storage/ndb/src/mgmclient/ndb_mgm
-storage/ndb/src/mgmclient/ndb_mgm.dsp
storage/ndb/src/mgmclient/test_cpcd/*.d
storage/ndb/src/mgmsrv/ndb_mgmd
-storage/ndb/src/mgmsrv/ndb_mgmd.dsp
-storage/ndb/src/ndbapi/libndbapi.dsp
storage/ndb/src/ndbapi/ndberror_check
storage/ndb/test/ndbapi/DbAsyncGenerator
storage/ndb/test/ndbapi/DbCreate
@@ -2752,17 +1674,14 @@ storage/ndb/test/ndbapi/create_tab
storage/ndb/test/ndbapi/drop_all_tabs
storage/ndb/test/ndbapi/flexAsynch
storage/ndb/test/ndbapi/flexBench
-storage/ndb/test/ndbapi/flexBench.dsp
storage/ndb/test/ndbapi/flexHammer
storage/ndb/test/ndbapi/flexTT
storage/ndb/test/ndbapi/ndbapi_slow_select
storage/ndb/test/ndbapi/testBackup
storage/ndb/test/ndbapi/testBasic
-storage/ndb/test/ndbapi/testBasic.dsp
storage/ndb/test/ndbapi/testBasicAsynch
storage/ndb/test/ndbapi/testBitfield
storage/ndb/test/ndbapi/testBlobs
-storage/ndb/test/ndbapi/testBlobs.dsp
storage/ndb/test/ndbapi/testDataBuffers
storage/ndb/test/ndbapi/testDeadlock
storage/ndb/test/ndbapi/testDict
@@ -2780,7 +1699,6 @@ storage/ndb/test/ndbapi/testReadPerf
storage/ndb/test/ndbapi/testRestartGci
storage/ndb/test/ndbapi/testSRBank
storage/ndb/test/ndbapi/testScan
-storage/ndb/test/ndbapi/testScan.dsp
storage/ndb/test/ndbapi/testScanInterpreter
storage/ndb/test/ndbapi/testScanPerf
storage/ndb/test/ndbapi/testSystemRestart
@@ -2789,7 +1707,6 @@ storage/ndb/test/ndbapi/testTransactions
storage/ndb/test/ndbapi/test_event
storage/ndb/test/ndbapi/test_event_merge
storage/ndb/test/run-test/atrt
-storage/ndb/test/src/libNDBT.dsp
storage/ndb/test/tools/copy_tab
storage/ndb/test/tools/create_index
storage/ndb/test/tools/hugoCalculator
@@ -2809,83 +1726,17 @@ storage/ndb/test/tools/restart
storage/ndb/test/tools/verify_index
storage/ndb/tools/ndb_config
storage/ndb/tools/ndb_delete_all
-storage/ndb/tools/ndb_delete_all.dsp
storage/ndb/tools/ndb_desc
-storage/ndb/tools/ndb_desc.dsp
storage/ndb/tools/ndb_drop_index
-storage/ndb/tools/ndb_drop_index.dsp
storage/ndb/tools/ndb_drop_table
-storage/ndb/tools/ndb_drop_table.dsp
storage/ndb/tools/ndb_restore
storage/ndb/tools/ndb_select_all
-storage/ndb/tools/ndb_select_all.dsp
storage/ndb/tools/ndb_select_count
-storage/ndb/tools/ndb_select_count.dsp
storage/ndb/tools/ndb_show_tables
-storage/ndb/tools/ndb_show_tables.dsp
storage/ndb/tools/ndb_test_platform
storage/ndb/tools/ndb_waiter
-storage/ndb/tools/ndb_waiter.dsp
strings/*.ds?
strings/*.vcproj
-strings/.deps/bchange.Po
-strings/.deps/bcmp.Po
-strings/.deps/bfill.Po
-strings/.deps/bmove.Po
-strings/.deps/bmove512.Po
-strings/.deps/bmove_upp.Po
-strings/.deps/conf_to_src.Po
-strings/.deps/ctype-big5.Po
-strings/.deps/ctype-bin.Po
-strings/.deps/ctype-cp932.Po
-strings/.deps/ctype-czech.Po
-strings/.deps/ctype-euc_kr.Po
-strings/.deps/ctype-eucjpms.Po
-strings/.deps/ctype-extra.Po
-strings/.deps/ctype-gb2312.Po
-strings/.deps/ctype-gbk.Po
-strings/.deps/ctype-latin1.Po
-strings/.deps/ctype-mb.Po
-strings/.deps/ctype-simple.Po
-strings/.deps/ctype-sjis.Po
-strings/.deps/ctype-tis620.Po
-strings/.deps/ctype-uca.Po
-strings/.deps/ctype-ucs2.Po
-strings/.deps/ctype-ujis.Po
-strings/.deps/ctype-utf8.Po
-strings/.deps/ctype-win1250ch.Po
-strings/.deps/ctype.Po
-strings/.deps/decimal.Po
-strings/.deps/int2str.Po
-strings/.deps/is_prefix.Po
-strings/.deps/llstr.Po
-strings/.deps/longlong2str.Po
-strings/.deps/longlong2str_asm.Po
-strings/.deps/my_strchr.Po
-strings/.deps/my_strtoll10.Po
-strings/.deps/my_vsnprintf.Po
-strings/.deps/r_strinstr.Po
-strings/.deps/str2int.Po
-strings/.deps/str_alloc.Po
-strings/.deps/strappend.Po
-strings/.deps/strcend.Po
-strings/.deps/strcont.Po
-strings/.deps/strend.Po
-strings/.deps/strfill.Po
-strings/.deps/strinstr.Po
-strings/.deps/strmake.Po
-strings/.deps/strmov.Po
-strings/.deps/strnlen.Po
-strings/.deps/strnmov.Po
-strings/.deps/strstr.Po
-strings/.deps/strtod.Po
-strings/.deps/strtol.Po
-strings/.deps/strtoll.Po
-strings/.deps/strtoul.Po
-strings/.deps/strtoull.Po
-strings/.deps/strxmov.Po
-strings/.deps/strxnmov.Po
-strings/.deps/xml.Po
strings/conf_to_src
strings/ctype_autoconf.c
strings/ctype_extra_sources.c
@@ -2969,17 +1820,11 @@ test/tools/ndb_cpcc
test/tools/restart
test/tools/verify_index
test1/*
+test?.MA?
test_xml
tests/*.ds?
tests/*.vcproj
-tests/.deps/dummy.Po
-tests/.deps/insert_test.Po
-tests/.deps/mysql_client_test.Po
-tests/.deps/select_test.Po
-tests/.deps/thread_test.Po
tests/.libs -prune
-tests/.libs/lt-mysql_client_test
-tests/.libs/mysql_client_test
tests/bug25714
tests/client_test
tests/connect_test
@@ -2995,30 +1840,25 @@ tools/mysqlmngd
tools/mysqltestmanager
tools/mysys_priv.h
unittest/examples/*.t
-unittest/examples/.deps/no_plan-t.Po
-unittest/examples/.deps/simple-t.Po
-unittest/examples/.deps/skip-t.Po
-unittest/examples/.deps/skip_all-t.Po
-unittest/examples/.deps/todo-t.Po
+unittest/maria_control
unittest/mysys/*.t
-unittest/mysys/.deps/base64-t.Po
-unittest/mysys/.deps/bitmap-t.Po
-unittest/mysys/.deps/my_atomic-t.Po
-unittest/mytap/.deps/tap.Po
+unittest/mysys/mf_pagecache_consist_1k-t-big
+unittest/mysys/mf_pagecache_consist_1kHC-t-big
+unittest/mysys/mf_pagecache_consist_1kRD-t-big
+unittest/mysys/mf_pagecache_consist_1kWR-t-big
+unittest/mysys/mf_pagecache_consist_64k-t-big
+unittest/mysys/mf_pagecache_consist_64kHC-t-big
+unittest/mysys/mf_pagecache_consist_64kRD-t-big
+unittest/mysys/mf_pagecache_consist_64kWR-t-big
+unittest/mysys/mf_pagecache_single_64k-t-big
unittest/mytap/t/*.t
-unittest/mytap/t/.deps/basic-t.Po
+unittest/page_cache_test_file_1
+unittest/pagecache_debug.log
+unittest/tmp/*
unittest/unit
vi.h
vio/*.ds?
vio/*.vcproj
-vio/.deps/dummy.Po
-vio/.deps/test-ssl.Po
-vio/.deps/test-sslclient.Po
-vio/.deps/test-sslserver.Po
-vio/.deps/vio.Po
-vio/.deps/viosocket.Po
-vio/.deps/viossl.Po
-vio/.deps/viosslfactories.Po
vio/test-ssl
vio/test-sslclient
vio/test-sslserver
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index 3655d3eae67..7e561e85f58 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -147,6 +147,7 @@ base_configs="--prefix=$prefix --enable-assembler "
base_configs="$base_configs --with-extra-charsets=complex "
base_configs="$base_configs --enable-thread-safe-client "
base_configs="$base_configs --with-big-tables"
+base_configs="$base_configs --with-plugin-maria --with-maria-tmp-tables"
if test -d "$path/../cmd-line-utils/readline"
then
diff --git a/BUILD/compile-amd64-gprof-no-ndb b/BUILD/compile-amd64-gprof-no-ndb
new file mode 100755
index 00000000000..9fd4c67155c
--- /dev/null
+++ b/BUILD/compile-amd64-gprof-no-ndb
@@ -0,0 +1,7 @@
+#! /bin/sh
+path=`dirname $0`
+. "$path/SETUP.sh"
+extra_flags="$amd64_cflags -pg -g"
+extra_configs="$amd64_configs $max_no_ndb_configs --disable-shared $static_link"
+
+. "$path/FINISH.sh"
diff --git a/BUILD/compile-dist b/BUILD/compile-dist
index cf6cefc0969..e7bfb97be41 100755
--- a/BUILD/compile-dist
+++ b/BUILD/compile-dist
@@ -60,6 +60,7 @@ fi
# Make sure to enable all features that affect "make dist"
# Remember that configure restricts the man pages to the configured features !
./configure \
+ --with-maria-storage-engine \
--with-embedded-server \
--with-ndbcluster
$gmake
diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit
index c3a61ed2dde..e3cd589f50b 100755
--- a/BitKeeper/triggers/post-commit
+++ b/BitKeeper/triggers/post-commit
@@ -8,10 +8,10 @@ else
COMMITTER=$USER
fi
FROM=$COMMITTER@mysql.com
-COMMITS=commits@lists.mysql.com
+COMMITS=maria@lists.mysql.com
DOCS=docs-commit@mysql.com
LIMIT=10000
-VERSION="5.1"
+VERSION="maria"
BKROOT=`bk root`
if [ -x /usr/sbin/sendmail ]; then
@@ -73,11 +73,11 @@ else
fi
#++
-# commits@ or dev-private@ mail
+# maria@ or dev-private@ mail
#--
LIST="commits"
-TO="commits@lists.mysql.com"
+TO="maria@lists.mysql.com"
if [ -f .tree-is-private ]
then
LIST="dev-private"
@@ -103,7 +103,7 @@ see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
EOF
bk changes -v -r+
bk rset -r+ -ah | bk gnupatch -h -dup -T
- ) | bk sed -e ${LIMIT}q > $BKROOT/BitKeeper/tmp/commits.txt
+ ) > $BKROOT/BitKeeper/tmp/commits.txt
$SENDMAIL -t < $BKROOT/BitKeeper/tmp/commits.txt
diff --git a/BitKeeper/triggers/pre-delta b/BitKeeper/triggers/pre-delta
index cd861703bb5..d6afe0905e7 100755
--- a/BitKeeper/triggers/pre-delta
+++ b/BitKeeper/triggers/pre-delta
@@ -20,3 +20,18 @@ then
exit 1
fi
+# detect if C/C++ files have new trailing white space
+trailingblank=`echo $BK_FILE | egrep '\.(c|.h)'`
+if [ -n "$trailingblank" ]
+then
+ trailingblank=`bk diffs $BK_FILE | grep '^> .*[[:space:]]$'`
+ if [ -n "$trailingblank" ]
+ then
+ echo "bk diffs $BK_FILE | grep '^> .*[[:space:]]$'"
+ echo "reported white space at end of some added/modified lines"
+ echo ""
+ echo "Checkin FAILED!"
+ echo "Fix the problem and retry."
+ exit 1
+ fi
+fi
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0657013089b..2c19f2b5059 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,6 +75,13 @@ IF(WITH_FEDERATED_STORAGE_ENGINE)
ADD_DEFINITIONS(-DWITH_FEDERATED_STORAGE_ENGINE)
SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_federated_plugin")
ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
+IF(WITH_MARIA_STORAGE_ENGINE)
+ ADD_DEFINITIONS(-DWITH_MARIA_STORAGE_ENGINE)
+ IF(WITH_MARIA_TMP_TABLES)
+ ADD_DEFINITIONS(-DUSE_MARIA_FOR_TMP_TABLES)
+ ENDIF(WITH_MARIA_TMP_TABLES)
+ SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_maria_plugin")
+ENDIF(WITH_MARIA_STORAGE_ENGINE)
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc.in
${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc @ONLY)
@@ -251,10 +258,17 @@ ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
IF(WITH_INNOBASE_STORAGE_ENGINE)
ADD_SUBDIRECTORY(storage/innobase)
ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
+IF(WITH_MARIA_STORAGE_ENGINE)
+ ADD_SUBDIRECTORY(storage/maria)
+ ADD_SUBDIRECTORY(storage/maria/unittest)
+ENDIF(WITH_MARIA_STORAGE_ENGINE)
ADD_SUBDIRECTORY(sql)
ADD_SUBDIRECTORY(server-tools/instance-manager)
ADD_SUBDIRECTORY(libmysql)
ADD_SUBDIRECTORY(tests)
+ADD_SUBDIRECTORY(unittest/mytap)
+ADD_SUBDIRECTORY(unittest/examples)
+ADD_SUBDIRECTORY(unittest/mysys)
IF(WITH_EMBEDDED_SERVER)
ADD_SUBDIRECTORY(libmysqld)
ADD_SUBDIRECTORY(libmysqld/examples)
diff --git a/KNOWN_BUGS.txt b/KNOWN_BUGS.txt
new file mode 100644
index 00000000000..189c7dcd613
--- /dev/null
+++ b/KNOWN_BUGS.txt
@@ -0,0 +1,86 @@
+This file should contain all know fatal bugs in the Maria storage
+engine for the last source or binary release. Minor bugs, extensions
+and feature request and bugs found since this release can be find in the
+MySQL bugs databases at: http://bugs.mysql.com/ (category "Maria
+storage engine").
+
+There shouldn't normally be any bugs that affects normal operations in
+any Maria release. Still, there are always exceptions and edge cases
+and that's what this file is for.
+
+For the first few Alpha releases of Maria there may be some edge cases
+that crashes during recovery; We don't like that but we think it's
+better to get the Maria alpha out early to get things tested and get
+more developers on the code early than wait until these are fixed. We
+do however think that the bugs are not seriously enough to stop anyone
+from starting to test and even use Maria for real (as long as they are
+prepared to upgrade to next MySQL-Maria release ASAP).
+
+If you have found a bug that is not listed here, please add it to
+http://bugs.mysql.com/ so that we can either fix it for next release
+or in the worst case add it here for others to know!
+
+IMPORTANT:
+
+If you have been using a MySQL-5.1-Maria-alpha build and upgrading to
+MySQL-5.1-Maria-beta you MUST run maria_chk --recover on all your
+Maria tables. This is because we made an incompatible change of how
+transaction id is stored and old transaction id's must be reset!
+
+cd mysql-data-directory
+maria_chk --recover */*.MAI
+
+As the Maria-1.5 engine is now in beta we will do our best to not
+introduce any incompatible changes in the data format for the Maria
+tables; If this would be ever be needed, we will, if possible, support
+both the old and the new version to make upgrades as easy as possible.
+
+Known bugs that we are working on and will be fixed shortly
+===========================================================
+
+- We have some time ago some instabilities in log writing that is was
+ under investigation but we haven't been able to repeat in a while.
+ This causes mainly assert to triggers in the code and sometimes
+ the log handler doesn't start up after restart.
+ Most of this should now be fixed.
+
+- INSERT on a duplicate key against a key inserted by another connection
+ that has not yet ended will give a duplicate key error instead of
+ waiting for the other statement to end.
+
+
+Known bugs that are planned to be fixed before Gamma/RC
+=======================================================
+
+- If we get a write failure on disk (disk full or disk error) for the
+ log, we should stop all usage of transactional tables and mark all
+ transactional tables that are changed as crashed.
+ For the moment, if this happens, you have to take down mysqld,
+ remove all logs, restart mysqld and repair your tables.
+
+ If you get the related error:
+ "Disk is full writing '/usr/local/mysql/var/maria_log.????????' (Errcode: 28)
+ Waiting for someone to free space..."
+ you should either free disk space, in which Maria will continue as before
+ or kill mysqld, remove logs and repair tables.
+
+
+Known bugs that are planned to be fixed later
+=============================================
+
+LOCK TABLES .. WRITE CONCURRENT is mainly done for testing MVCC. Don't
+use this in production.
+
+Missing features that is planned to fix before Beta
+===================================================
+
+None
+
+Features planned for future releases
+====================================
+
+Most notable is full transaction support and multiple reader/writers
+in Maria 2.0
+
+http://forge.mysql.com/worklog/
+(you can enter "maria" in the "quick search" field there).
diff --git a/Makefile.am b/Makefile.am
index adab4dc41f4..86071e2d934 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -67,7 +67,7 @@ tags:
.PHONY: init-db bin-dist \
test test-force test-full test-force-full test-force-mem \
test-pl test-force-pl test-full-pl test-force-full-pl test-force-pl-mem \
- test-unit test-ps test-nr test-pr test-ns test-binlog-statement \
+ test-unit test-unit-big test-ps test-nr test-pr test-ns test-binlog-statement \
test-ext-funcs test-ext-rpl test-ext-partitions test-ext-jp \
test-ext-stress test-ext test-embedded test-reprepare \
test-fast test-fast-cursor test-fast-view test-fast-prepare \
@@ -82,7 +82,10 @@ tags:
# making sure each user use different ports.
test-unit:
- cd unittest && $(MAKE) test
+ cd unittest; $(MAKE) test
+
+test-unit-big:
+ cd unittest; MYTAP_CONFIG=big $(MAKE) test
test-ps:
cd mysql-test ; \
@@ -112,14 +115,14 @@ test-embedded:
--embedded-server --skip-rpl --skip-ndbcluster ; \
else \
echo "no program found for 'embedded' tests - skipped testing" ; \
- fi
+ fi
test-reprepare:
cd mysql-test ; \
@PERL@ ./mysql-test-run.pl $(force) $(mem) --ps-protocol \
--mysqld=--debug=+d,reprepare_each_statement
-test: test-unit test-ns test-pr
+test: test-ns test-pr
smoke:
cd mysql-test ; \
diff --git a/client/client_priv.h b/client/client_priv.h
index 06145232995..07b5cd72d84 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -80,5 +80,6 @@ enum options_client
OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT,
OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE,
OPT_WRITE_BINLOG, OPT_DUMP_DATE,
+ OPT_ABORT_SOURCE_ON_ERROR,
OPT_MAX_CLIENT_OPTION
};
diff --git a/client/get_password.c b/client/get_password.c
index ea024f76fb6..c6653183f48 100644
--- a/client/get_password.c
+++ b/client/get_password.c
@@ -113,7 +113,7 @@ static void get_password(char *to,uint length,int fd, my_bool echo)
for (;;)
{
- char tmp;
+ uchar tmp;
if (my_read(fd,&tmp,1,MYF(0)) != 1)
break;
if (tmp == '\b' || (int) tmp == 127)
@@ -138,7 +138,7 @@ static void get_password(char *to,uint length,int fd, my_bool echo)
fputc('*',stderr);
fflush(stderr);
}
- *(pos++) = tmp;
+ *(pos++)= (char) tmp;
}
while (pos != to && isspace(pos[-1]) == ' ')
pos--; /* Allow dummy space at end */
diff --git a/client/mysql.cc b/client/mysql.cc
index be157f52d08..d61d2781e14 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -43,7 +43,7 @@
#include <locale.h>
#endif
-const char *VER= "14.14";
+const char *VER= "14.15";
/* Don't try to make a nice table if the data is too big */
#define MAX_COLUMN_LENGTH 1024
@@ -142,7 +142,7 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0,
default_charset_used= 0, opt_secure_auth= 0,
default_pager_set= 0, opt_sigint_ignore= 0,
show_warnings= 0, executing_query= 0, interrupted_query= 0;
-static my_bool debug_info_flag, debug_check_flag;
+static my_bool debug_info_flag, debug_check_flag, batch_abort_on_error;
static my_bool column_types_flag;
static my_bool preserve_comments= 0;
static ulong opt_max_allowed_packet, opt_net_buffer_length;
@@ -1308,6 +1308,10 @@ static struct my_option my_long_options[] =
0, 0, 0, 0, 0},
{"help", 'I', "Synonym for -?", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
0, 0, 0, 0, 0},
+ {"abort-source-on-error", OPT_ABORT_SOURCE_ON_ERROR,
+ "Abort 'source filename' operations in case of errors",
+ (uchar**) &batch_abort_on_error, (uchar**) &batch_abort_on_error, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef __NETWARE__
{"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -1359,7 +1363,7 @@ static struct my_option my_long_options[] =
{"vertical", 'E', "Print the output of a query (rows) vertically.",
(uchar**) &vertical, (uchar**) &vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
- {"force", 'f', "Continue even if we get an sql error.",
+ {"force", 'f', "Continue even if we get an sql error. Sets abort-source-on-error to 0",
(uchar**) &ignore_errors, (uchar**) &ignore_errors, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
{"named-commands", 'G',
@@ -1718,6 +1722,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
#endif
break;
#include <sslopt-case.h>
+ case 'f':
+ batch_abort_on_error= 0;
+ break;
case 'V':
usage(1);
exit(0);
@@ -3882,6 +3889,7 @@ static int com_source(String *buffer, char *line)
int error;
STATUS old_status;
FILE *sql_file;
+ my_bool save_ignore_errors;
/* Skip space from file name */
while (my_isspace(charset_info,*line))
@@ -3913,16 +3921,25 @@ static int com_source(String *buffer, char *line)
/* Save old status */
old_status=status;
+ save_ignore_errors= ignore_errors;
bfill((char*) &status,sizeof(status),(char) 0);
status.batch=old_status.batch; // Run in batch mode
status.line_buff=line_buff;
status.file_name=source_name;
glob_buffer.length(0); // Empty command buffer
+ ignore_errors= !batch_abort_on_error;
error= read_and_execute(false);
+ ignore_errors= save_ignore_errors;
status=old_status; // Continue as before
my_fclose(sql_file,MYF(0));
batch_readline_end(line_buff);
+ /*
+ If we got an error during source operation, don't abort the client
+ if ignore_errors is set
+ */
+ if (error && batch_abort_on_error && ignore_errors)
+ error= -1;
return error;
}
@@ -4428,12 +4445,19 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
if (error)
{
if (sqlstate)
- (void) tee_fprintf(file, "ERROR %d (%s): ", error, sqlstate);
+ (void) tee_fprintf(file, "ERROR %d (%s)", error, sqlstate);
else
- (void) tee_fprintf(file, "ERROR %d: ", error);
+ (void) tee_fprintf(file, "ERROR %d", error);
}
else
- tee_puts("ERROR: ", file);
+ tee_fputs("ERROR", file);
+ if (status.query_start_line && line_numbers)
+ {
+ (void) fprintf(file," at line %lu",status.query_start_line);
+ if (status.file_name)
+ (void) fprintf(file," in file: '%s'", status.file_name);
+ }
+ tee_fputs(": ", file);
}
else
vidattr(A_BOLD);
@@ -4442,7 +4466,7 @@ put_info(const char *str,INFO_TYPE info_type, uint error, const char *sqlstate)
}
if (unbuffered)
fflush(file);
- return info_type == INFO_ERROR ? -1 : 0;
+ return info_type == INFO_ERROR ? (ignore_errors ? -1 : 1): 0;
}
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index 1e3249dd92a..f06bc6ee9ed 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -512,7 +512,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
If this behaviour is ever changed, Docs should be notified.
*/
- struct rand_struct rand_st;
+ struct my_rnd_struct rand_st;
for (; argc > 0 ; argv++,argc--)
{
@@ -824,7 +824,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
time_t start_time;
/* Do initialization the same way as we do in mysqld */
start_time=time((time_t*) 0);
- randominit(&rand_st,(ulong) start_time,(ulong) start_time/2);
+ my_rnd_init(&rand_st,(ulong) start_time,(ulong) start_time/2);
if (argc < 2)
{
diff --git a/client/mysqlslap.c b/client/mysqlslap.c
index 9ba912d646c..a2de6a16af3 100644
--- a/client/mysqlslap.c
+++ b/client/mysqlslap.c
@@ -1884,10 +1884,17 @@ limit_not_met:
{
if (mysql_field_count(mysql))
{
- result= mysql_store_result(mysql);
- while ((row = mysql_fetch_row(result)))
- counter++;
- mysql_free_result(result);
+ if ((result= mysql_store_result(mysql)))
+ {
+ while ((row = mysql_fetch_row(result)))
+ counter++;
+ mysql_free_result(result);
+ }
+ else
+ {
+ fprintf(stderr,"%s: Error in mysql_store_result(): %d %s\n",
+ my_progname, mysql_errno(mysql), mysql_error(mysql));
+ }
}
} while(mysql_next_result(mysql) == 0);
queries++;
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index 89b9c78a049..aaed61ea827 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -181,6 +181,10 @@ static void init_re(void);
static int match_re(my_regex_t *, char *);
static void free_re(void);
+static int replace(DYNAMIC_STRING *ds_str,
+ const char *search_str, ulong search_len,
+ const char *replace_str, ulong replace_len);
+
DYNAMIC_ARRAY q_lines;
#include "sslopt-vars.h"
@@ -1747,6 +1751,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
void check_result()
{
+ int res;
const char* mess= "Result content mismatch\n";
DBUG_ENTER("check_result");
@@ -2459,7 +2464,7 @@ void do_source(struct st_command *command)
}
dynstr_free(&ds_filename);
- return;
+ DBUG_VOID_RETURN;
}
@@ -5863,7 +5868,6 @@ int parse_args(int argc, char **argv)
if (debug_check_flag)
my_end_arg= MY_CHECK_ERROR;
-
if (!record)
{
/* Check that the result file exists */
@@ -7438,6 +7442,7 @@ static void init_signal_handling(void)
#endif
sigaction(SIGILL, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
+ DBUG_VOID_RETURN;
}
#endif /* !__WIN__ */
diff --git a/cmd-line-utils/readline/bind.c b/cmd-line-utils/readline/bind.c
index baed1dfad49..84bf37bc993 100644
--- a/cmd-line-utils/readline/bind.c
+++ b/cmd-line-utils/readline/bind.c
@@ -701,7 +701,7 @@ rl_function_of_keyseq (keyseq, map, type)
{
unsigned char ic = keyseq[i];
- if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
+ if (META_CHAR_FOR_UCHAR(ic) && _rl_convert_meta_chars_to_ascii)
{
if (map[ESC].type == ISKMAP)
{
diff --git a/cmd-line-utils/readline/chardefs.h b/cmd-line-utils/readline/chardefs.h
index def3a111bd3..a184ab30acb 100644
--- a/cmd-line-utils/readline/chardefs.h
+++ b/cmd-line-utils/readline/chardefs.h
@@ -60,6 +60,7 @@
#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0))
#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
+#define META_CHAR_FOR_UCHAR(c) ((c) > meta_character_threshold)
#define CTRL(c) ((c) & control_character_mask)
#define META(c) ((c) | meta_character_bit)
diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c
index 6f63faa9738..b8699c34b82 100644
--- a/cmd-line-utils/readline/display.c
+++ b/cmd-line-utils/readline/display.c
@@ -191,8 +191,6 @@ static int visible_first_line_len;
(or is equal to) _rl_screenwidth. */
static int prompt_invis_chars_first_line;
-static int prompt_last_screen_line;
-
static int prompt_physical_chars;
/* Variables to save and restore prompt and display information. */
@@ -458,7 +456,7 @@ rl_redisplay ()
{
register int in, out, c, linenum, cursor_linenum;
register char *line;
- int inv_botlin, lb_botlin, lb_linenum, o_cpos;
+ int inv_botlin, lb_linenum, o_cpos;
int newlines, lpos, temp, modmark, n0, num;
char *prompt_this_line;
#if defined (HANDLE_MULTIBYTE)
@@ -671,11 +669,9 @@ rl_redisplay ()
lpos -= _rl_screenwidth;
}
- prompt_last_screen_line = newlines;
-
/* Draw the rest of the line (after the prompt) into invisible_line, keeping
track of where the cursor is (cpos_buffer_position), the number of the line containing
- the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
+ the cursor (lb_linenum), the last line number (inv_botlin).
It maintains an array of line breaks for display (inv_lbreaks).
This handles expanding tabs for display and displaying meta characters. */
lb_linenum = 0;
@@ -858,7 +854,7 @@ rl_redisplay ()
lb_linenum = newlines;
}
- inv_botlin = lb_botlin = newlines;
+ inv_botlin = newlines;
CHECK_INV_LBREAKS ();
inv_lbreaks[newlines+1] = out;
cursor_linenum = lb_linenum;
@@ -1888,7 +1884,7 @@ rl_character_len (c, pos)
uc = (unsigned char)c;
- if (META_CHAR (uc))
+ if (META_CHAR_FOR_UCHAR(uc))
return ((_rl_output_meta_chars == 0) ? 4 : 1);
if (uc == '\t')
diff --git a/cmd-line-utils/readline/histexpand.c b/cmd-line-utils/readline/histexpand.c
index 45377fc3b5e..b52b0685c47 100644
--- a/cmd-line-utils/readline/histexpand.c
+++ b/cmd-line-utils/readline/histexpand.c
@@ -693,7 +693,7 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
case 's':
{
char *new_event;
- int delimiter, failed, si, l_temp, ws, we;
+ int delimiter, failed, si, l_temp, we;
if (c == 's')
{
@@ -792,7 +792,6 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
{
for (; temp[si] && whitespace (temp[si]); si++)
;
- ws = si;
we = history_tokenize_word (temp, si);
}
diff --git a/cmd-line-utils/readline/history.c b/cmd-line-utils/readline/history.c
index 5cd5788d1da..c81101fc555 100644
--- a/cmd-line-utils/readline/history.c
+++ b/cmd-line-utils/readline/history.c
@@ -306,7 +306,7 @@ add_history (string)
}
}
- temp = alloc_history_entry (string, hist_inittime ());
+ temp = alloc_history_entry ((char*) string, hist_inittime ());
the_history[history_length] = (HIST_ENTRY *)NULL;
the_history[history_length - 1] = temp;
diff --git a/cmd-line-utils/readline/readline.c b/cmd-line-utils/readline/readline.c
index 8c3cad52d36..3a0f533fcd6 100644
--- a/cmd-line-utils/readline/readline.c
+++ b/cmd-line-utils/readline/readline.c
@@ -90,7 +90,6 @@ static void bind_arrow_keys_internal PARAMS((Keymap));
static void bind_arrow_keys PARAMS((void));
static void readline_default_bindings PARAMS((void));
-static void reset_default_bindings PARAMS((void));
static int _rl_subseq_result PARAMS((int, Keymap, int, int));
static int _rl_subseq_getchar PARAMS((int));
@@ -287,7 +286,7 @@ rl_set_prompt (prompt)
{
FREE (rl_prompt);
rl_prompt = prompt ? savestring (prompt) : (char *)NULL;
- rl_display_prompt = rl_prompt ? rl_prompt : "";
+ rl_display_prompt = rl_prompt ? rl_prompt : (char*) "";
rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
return 0;
@@ -1072,18 +1071,6 @@ readline_default_bindings ()
rl_tty_set_default_bindings (_rl_keymap);
}
-/* Reset the default bindings for the terminal special characters we're
- interested in back to rl_insert and read the new ones. */
-static void
-reset_default_bindings ()
-{
- if (_rl_bind_stty_chars)
- {
- rl_tty_unset_default_bindings (_rl_keymap);
- rl_tty_set_default_bindings (_rl_keymap);
- }
-}
-
/* Bind some common arrow key sequences in MAP. */
static void
bind_arrow_keys_internal (map)
diff --git a/cmd-line-utils/readline/text.c b/cmd-line-utils/readline/text.c
index b26afeda525..bcb5a5c32fd 100644
--- a/cmd-line-utils/readline/text.c
+++ b/cmd-line-utils/readline/text.c
@@ -1169,7 +1169,7 @@ rl_insert_comment (count, key)
int rl_comment_len;
rl_beg_of_line (1, key);
- rl_comment_text = _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT;
+ rl_comment_text = _rl_comment_begin ? _rl_comment_begin : (char*) RL_COMMENT_BEGIN_DEFAULT;
if (rl_explicit_arg == 0)
rl_insert_text (rl_comment_text);
@@ -1386,10 +1386,11 @@ rl_transpose_chars (count, key)
#if defined (HANDLE_MULTIBYTE)
char *dummy;
int i;
+ int prev_point;
#else
char dummy[2];
#endif
- int char_length, prev_point;
+ int char_length;
if (count == 0)
return 0;
@@ -1408,7 +1409,9 @@ rl_transpose_chars (count, key)
count = 1;
}
+#if defined (HANDLE_MULTIBYTE)
prev_point = rl_point;
+#endif
rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_NONZERO);
#if defined (HANDLE_MULTIBYTE)
diff --git a/config/ac-macros/plugins.m4 b/config/ac-macros/plugins.m4
index 8dfb698709f..62789e2fb15 100644
--- a/config/ac-macros/plugins.m4
+++ b/config/ac-macros/plugins.m4
@@ -280,7 +280,7 @@ dnl ---------------------------------------------------------------------------
dnl Macro: MYSQL_CONFIGURE_PLUGINS
dnl
dnl SYNOPSIS
-dnl MYSQL_PLUGIN_DEPENDS([name,name...])
+dnl MYSQL_CONFIGURE_PLUGINS([name,name...])
dnl
dnl DESCRIPTION
dnl Used last, emits all required shell code to configure the plugins
@@ -735,13 +735,13 @@ dnl Emits shell script for checking configure arguments
dnl Arguments to this macro is default value for selected plugins
AC_DEFUN([_MYSQL_CHECK_PLUGIN_ARGS],[
- __MYSQL_CHECK_PLUGIN_ARGS(m4_default([$1], [none]))
+ __MYSQL_CHECK_PLUGIN_ARGS(m4_default([$1], [default]))
])
AC_DEFUN([__MYSQL_CHECK_PLUGIN_ARGS],[
AC_ARG_WITH([plugins],
AS_HELP_STRING([--with-plugins=PLUGIN[[[[[,PLUGIN..]]]]]],
- [Plugins to include in mysqld. (default is: $1) Must be a
+ [Plugins to include in mysqld. Must be a
configuration name or a comma separated list of plugins.])
AS_HELP_STRING([],
[Available configurations are:] dnl
diff --git a/configure.in b/configure.in
index 16d229a84e3..be9c9b8e0b0 100644
--- a/configure.in
+++ b/configure.in
@@ -10,7 +10,7 @@ AC_CANONICAL_SYSTEM
#
# When changing major version number please also check switch statement
# in mysqlbinlog::check_master_version().
-AM_INIT_AUTOMAKE(mysql, 5.1.32)
+AM_INIT_AUTOMAKE(mysql, 5.1.32-maria-alpha)
AM_CONFIG_HEADER([include/config.h:config.h.in])
PROTOCOL_VERSION=10
@@ -250,8 +250,6 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
# Not critical since the generated file is distributed
AC_CHECK_PROGS(YACC, ['bison -y -p MYSQL'])
-AC_CHECK_PROG(PDFMANUAL, pdftex, manual.pdf)
-AC_CHECK_PROG(DVIS, tex, manual.dvi)
#check the return type of sprintf
AC_MSG_CHECKING("return type of sprintf")
@@ -817,7 +815,7 @@ AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \
memory.h pwd.h select.h \
- stdlib.h stddef.h \
+ stdlib.h stddef.h sys/stat.h \
strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \
sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \
unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h \
@@ -1727,41 +1725,43 @@ fi
AC_ARG_WITH([atomic-ops],
AC_HELP_STRING([--with-atomic-ops=rwlocks|smp|up],
[Implement atomic operations using pthread rwlocks or atomic CPU
- instructions for multi-processor (default) or uniprocessor
- configuration]), , [with_atomic_ops=smp])
+ instructions for multi-processor or uniprocessor
+ configuration. By default gcc built-in sync functions are used,
+ if available and 'smp' configuration otherwise.]))
case "$with_atomic_ops" in
"up") AC_DEFINE([MY_ATOMIC_MODE_DUMMY], [1],
[Assume single-CPU mode, no concurrency]) ;;
"rwlocks") AC_DEFINE([MY_ATOMIC_MODE_RWLOCKS], [1],
[Use pthread rwlocks for atomic ops]) ;;
"smp") ;;
+ "")
+ AC_CACHE_CHECK([whether the compiler provides atomic builtins],
+ [mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([
+ int main()
+ {
+ int foo= -10; int bar= 10;
+ if (!__sync_fetch_and_add(&foo, bar) || foo)
+ return -1;
+ bar= __sync_lock_test_and_set(&foo, bar);
+ if (bar || foo != 10)
+ return -1;
+ bar= __sync_val_compare_and_swap(&bar, foo, 15);
+ if (bar)
+ return -1;
+ return 0;
+ }
+ ], [mysql_cv_gcc_atomic_builtins=yes_but_disabled],
+ [mysql_cv_gcc_atomic_builtins=no],
+ [mysql_cv_gcc_atomic_builtins=no])])
+
+ if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
+ AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
+ [Define to 1 if compiler provides atomic builtins.])
+ fi
+ ;;
*) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;;
esac
-AC_CACHE_CHECK([whether the compiler provides atomic builtins],
- [mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([
- int main()
- {
- int foo= -10; int bar= 10;
- if (!__sync_fetch_and_add(&foo, bar) || foo)
- return -1;
- bar= __sync_lock_test_and_set(&foo, bar);
- if (bar || foo != 10)
- return -1;
- bar= __sync_val_compare_and_swap(&bar, foo, 15);
- if (bar)
- return -1;
- return 0;
- }
-], [mysql_cv_gcc_atomic_builtins=yes],
- [mysql_cv_gcc_atomic_builtins=no],
- [mysql_cv_gcc_atomic_builtins=no])])
-
-if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
- AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
- [Define to 1 if compiler provides atomic builtins.])
-fi
-
# Force static compilation to avoid linking problems/get more speed
AC_ARG_WITH(mysqld-ldflags,
[ --with-mysqld-ldflags Extra linking arguments for mysqld],
@@ -2052,7 +2052,7 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bsearch bzero \
pthread_setprio_np pthread_setschedparam pthread_sigmask readlink \
realpath rename rint rwlock_init setupterm \
shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \
- sighold sigset sigthreadmask port_create sleep \
+ sighold sigset sigthreadmask port_create sleep thr_yield \
snprintf socket stpcpy strcasecmp strerror strsignal strnlen strpbrk strstr \
strtol strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr \
posix_fallocate backtrace backtrace_symbols backtrace_symbols_fd)
@@ -2396,12 +2396,23 @@ MYSQL_CHECK_SSL
# functions tested above
#--------------------------------------------------------------------
+# MyISAM is declared here,not in storage/myisam/plug.in
+# because we want it to be the first in the list of plugins,
+# Maria needs it. When it'll be fixed the declaration below can
+# be removed and restored (uncommented) in storage/myisam/plug.in
+MYSQL_STORAGE_ENGINE(myisam,no, [MyISAM Storage Engine],
+ [Traditional non-transactional MySQL tables])
+MYSQL_PLUGIN_DIRECTORY(myisam, [storage/myisam])
+MYSQL_PLUGIN_STATIC(myisam, [libmyisam.a])
+MYSQL_PLUGIN_MANDATORY(myisam) dnl Default
+MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(myisam, [ha_myisam.cc])
+
MYSQL_STORAGE_ENGINE(partition, partition, [Partition Support],
[MySQL Partitioning Support], [max,max-no-ndb])
dnl -- ndbcluster requires partition to be enabled
-MYSQL_CONFIGURE_PLUGINS([none])
+MYSQL_CONFIGURE_PLUGINS([default])
# Only build client code?
AC_ARG_WITH(server,
@@ -2624,8 +2635,6 @@ AC_SUBST(readline_basedir)
AC_SUBST(readline_link)
AC_SUBST(readline_h_ln_cmd)
-
-
# Include man pages, if desired, adapted to the configured parts.
if test X"$with_man" = Xyes
then
@@ -2719,14 +2728,12 @@ if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no"
then
AC_DEFINE([THREAD], [1],
[Define if you want to have threaded code. This may be undef on client code])
- # Avoid _PROGRAMS names
- THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o"
- AC_SUBST(THREAD_LOBJECTS)
server_scripts="mysqld_safe mysql_install_db"
sql_server_dirs="strings mysys dbug extra regex"
sql_server="vio sql"
fi
+AM_CONDITIONAL(THREAD, test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no")
# "innochecksum" is not in the "innobase/" subdirectory, but should be switched
AM_CONDITIONAL([BUILD_INNODB_TOOLS], [test X"$with_plugin_innobase" = Xyes])
diff --git a/dbug/.cvsignore b/dbug/.cvsignore
deleted file mode 100644
index e9955884756..00000000000
--- a/dbug/.cvsignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.deps
-Makefile
-Makefile.in
diff --git a/dbug/CMakeLists.txt b/dbug/CMakeLists.txt
index 8b27f79dcf4..8b27f79dcf4 100755..100644
--- a/dbug/CMakeLists.txt
+++ b/dbug/CMakeLists.txt
diff --git a/dbug/Makefile.am b/dbug/Makefile.am
index 872ebdb7902..7e909f9154f 100644
--- a/dbug/Makefile.am
+++ b/dbug/Makefile.am
@@ -23,19 +23,20 @@ libdbug_a_SOURCES = dbug.c sanity.c
EXTRA_DIST = CMakeLists.txt example1.c example2.c example3.c \
user.r monty.doc dbug_add_tags.pl \
my_main.c main.c factorial.c dbug_analyze.c \
- CMakeLists.txt
+ CMakeLists.txt tests.c tests-t.pl
NROFF_INC = example1.r example2.r example3.r main.r \
factorial.r output1.r output2.r output3.r \
output4.r output5.r
-CLEANFILES = $(NROFF_INC) user.t user.ps
+CLEANFILES = $(NROFF_INC) user.t user.ps tests-t
# Must be linked with libs that are not compiled yet
-noinst_PROGRAMS = factorial dbug_analyze
+noinst_PROGRAMS = factorial dbug_analyze tests
factorial_SOURCES = my_main.c factorial.c
+tests_SOURCES = tests.c
dbug_analyze_SOURCES = dbug_analyze.c
-all: user.t user.ps
+all: user.t user.ps tests-t
user.t: user.r $(NROFF_INC)
-nroff -mm user.r > $@
@@ -61,5 +62,9 @@ output5.r: factorial
@RM@ -f $@
@SED@ -e 's!\\!\\\\!g' $< > $@
+# a hack to have executable in builddir, not in srcdir
+tests-t: tests-t.pl
+ cp -f $(srcdir)/tests-t.pl ./tests-t
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/dbug/dbug.c b/dbug/dbug.c
index baf080f5e27..1e18fb3eab0 100644
--- a/dbug/dbug.c
+++ b/dbug/dbug.c
@@ -57,21 +57,34 @@
* seismo!bpa!sjuvax!bbanerje
*
* Michael Widenius:
- * DBUG_DUMP - To dump a block of memory.
- * PUSH_FLAG "O" - To be used insted of "o" if we
- * want flushing after each write
- * PUSH_FLAG "A" - as 'O', but we will append to the out file instead
- * of creating a new one.
- * Check of malloc on entry/exit (option "S")
- *
- * DBUG_EXECUTE_IF
- * incremental mode (-#+t:-d,info ...)
- * DBUG_SET, _db_explain_
- * thread-local settings
+ * DBUG_DUMP - To dump a block of memory.
+ * PUSH_FLAG "O" - To be used insted of "o" if we
+ * want flushing after each write
+ * PUSH_FLAG "A" - as 'O', but we will append to the out file instead
+ * of creating a new one.
+ * Check of malloc on entry/exit (option "S")
+ *
+ * Sergei Golubchik:
+ * DBUG_EXECUTE_IF
+ * incremental mode (-#+t:-d,info ...)
+ * DBUG_SET, _db_explain_
+ * thread-local settings
+ * negative lists (-#-d,info => everything but "info")
+ *
+ * function/ syntax
+ * (the logic is - think of a call stack as of a path.
+ * "function" means only this function, "function/" means the hierarchy.
+ * in the future, filters like function1/function2 could be supported.
+ * wildcards are a natural extension too: * and ?)
*
*/
+/*
+ We can't have SAFE_MUTEX defined here as this will cause recursion
+ in pthread_mutex_lock
+*/
+#undef SAFE_MUTEX
#include <my_global.h>
#include <m_string.h>
#include <errno.h>
@@ -79,7 +92,6 @@
#include <process.h>
#endif
-
#ifndef DBUG_OFF
@@ -95,21 +107,24 @@
* The following flags are used to determine which
* capabilities the user has enabled with the settings
* push macro.
+ *
+ * TRACE_ON is also used in _db_stack_frame_->level
+ * (until we add flags to _db_stack_frame_, increasing it by 4 bytes)
*/
-#define TRACE_ON 000001 /* Trace enabled */
-#define DEBUG_ON 000002 /* Debug enabled */
-#define FILE_ON 000004 /* File name print enabled */
-#define LINE_ON 000010 /* Line number print enabled */
-#define DEPTH_ON 000020 /* Function nest level print enabled */
-#define PROCESS_ON 000040 /* Process name print enabled */
-#define NUMBER_ON 000100 /* Number each line of output */
-#define PROFILE_ON 000200 /* Print out profiling code */
-#define PID_ON 000400 /* Identify each line with process id */
-#define TIMESTAMP_ON 001000 /* timestamp every line of output */
-#define SANITY_CHECK_ON 002000 /* Check safemalloc on DBUG_ENTER */
-#define FLUSH_ON_WRITE 004000 /* Flush on every write */
-#define OPEN_APPEND 010000 /* Open for append */
+#define DEBUG_ON (1 << 1) /* Debug enabled */
+#define FILE_ON (1 << 2) /* File name print enabled */
+#define LINE_ON (1 << 3) /* Line number print enabled */
+#define DEPTH_ON (1 << 4) /* Function nest level print enabled */
+#define PROCESS_ON (1 << 5) /* Process name print enabled */
+#define NUMBER_ON (1 << 6) /* Number each line of output */
+#define PROFILE_ON (1 << 7) /* Print out profiling code */
+#define PID_ON (1 << 8) /* Identify each line with process id */
+#define TIMESTAMP_ON (1 << 9) /* timestamp every line of output */
+#define SANITY_CHECK_ON (1 << 10) /* Check safemalloc on DBUG_ENTER */
+#define FLUSH_ON_WRITE (1 << 11) /* Flush on every write */
+#define OPEN_APPEND (1 << 12) /* Open for append */
+#define TRACE_ON ((uint)1 << 31) /* Trace enabled. MUST be the highest bit!*/
#define TRACING (cs->stack->flags & TRACE_ON)
#define DEBUGGING (cs->stack->flags & DEBUG_ON)
@@ -119,11 +134,7 @@
* Typedefs to make things more obvious.
*/
-#ifndef __WIN__
-typedef int BOOLEAN;
-#else
-#define BOOLEAN BOOL
-#endif
+#define BOOLEAN my_bool
/*
* Make it easy to change storage classes if necessary.
@@ -139,7 +150,7 @@ typedef int BOOLEAN;
* (G?) which allowed the user to specify this.
*
* If the automatic variables get allocated on the stack in
- * reverse order from their declarations, then define AUTOS_REVERSE.
+ * reverse order from their declarations, then define AUTOS_REVERSE to 1.
* This is used by the code that keeps track of stack usage. For
* forward allocation, the difference in the dbug frame pointers
* represents stack used by the callee function. For reverse allocation,
@@ -154,6 +165,8 @@ typedef int BOOLEAN;
#ifdef M_I386 /* predefined by xenix 386 compiler */
#define AUTOS_REVERSE 1
+#else
+#define AUTOS_REVERSE 0
#endif
/*
@@ -164,7 +177,11 @@ typedef int BOOLEAN;
static void perror(); /* Fake system/library error print routine */
#endif
+#ifdef SAFEMALLOC
IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
+#else
+#define _sanity(X,Y) (1)
+#endif
/*
* The user may specify a list of functions to trace or
@@ -174,9 +191,18 @@ IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
struct link {
struct link *next_link; /* Pointer to the next link */
- char str[1]; /* Pointer to link's contents */
+ char flags;
+ char str[1]; /* Pointer to link's contents */
};
+/* flags for struct link and return flags of InList */
+#define SUBDIR 1 /* this MUST be 1 */
+#define INCLUDE 2
+#define EXCLUDE 4
+/* this is not a struct link flag, but only a return flags of InList */
+#define MATCHED 65536
+#define NOT_MATCHED 0
+
/*
* Debugging settings can be pushed or popped off of a
* stack which is implemented as a linked list. Note
@@ -188,18 +214,18 @@ struct link {
*/
struct settings {
- int flags; /* Current settings flags */
- int maxdepth; /* Current maximum trace depth */
- uint delay; /* Delay after each output line */
- int sub_level; /* Sub this from code_state->level */
- FILE *out_file; /* Current output stream */
- FILE *prof_file; /* Current profiling stream */
- char name[FN_REFLEN]; /* Name of output file */
- struct link *functions; /* List of functions */
- struct link *p_functions; /* List of profiled functions */
- struct link *keywords; /* List of debug keywords */
- struct link *processes; /* List of process names */
- struct settings *next; /* Next settings in the list */
+ uint flags; /* Current settings flags */
+ uint maxdepth; /* Current maximum trace depth */
+ uint delay; /* Delay after each output line */
+ uint sub_level; /* Sub this from code_state->level */
+ FILE *out_file; /* Current output stream */
+ FILE *prof_file; /* Current profiling stream */
+ char name[FN_REFLEN]; /* Name of output file */
+ struct link *functions; /* List of functions */
+ struct link *p_functions; /* List of profiled functions */
+ struct link *keywords; /* List of debug keywords */
+ struct link *processes; /* List of process names */
+ struct settings *next; /* Next settings in the list */
};
#define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V)
@@ -212,18 +238,19 @@ struct settings {
static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */
static struct settings init_settings;
static const char *db_process= 0;/* Pointer to process name; argv[0] */
+my_bool _dbug_on_= TRUE; /* FALSE if no debugging at all */
typedef struct _db_code_state_ {
const char *process; /* Pointer to process name; usually argv[0] */
- const char *func; /* Name of current user function */
- const char *file; /* Name of current user file */
- char **framep; /* Pointer to current frame */
- struct settings *stack; /* debugging settings */
- const char *jmpfunc; /* Remember current function for setjmp */
- const char *jmpfile; /* Remember current file for setjmp */
- int lineno; /* Current debugger output line number */
- int level; /* Current function nesting level */
- int jmplevel; /* Remember nesting level at setjmp() */
+ const char *func; /* Name of current user function */
+ const char *file; /* Name of current user file */
+ struct _db_stack_frame_ *framep; /* Pointer to current frame */
+ struct settings *stack; /* debugging settings */
+ const char *jmpfunc; /* Remember current function for setjmp */
+ const char *jmpfile; /* Remember current file for setjmp */
+ int lineno; /* Current debugger output line number */
+ uint level; /* Current function nesting level */
+ int jmplevel; /* Remember nesting level at setjmp() */
/*
* The following variables are used to hold the state information
@@ -244,12 +271,16 @@ typedef struct _db_code_state_ {
The test below is so we could call functions with DBUG_ENTER before
my_thread_init().
*/
-#define get_code_state_or_return if (!cs && !((cs=code_state()))) return
+#define get_code_state_if_not_set_or_return if (!cs && !((cs=code_state()))) return
+#define get_code_state_or_return if (!((cs=code_state()))) return
/* Handling lists */
-static struct link *ListAdd(struct link *, const char *, const char *);
-static struct link *ListDel(struct link *, const char *, const char *);
+#define ListAdd(A,B,C) ListAddDel(A,B,C,INCLUDE)
+#define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE)
+static struct link *ListAddDel(struct link *, const char *, const char *, int);
static struct link *ListCopy(struct link *);
+static int InList(struct link *linkp,const char *cp);
+static uint ListFlags(struct link *linkp);
static void FreeList(struct link *linkp);
/* OpenClose debug output stream */
@@ -260,10 +291,18 @@ static void PushState(CODE_STATE *cs);
/* Free memory associated with debug state. */
static void FreeState (CODE_STATE *cs, struct settings *state, int free_state);
/* Test for tracing enabled */
-static BOOLEAN DoTrace(CODE_STATE *cs);
+static int DoTrace(CODE_STATE *cs);
+/*
+ return values of DoTrace.
+ Can also be used as bitmask: ret & DO_TRACE
+*/
+#define DO_TRACE 1
+#define DONT_TRACE 2
+#define ENABLE_TRACE 3
+#define DISABLE_TRACE 4
/* Test to see if file is writable */
-#if !(!defined(HAVE_ACCESS) || defined(MSDOS))
+#if defined(HAVE_ACCESS) && !defined(MSDOS)
static BOOLEAN Writable(const char *pathname);
/* Change file owner and group */
static void ChangeOwner(CODE_STATE *cs, char *pathname);
@@ -275,8 +314,7 @@ static void DoPrefix(CODE_STATE *cs, uint line);
static char *DbugMalloc(size_t size);
static const char *BaseName(const char *pathname);
static void Indent(CODE_STATE *cs, int indent);
-static BOOLEAN InList(struct link *linkp,const char *cp);
-static void dbug_flush(CODE_STATE *);
+static void DbugFlush(CODE_STATE *);
static void DbugExit(const char *why);
static const char *DbugStrTok(const char *s);
@@ -322,34 +360,39 @@ static unsigned long Clock(void);
#ifdef THREAD
#include <my_pthread.h>
-pthread_mutex_t THR_LOCK_dbug;
+static pthread_mutex_t THR_LOCK_dbug;
static CODE_STATE *code_state(void)
{
- CODE_STATE *cs=0;
- struct st_my_thread_var *tmp;
+ CODE_STATE *cs, **cs_ptr;
+
+ /*
+ _dbug_on_ is reset if we don't plan to use any debug commands at all and
+ we want to run on maximum speed
+ */
+ if (!_dbug_on_)
+ return 0;
if (!init_done)
{
+ init_done=TRUE;
pthread_mutex_init(&THR_LOCK_dbug,MY_MUTEX_INIT_FAST);
bzero(&init_settings, sizeof(init_settings));
init_settings.out_file=stderr;
init_settings.flags=OPEN_APPEND;
- init_done=TRUE;
}
- if ((tmp=my_thread_var))
+ if (!(cs_ptr= (CODE_STATE**) my_thread_var_dbug()))
+ return 0; /* Thread not initialised */
+ if (!(cs= *cs_ptr))
{
- if (!(cs=(CODE_STATE *) tmp->dbug))
- {
- cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
- bzero((uchar*) cs,sizeof(*cs));
- cs->process= db_process ? db_process : "dbug";
- cs->func="?func";
- cs->file="?file";
- cs->stack=&init_settings;
- tmp->dbug= (void*) cs;
- }
+ cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
+ bzero((uchar*) cs,sizeof(*cs));
+ cs->process= db_process ? db_process : "dbug";
+ cs->func="?func";
+ cs->file="?file";
+ cs->stack=&init_settings;
+ *cs_ptr= cs;
}
return cs;
}
@@ -403,20 +446,19 @@ static CODE_STATE *code_state(void)
void _db_process_(const char *name)
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
if (!db_process)
db_process= name;
-
+
get_code_state_or_return;
cs->process= name;
}
-
/*
* FUNCTION
*
- * DbugParse parse control string and set current debugger setting
+ * DbugParse parse control string and set current debugger settings
*
* DESCRIPTION
*
@@ -438,15 +480,17 @@ void _db_process_(const char *name)
*
* For convenience, any leading "-#" is stripped off.
*
+ * RETURN
+ * 1 - a list of functions ("f" flag) was possibly changed
+ * 0 - a list of functions was not changed
*/
-static void DbugParse(CODE_STATE *cs, const char *control)
+int DbugParse(CODE_STATE *cs, const char *control)
{
const char *end;
- int rel=0;
+ int rel, f_used=0;
struct settings *stack;
- get_code_state_or_return;
stack= cs->stack;
if (control[0] == '-' && control[1] == '#')
@@ -497,7 +541,6 @@ static void DbugParse(CODE_STATE *cs, const char *control)
{
int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
if (sign) control++;
- if (!rel) sign=0;
c= *control++;
if (*control == ',') control++;
/* XXX when adding new cases here, don't forget _db_explain_ ! */
@@ -526,6 +569,7 @@ static void DbugParse(CODE_STATE *cs, const char *control)
stack->delay= atoi(control);
break;
case 'f':
+ f_used= 1;
if (sign < 0 && control == end)
{
if (!is_shared(stack,functions))
@@ -664,8 +708,111 @@ static void DbugParse(CODE_STATE *cs, const char *control)
control=end+1;
end= DbugStrTok(control);
}
+ return !rel || f_used;
}
+#define framep_trace_flag(cs, frp) (frp ? \
+ frp->level & TRACE_ON : \
+ (ListFlags(cs->stack->functions) & INCLUDE) ? \
+ 0 : (uint)TRACE_ON)
+
+void FixTraceFlags_helper(CODE_STATE *cs, const char *func,
+ struct _db_stack_frame_ *framep)
+{
+ if (framep->prev)
+ FixTraceFlags_helper(cs, framep->func, framep->prev);
+
+ cs->func= func;
+ cs->level= framep->level & ~TRACE_ON;
+ framep->level= cs->level | framep_trace_flag(cs, framep->prev);
+ /*
+ we don't set cs->framep correctly, even though DoTrace uses it.
+ It's ok, because cs->framep may only affect DO_TRACE/DONT_TRACE return
+ values, but we ignore them here anyway
+ */
+ switch(DoTrace(cs)) {
+ case ENABLE_TRACE:
+ framep->level|= TRACE_ON;
+ break;
+ case DISABLE_TRACE:
+ framep->level&= ~TRACE_ON;
+ break;
+ }
+}
+
+#define fflags(cs) cs->stack->out_file ? ListFlags(cs->stack->functions) : TRACE_ON;
+
+void FixTraceFlags(uint old_fflags, CODE_STATE *cs)
+{
+ const char *func;
+ uint new_fflags, traceon, level;
+ struct _db_stack_frame_ *framep;
+
+ /*
+ first (a.k.a. safety) check:
+ if we haven't started tracing yet, no call stack at all - we're safe.
+ */
+ framep=cs->framep;
+ if (framep == 0)
+ return;
+
+ /*
+ Ok, the tracing has started, call stack isn't empty.
+
+ second check: does the new list have a SUBDIR rule ?
+ */
+ new_fflags=fflags(cs);
+ if (new_fflags & SUBDIR)
+ goto yuck;
+
+ /*
+ Ok, new list doesn't use SUBDIR.
+
+ third check: we do NOT need to re-scan if
+ neither old nor new lists used SUBDIR flag and if a default behavior
+ (whether an unlisted function is traced) hasn't changed.
+ Default behavior depends on whether there're INCLUDE elements in the list.
+ */
+ if (!(old_fflags & SUBDIR) && !((new_fflags^old_fflags) & INCLUDE))
+ return;
+
+ /*
+ Ok, old list may've used SUBDIR, or defaults could've changed.
+
+ fourth check: are we inside a currently active SUBDIR rule ?
+ go up the call stack, if TRACE_ON flag ever changes its value - we are.
+ */
+ for (traceon=framep->level; framep; framep=framep->prev)
+ if ((traceon ^ framep->level) & TRACE_ON)
+ goto yuck;
+
+ /*
+ Ok, TRACE_ON flag doesn't change in the call stack.
+
+ fifth check: but is the top-most value equal to a default one ?
+ */
+ if (((traceon & TRACE_ON) != 0) == ((new_fflags & INCLUDE) == 0))
+ return;
+
+yuck:
+ /*
+ Yuck! function list was changed, and one of the currently active rules
+ was possibly affected. For example, a tracing could've been enabled or
+ disabled for a function somewhere up the call stack.
+ To react correctly, we must go up the call stack all the way to
+ the top and re-match rules to set TRACE_ON bit correctly.
+
+ We must traverse the stack forwards, not backwards.
+ That's what a recursive helper is doing.
+ It'll destroy two CODE_STATE fields, save them now.
+ */
+ func= cs->func;
+ level= cs->level;
+ FixTraceFlags_helper(cs, func, cs->framep);
+ /* now we only need to restore CODE_STATE fields, and we're done */
+ cs->func= func;
+ cs->level= level;
+}
/*
* FUNCTION
@@ -680,22 +827,21 @@ static void DbugParse(CODE_STATE *cs, const char *control)
* DESCRIPTION
*
* Given pointer to a debug control string in "control",
- * parses the control string, and sets up a current debug
- * settings. Pushes a new debug settings if the current is
- * set to the initial debugger settings.
+ * parses the control string, and sets
+ * up a current debug settings.
+ *
*/
-void _db_set_(CODE_STATE *cs, const char *control)
+void _db_set_(const char *control)
{
+ CODE_STATE *cs;
+ uint old_fflags;
get_code_state_or_return;
-
- if (cs->stack == &init_settings)
- PushState(cs);
-
- DbugParse(cs, control);
+ old_fflags=fflags(cs);
+ if (DbugParse(cs, control))
+ FixTraceFlags(old_fflags, cs);
}
-
/*
* FUNCTION
*
@@ -710,16 +856,19 @@ void _db_set_(CODE_STATE *cs, const char *control)
*
* Given pointer to a debug control string in "control", pushes
* the current debug settings, parses the control string, and sets
- * up a new debug settings with DbugParse()
+ * up a new debug settings
*
*/
void _db_push_(const char *control)
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
+ uint old_fflags;
get_code_state_or_return;
+ old_fflags=fflags(cs);
PushState(cs);
- DbugParse(cs, control);
+ if (DbugParse(cs, control))
+ FixTraceFlags(old_fflags, cs);
}
/*
@@ -765,15 +914,18 @@ void _db_set_init_(const char *control)
void _db_pop_()
{
struct settings *discard;
- CODE_STATE *cs=0;
+ uint old_fflags;
+ CODE_STATE *cs;
get_code_state_or_return;
discard= cs->stack;
if (discard->next != NULL)
{
+ old_fflags=fflags(cs);
cs->stack= discard->next;
FreeState(cs, discard, 1);
+ FixTraceFlags(old_fflags, cs);
}
}
@@ -798,11 +950,16 @@ void _db_pop_()
buf=strnmov(buf, (S), len+1); \
if (buf >= end) goto overflow; \
} while (0)
-#define list_to_buf(l) do { \
+#define list_to_buf(l, f) do { \
struct link *listp=(l); \
while (listp) \
{ \
- str_to_buf(listp->str); \
+ if (listp->flags & (f)) \
+ { \
+ str_to_buf(listp->str); \
+ if (listp->flags & SUBDIR) \
+ char_to_buf('/'); \
+ } \
listp=listp->next_link; \
} \
} while (0)
@@ -842,9 +999,18 @@ void _db_pop_()
#define op_list_to_buf(C, val, cond) do { \
if ((cond)) \
{ \
+ int f=ListFlags(val); \
colon_to_buf; \
char_to_buf((C)); \
- list_to_buf(val); \
+ if (f & INCLUDE) \
+ list_to_buf(val, INCLUDE); \
+ if (f & EXCLUDE) \
+ { \
+ colon_to_buf; \
+ char_to_buf('-'); \
+ char_to_buf((C)); \
+ list_to_buf(val, EXCLUDE); \
+ } \
} \
} while (0)
#define op_bool_to_buf(C, cond) do { \
@@ -859,7 +1025,7 @@ int _db_explain_ (CODE_STATE *cs, char *buf, size_t len)
{
char *start=buf, *end=buf+len-4;
- get_code_state_or_return *buf=0;
+ get_code_state_if_not_set_or_return *buf=0;
op_list_to_buf('d', cs->stack->keywords, DEBUGGING);
op_int_to_buf ('D', cs->stack->delay, 0);
@@ -927,15 +1093,11 @@ int _db_explain_init_(char *buf, size_t len)
*
* SYNOPSIS
*
- * VOID _db_enter_(_func_, _file_, _line_,
- * _sfunc_, _sfile_, _slevel_, _sframep_)
+ * VOID _db_enter_(_func_, _file_, _line_, _stack_frame_)
* char *_func_; points to current function name
* char *_file_; points to current file name
* int _line_; called from source line number
- * char **_sfunc_; save previous _func_
- * char **_sfile_; save previous _file_
- * int *_slevel_; save previous nesting level
- * char ***_sframep_; save previous frame pointer
+ * struct _db_stack_frame_ allocated on the caller's stack
*
* DESCRIPTION
*
@@ -959,55 +1121,66 @@ int _db_explain_init_(char *buf, size_t len)
*/
void _db_enter_(const char *_func_, const char *_file_,
- uint _line_, const char **_sfunc_, const char **_sfile_,
- uint *_slevel_, char ***_sframep_ __attribute__((unused)))
+ uint _line_, struct _db_stack_frame_ *_stack_frame_)
{
- int save_errno=errno;
- CODE_STATE *cs=0;
- get_code_state_or_return;
+ int save_errno;
+ CODE_STATE *cs;
+ if (!((cs=code_state())))
+ {
+ _stack_frame_->level= 0; /* Set to avoid valgrind warnings if dbug is enabled later */
+ _stack_frame_->prev= 0;
+ return;
+ }
+ save_errno= errno;
- *_sfunc_= cs->func;
- *_sfile_= cs->file;
+ _stack_frame_->func= cs->func;
+ _stack_frame_->file= cs->file;
cs->func= _func_;
cs->file= _file_;
- *_slevel_= ++cs->level;
+ _stack_frame_->prev= cs->framep;
+ _stack_frame_->level= ++cs->level | framep_trace_flag(cs, cs->framep);
+ cs->framep= _stack_frame_;
#ifndef THREAD
- *_sframep_= cs->framep;
- cs->framep= (char **) _sframep_;
if (DoProfile(cs))
{
long stackused;
- if (*cs->framep == NULL)
+ if (cs->framep->prev == NULL)
stackused= 0;
else
{
- stackused= ((long)(*cs->framep)) - ((long)(cs->framep));
+ stackused= (char*)(cs->framep->prev) - (char*)(cs->framep);
stackused= stackused > 0 ? stackused : -stackused;
}
(void) fprintf(cs->stack->prof_file, PROF_EFMT , Clock(), cs->func);
-#ifdef AUTOS_REVERSE
- (void) fprintf(cs->stack->prof_file, PROF_SFMT, cs->framep, stackused, *_sfunc_);
-#else
(void) fprintf(cs->stack->prof_file, PROF_SFMT, (ulong) cs->framep, stackused,
- cs->func);
-#endif
+ AUTOS_REVERSE ? _stack_frame_->func : cs->func);
(void) fflush(cs->stack->prof_file);
}
#endif
- if (DoTrace(cs))
- {
- if (!cs->locked)
- pthread_mutex_lock(&THR_LOCK_dbug);
- DoPrefix(cs, _line_);
- Indent(cs, cs->level);
- (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
- dbug_flush(cs); /* This does a unlock */
- }
-#ifdef SAFEMALLOC
- if (cs->stack->flags & SANITY_CHECK_ON)
- if (_sanity(_file_,_line_)) /* Check of safemalloc */
+ switch (DoTrace(cs)) {
+ case ENABLE_TRACE:
+ cs->framep->level|= TRACE_ON;
+ if (!TRACING) break;
+ /* fall through */
+ case DO_TRACE:
+ if ((cs->stack->flags & SANITY_CHECK_ON) && _sanity(_file_,_line_))
cs->stack->flags &= ~SANITY_CHECK_ON;
-#endif
+ if (TRACING)
+ {
+ if (!cs->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ DoPrefix(cs, _line_);
+ Indent(cs, cs->level);
+ (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
+ DbugFlush(cs); /* This does a unlock */
+ }
+ break;
+ case DISABLE_TRACE:
+ cs->framep->level&= ~TRACE_ON;
+ /* fall through */
+ case DONT_TRACE:
+ break;
+ }
errno=save_errno;
}
@@ -1018,11 +1191,9 @@ void _db_enter_(const char *_func_, const char *_file_,
*
* SYNOPSIS
*
- * VOID _db_return_(_line_, _sfunc_, _sfile_, _slevel_)
+ * VOID _db_return_(_line_, _stack_frame_)
* int _line_; current source line number
- * char **_sfunc_; where previous _func_ is to be retrieved
- * char **_sfile_; where previous _file_ is to be retrieved
- * int *_slevel_; where previous level was stashed
+ * struct _db_stack_frame_ allocated on the caller's stack
*
* DESCRIPTION
*
@@ -1034,51 +1205,52 @@ void _db_enter_(const char *_func_, const char *_file_,
*/
/* helper macro */
-void _db_return_(uint _line_, const char **_sfunc_,
- const char **_sfile_, uint *_slevel_)
+void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
{
int save_errno=errno;
- CODE_STATE *cs=0;
+ uint _slevel_= _stack_frame_->level & ~TRACE_ON;
+ CODE_STATE *cs;
get_code_state_or_return;
- if (cs->level != (int) *_slevel_)
+ if (cs->level != _slevel_)
{
if (!cs->locked)
pthread_mutex_lock(&THR_LOCK_dbug);
(void) fprintf(cs->stack->out_file, ERR_MISSING_RETURN, cs->process,
cs->func);
- dbug_flush(cs);
+ DbugFlush(cs);
}
else
{
-#ifdef SAFEMALLOC
- if (cs->stack->flags & SANITY_CHECK_ON)
- {
- if (_sanity(*_sfile_,_line_))
- cs->stack->flags &= ~SANITY_CHECK_ON;
- }
-#endif
#ifndef THREAD
if (DoProfile(cs))
(void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
#endif
- if (DoTrace(cs))
+ if (DoTrace(cs) & DO_TRACE)
{
- if (!cs->locked)
- pthread_mutex_lock(&THR_LOCK_dbug);
- DoPrefix(cs, _line_);
- Indent(cs, cs->level);
- (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
- dbug_flush(cs);
+ if ((cs->stack->flags & SANITY_CHECK_ON) &&
+ _sanity(_stack_frame_->file,_line_))
+ cs->stack->flags &= ~SANITY_CHECK_ON;
+ if (TRACING)
+ {
+ if (!cs->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ DoPrefix(cs, _line_);
+ Indent(cs, cs->level);
+ (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
+ DbugFlush(cs);
+ }
}
}
- cs->level= *_slevel_-1;
- cs->func= *_sfunc_;
- cs->file= *_sfile_;
-#ifndef THREAD
+ /*
+ Check to not set level < 0. This can happen if DBUG was disabled when
+ function was entered and enabled in function.
+ */
+ cs->level= _slevel_ != 0 ? _slevel_ - 1 : 0;
+ cs->func= _stack_frame_->func;
+ cs->file= _stack_frame_->file;
if (cs->framep != NULL)
- cs->framep= (char **) *cs->framep;
-#endif
+ cs->framep= cs->framep->prev;
errno=save_errno;
}
@@ -1105,7 +1277,7 @@ void _db_return_(uint _line_, const char **_sfunc_,
void _db_pargs_(uint _line_, const char *keyword)
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return;
cs->u_line= _line_;
cs->u_keyword= keyword;
@@ -1141,13 +1313,12 @@ void _db_pargs_(uint _line_, const char *keyword)
void _db_doprnt_(const char *format,...)
{
va_list args;
-
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return;
va_start(args,format);
- if (_db_keyword_(cs, cs->u_keyword))
+ if (_db_keyword_(cs, cs->u_keyword, 0))
{
int save_errno=errno;
if (!cs->locked)
@@ -1160,7 +1331,7 @@ void _db_doprnt_(const char *format,...)
(void) fprintf(cs->stack->out_file, "%s: ", cs->u_keyword);
(void) vfprintf(cs->stack->out_file, format, args);
(void) fputc('\n',cs->stack->out_file);
- dbug_flush(cs);
+ DbugFlush(cs);
errno=save_errno;
}
va_end(args);
@@ -1190,11 +1361,10 @@ void _db_dump_(uint _line_, const char *keyword,
{
int pos;
char dbuff[90];
-
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return;
- if (_db_keyword_(cs, keyword))
+ if (_db_keyword_(cs, keyword, 0))
{
if (!cs->locked)
pthread_mutex_lock(&THR_LOCK_dbug);
@@ -1226,7 +1396,7 @@ void _db_dump_(uint _line_, const char *keyword,
fputc(' ',cs->stack->out_file);
}
(void) fputc('\n',cs->stack->out_file);
- dbug_flush(cs);
+ DbugFlush(cs);
}
}
@@ -1234,93 +1404,74 @@ void _db_dump_(uint _line_, const char *keyword,
/*
* FUNCTION
*
- * ListAdd add to the list modifiers from debug control string
- *
- * SYNOPSIS
- *
- * static struct link *ListAdd(listp, ctlp, end)
- * struct link *listp;
- * char *ctlp;
- * char *end;
+ * ListAddDel modify the list according to debug control string
*
* DESCRIPTION
*
* Given pointer to a comma separated list of strings in "cltp",
- * parses the list, and adds it to listp, returning a pointer
- * to the new list
+ * parses the list, and modifies "listp", returning a pointer
+ * to the new list.
*
- * Note that since each link is added at the head of the list,
- * the final list will be in "reverse order", which is not
- * significant for our usage here.
+ * The mode of operation is defined by "todo" parameter.
*
- */
-
-static struct link *ListAdd(struct link *head,
- const char *ctlp, const char *end)
-{
- const char *start;
- struct link *new_malloc;
- int len;
-
- while (ctlp < end)
- {
- start= ctlp;
- while (ctlp < end && *ctlp != ',')
- ctlp++;
- len=ctlp-start;
- new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
- memcpy(new_malloc->str, start, len);
- new_malloc->str[len]=0;
- new_malloc->next_link= head;
- head= new_malloc;
- ctlp++;
- }
- return head;
-}
-
-/*
- * FUNCTION
- *
- * ListDel remove from the list modifiers in debug control string
- *
- * SYNOPSIS
- *
- * static struct link *ListDel(listp, ctlp, end)
- * struct link *listp;
- * char *ctlp;
- * char *end;
- *
- * DESCRIPTION
- *
- * Given pointer to a comma separated list of strings in "cltp",
- * parses the list, and removes these strings from the listp,
- * returning a pointer to the new list.
+ * If it is INCLUDE, elements (strings from "cltp") are added to the
+ * list, they will have INCLUDE flag set. If the list already contains
+ * the string in question, new element is not added, but a flag of
+ * the existing element is adjusted (INCLUDE bit is set, EXCLUDE bit
+ * is removed).
*
+ * If it is EXCLUDE, elements are added to the list with the EXCLUDE
+ * flag set. If the list already contains the string in question,
+ * it is removed, new element is not added.
*/
-static struct link *ListDel(struct link *head,
- const char *ctlp, const char *end)
+static struct link *ListAddDel(struct link *head, const char *ctlp,
+ const char *end, int todo)
{
const char *start;
struct link **cur;
- int len;
+ int len, subdir;
- while (ctlp < end)
+ ctlp--;
+next:
+ while (++ctlp < end)
{
start= ctlp;
+ subdir=0;
while (ctlp < end && *ctlp != ',')
ctlp++;
len=ctlp-start;
- cur=&head;
- do
+ if (start[len-1] == '/')
+ {
+ len--;
+ subdir=SUBDIR;
+ }
+ if (len == 0) continue;
+ for (cur=&head; *cur; cur=&((*cur)->next_link))
{
- while (*cur && !strncmp((*cur)->str, start, len))
+ if (!strncmp((*cur)->str, start, len))
{
- struct link *delme=*cur;
- *cur=(*cur)->next_link;
- free((void*) delme);
+ if ((*cur)->flags & todo) /* same action ? */
+ (*cur)->flags|= subdir; /* just merge the SUBDIR flag */
+ else if (todo == EXCLUDE)
+ {
+ struct link *delme=*cur;
+ *cur=(*cur)->next_link;
+ free((void*) delme);
+ }
+ else
+ {
+ (*cur)->flags&=~(EXCLUDE & SUBDIR);
+ (*cur)->flags|=INCLUDE | subdir;
+ }
+ goto next;
}
- } while (*cur && *(cur=&((*cur)->next_link)));
+ }
+ *cur= (struct link *) DbugMalloc(sizeof(struct link)+len);
+ memcpy((*cur)->str, start, len);
+ (*cur)->str[len]=0;
+ (*cur)->flags=todo | subdir;
+ (*cur)->next_link=0;
}
return head;
}
@@ -1361,6 +1512,7 @@ static struct link *ListCopy(struct link *orig)
new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
memcpy(new_malloc->str, orig->str, len);
new_malloc->str[len]= 0;
+ new_malloc->flags=orig->flags;
new_malloc->next_link= head;
head= new_malloc;
orig= orig->next_link;
@@ -1373,47 +1525,52 @@ static struct link *ListCopy(struct link *orig)
*
* InList test a given string for member of a given list
*
- * SYNOPSIS
- *
- * static BOOLEAN InList(linkp, cp)
- * struct link *linkp;
- * char *cp;
- *
* DESCRIPTION
*
* Tests the string pointed to by "cp" to determine if it is in
* the list pointed to by "linkp". Linkp points to the first
- * link in the list. If linkp is NULL then the string is treated
- * as if it is in the list (I.E all strings are in the null list).
+ * link in the list. If linkp is NULL or contains only EXCLUDE
+ * elements then the string is treated as if it is in the list.
* This may seem rather strange at first but leads to the desired
* operation if no list is given. The net effect is that all
* strings will be accepted when there is no list, and when there
* is a list, only those strings in the list will be accepted.
*
+ * RETURN
+ * combination of SUBDIR, INCLUDE, EXCLUDE, MATCHED flags
+ *
*/
-static BOOLEAN InList(struct link *linkp, const char *cp)
+static int InList(struct link *linkp, const char *cp)
{
- REGISTER struct link *scan;
- REGISTER BOOLEAN result;
+ int result;
- if (linkp == NULL)
- result= TRUE;
- else
+ for (result=MATCHED; linkp != NULL; linkp= linkp->next_link)
{
- result= FALSE;
- for (scan= linkp; scan != NULL; scan= scan->next_link)
- {
- if (!strcmp(scan->str, cp))
- {
- result= TRUE;
- break;
- }
- }
+ if (!strcmp(linkp->str, cp))
+ return linkp->flags;
+ if (!(linkp->flags & EXCLUDE))
+ result=NOT_MATCHED;
+ if (linkp->flags & SUBDIR)
+ result|=SUBDIR;
}
return result;
}
+/*
+ * FUNCTION
+ *
+ * ListFlags returns aggregated list flags (ORed over all elements)
+ *
+ */
+
+static uint ListFlags(struct link *linkp)
+{
+ uint f;
+ for (f=0; linkp != NULL; linkp= linkp->next_link)
+ f|= linkp->flags;
+ return f;
+}
/*
* FUNCTION
@@ -1503,8 +1660,12 @@ void _db_end_()
{
struct settings *discard;
static struct settings tmp;
- CODE_STATE *cs=0;
-
+ CODE_STATE *cs;
+ /*
+ Set _dbug_on_ to be able to do full reset even when DEBUGGER_OFF was
+ called after dbug was initialized
+ */
+ _dbug_on_= 1;
get_code_state_or_return;
while ((discard= cs->stack))
@@ -1538,25 +1699,30 @@ void _db_end_()
*
* DoTrace check to see if tracing is current enabled
*
- * SYNOPSIS
- *
- * static BOOLEAN DoTrace(stack)
- *
* DESCRIPTION
*
- * Checks to see if tracing is enabled based on whether the
- * user has specified tracing, the maximum trace depth has
- * not yet been reached, the current function is selected,
- * and the current process is selected. Returns TRUE if
- * tracing is enabled, FALSE otherwise.
+ * Checks to see if dbug in this function is enabled based on
+ * whether the maximum trace depth has been reached, the current
+ * function is selected, and the current process is selected.
*
*/
-static BOOLEAN DoTrace(CODE_STATE *cs)
+static int DoTrace(CODE_STATE *cs)
{
- return (TRACING && cs->level <= cs->stack->maxdepth &&
- InList(cs->stack->functions, cs->func) &&
- InList(cs->stack->processes, cs->process));
+ if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
+ InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
+ switch(InList(cs->stack->functions, cs->func)) {
+ case INCLUDE|SUBDIR: return ENABLE_TRACE;
+ case INCLUDE: return DO_TRACE;
+ case MATCHED|SUBDIR:
+ case NOT_MATCHED|SUBDIR:
+ case MATCHED: return framep_trace_flag(cs, cs->framep) ?
+ DO_TRACE : DONT_TRACE;
+ case EXCLUDE:
+ case NOT_MATCHED: return DONT_TRACE;
+ case EXCLUDE|SUBDIR: return DISABLE_TRACE;
+ }
+ return DONT_TRACE;
}
@@ -1584,62 +1750,27 @@ static BOOLEAN DoProfile(CODE_STATE *cs)
{
return PROFILING &&
cs->level <= cs->stack->maxdepth &&
- InList(cs->stack->p_functions, cs->func) &&
- InList(cs->stack->processes, cs->process);
+ InList(cs->stack->p_functions, cs->func) & (INCLUDE|MATCHED) &&
+ InList(cs->stack->processes, cs->process) & (INCLUDE|MATCHED);
}
#endif
FILE *_db_fp_(void)
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return NULL;
return cs->stack->out_file;
}
-
-/*
- * FUNCTION
- *
- * _db_strict_keyword_ test keyword for member of keyword list
- *
- * SYNOPSIS
- *
- * BOOLEAN _db_strict_keyword_(keyword)
- * char *keyword;
- *
- * DESCRIPTION
- *
- * Similar to _db_keyword_, but keyword is NOT accepted if keyword list
- * is empty. Used in DBUG_EXECUTE_IF() - for actions that must not be
- * executed by default.
- *
- * Returns TRUE if keyword accepted, FALSE otherwise.
- *
- */
-
-BOOLEAN _db_strict_keyword_(const char *keyword)
-{
- CODE_STATE *cs=0;
- get_code_state_or_return FALSE;
- if (!DEBUGGING || cs->stack->keywords == NULL)
- return FALSE;
- return _db_keyword_(cs, keyword);
-}
-
/*
* FUNCTION
*
* _db_keyword_ test keyword for member of keyword list
*
- * SYNOPSIS
- *
- * BOOLEAN _db_keyword_(keyword)
- * char *keyword;
- *
* DESCRIPTION
*
* Test a keyword to determine if it is in the currently active
- * keyword list. As with the function list, a keyword is accepted
+ * keyword list. If strict=0, a keyword is accepted
* if the list is null, otherwise it must match one of the list
* members. When debugging is not on, no keywords are accepted.
* After the maximum trace level is exceeded, no keywords are
@@ -1651,15 +1782,13 @@ BOOLEAN _db_strict_keyword_(const char *keyword)
*
*/
-BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword)
+BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
{
- get_code_state_or_return FALSE;
+ get_code_state_if_not_set_or_return FALSE;
+ strict=strict ? INCLUDE : INCLUDE|MATCHED;
- return (DEBUGGING &&
- (!TRACING || cs->level <= cs->stack->maxdepth) &&
- InList(cs->stack->functions, cs->func) &&
- InList(cs->stack->keywords, keyword) &&
- InList(cs->stack->processes, cs->process));
+ return DEBUGGING && DoTrace(cs) & DO_TRACE &&
+ InList(cs->stack->keywords, keyword) & strict;
}
/*
@@ -1955,7 +2084,7 @@ static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
pthread_mutex_lock(&THR_LOCK_dbug);
(void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
perror("");
- dbug_flush(cs);
+ DbugFlush(cs);
}
}
@@ -2172,7 +2301,7 @@ static void ChangeOwner(CODE_STATE *cs, char *pathname)
EXPORT void _db_setjmp_()
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return;
cs->jmplevel= cs->level;
@@ -2199,7 +2328,7 @@ EXPORT void _db_setjmp_()
EXPORT void _db_longjmp_()
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return;
cs->level= cs->jmplevel;
@@ -2250,11 +2379,9 @@ char *s;
/* This is because some systems (MSDOS!!) dosn't flush fileheader */
/* and dbug-file isn't readable after a system crash !! */
-static void dbug_flush(CODE_STATE *cs)
+static void DbugFlush(CODE_STATE *cs)
{
-#ifndef THREAD
if (cs->stack->flags & FLUSH_ON_WRITE)
-#endif
{
(void) fflush(cs->stack->out_file);
if (cs->stack->delay)
@@ -2262,12 +2389,22 @@ static void dbug_flush(CODE_STATE *cs)
}
if (!cs->locked)
pthread_mutex_unlock(&THR_LOCK_dbug);
-} /* dbug_flush */
+} /* DbugFlush */
+
+
+/* For debugging */
+
+void _db_flush_()
+{
+ CODE_STATE *cs;
+ get_code_state_or_return;
+ (void) fflush(cs->stack->out_file);
+}
void _db_lock_file_()
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return;
pthread_mutex_lock(&THR_LOCK_dbug);
cs->locked=1;
@@ -2275,7 +2412,7 @@ void _db_lock_file_()
void _db_unlock_file_()
{
- CODE_STATE *cs=0;
+ CODE_STATE *cs;
get_code_state_or_return;
cs->locked=0;
pthread_mutex_unlock(&THR_LOCK_dbug);
diff --git a/dbug/dbug_add_tags.pl b/dbug/dbug_add_tags.pl
index 141a2ed85f1..3e51a54c707 100755
--- a/dbug/dbug_add_tags.pl
+++ b/dbug/dbug_add_tags.pl
@@ -7,7 +7,7 @@ $ctags="exctags -x -f - --c-types=f -u";
sub get_tag {
local $.; local $_=<TAGS>;
($symbol, $line)= /^(.*\S)\s+function\s+(\d+)/;
- $symbol=$1 if /\s(\S+)\s*\(/;
+ $symbol=$1 if /[\s*]([^\s*]+)\s*\(/;
$line=1e50 unless $line;
}
@@ -51,7 +51,7 @@ while($src=shift)
$skip=!$semicolon;
$semicolon= /;\s*$/;
print && next if $skip ||
- (/^\s+\w+((::\w+)?|<\w+>)\s+\**\w+/ && !/^\s*return/);
+ (/^\s+\w+((::\w+)?|<\w+>)\s+\**\w+/ && !/^\s*return\b/);
last if /DBUG_ENTER/;
print "$tab DBUG_ENTER(\"$symbol\");\n";
print "\n" unless $_ eq "\n";
diff --git a/dbug/doinstall.sh b/dbug/doinstall.sh
deleted file mode 100644
index 707f193c761..00000000000
--- a/dbug/doinstall.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-
-# Warning - first line left blank for sh/csh/ksh compatibility. Do not
-# remove it. fnf@Unisoft
-
-# doinstall.sh --- figure out environment and do recursive make with
-# appropriate pathnames. Works under SV or BSD.
-
-if [ -r /usr/include/search.h ]
-then
- # System V
- $* LLIB=/usr/lib
-else
- # 4.2 BSD
- $* LLIB=/usr/lib/lint
-fi
diff --git a/dbug/install.sh b/dbug/install.sh
deleted file mode 100644
index 7226e01b1cf..00000000000
--- a/dbug/install.sh
+++ /dev/null
@@ -1,64 +0,0 @@
-
-# WARNING -- first line intentionally left blank for sh/csh/ksh
-# compatibility. Do not remove it! FNF, UniSoft Systems.
-#
-# Usage is:
-# install <from> <to>
-#
-# The file <to> is replaced with the file <from>, after first
-# moving <to> to a backup file. The backup file name is created
-# by prepending the filename (after removing any leading pathname
-# components) with "OLD".
-#
-# This script is currently not real robust in the face of signals
-# or permission problems. It also does not do (by intention) all
-# the things that the System V or BSD install scripts try to do
-#
-
-if [ $# -ne 2 ]
-then
- echo "usage: $0 <from> <to>"
- exit 1
-fi
-
-# Now extract the dirname and basename components. Unfortunately, BSD does
-# not have dirname, so we do it the hard way.
-
-fd=`expr $1'/' : '\(/\)[^/]*/$' \| $1'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
-ff=`basename $1`
-td=`expr $2'/' : '\(/\)[^/]*/$' \| $2'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \| .`
-tf=`basename $2`
-
-# Now test to make sure that they are not the same files.
-
-if [ $fd/$ff = $td/$tf ]
-then
- echo "install: input and output are same files"
- exit 2
-fi
-
-# Save a copy of the "to" file as a backup.
-
-if test -f $td/$tf
-then
- if test -f $td/OLD$tf
- then
- rm -f $td/OLD$tf
- fi
- mv $td/$tf $td/OLD$tf
- if [ $? != 0 ]
- then
- exit 3
- fi
-fi
-
-# Now do the copy and return appropriate status
-
-cp $fd/$ff $td/$tf
-if [ $? != 0 ]
-then
- exit 4
-else
- exit 0
-fi
-
diff --git a/dbug/mklintlib.sh b/dbug/mklintlib.sh
deleted file mode 100644
index 6963016f334..00000000000
--- a/dbug/mklintlib.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-
-# Warning - first line left blank for sh/csh/ksh compatibility. Do not
-# remove it. fnf@Unisoft
-
-# mklintlib --- make a lint library, under either System V or 4.2 BSD
-#
-# usage: mklintlib <infile> <outfile>
-#
-
-if test $# -ne 2
-then
- echo "usage: mklintlib <infile> <outfile>"
- exit 1
-fi
-
-if grep SIGTSTP /usr/include/signal.h >/dev/null
-then # BSD
- if test -r /usr/include/whoami.h # 4.1
- then
- /lib/cpp -C -Dlint $1 >hlint
- (/usr/lib/lint/lint1 <hlint >$2) 2>&1 | grep -v warning
- else # 4.2
- lint -Cxxxx $1
- mv llib-lxxxx.ln $2
- fi
-else # USG
- cc -E -C -Dlint $1 | /usr/lib/lint1 -vx -Hhlint >$2
- rm -f hlint
-fi
-exit 0 # don't kill make
diff --git a/dbug/qmake.cmd b/dbug/qmake.cmd
deleted file mode 100644
index ebd4432f7fc..00000000000
--- a/dbug/qmake.cmd
+++ /dev/null
@@ -1,4 +0,0 @@
-CL -I\my\include -AL -Gsm2 -FPi -DDBUG_OFF *.c
-rm \my\lib\dbug.lib
-lib.exe \my\lib\dbug dbug.obj sanity.obj;
-link /NOD /STACK:8000 main factoria,factoria,,DBUG+STRINGS+LLIBCEP+DOSCALLS;
diff --git a/dbug/remove_function_from_trace.pl b/dbug/remove_function_from_trace.pl
new file mode 100755
index 00000000000..1da9e25f9ba
--- /dev/null
+++ b/dbug/remove_function_from_trace.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+
+
+die <<EEE unless @ARGV;
+Usage: $0 func1 [func2 [ ...] ]
+
+This filter (stdin->stdout) removes lines from dbug trace that were generated
+by specified functions and all functions down the call stack. Produces the
+same effect as if the original source had DBUG_PUSH(""); right after
+DBUG_ENTER() and DBUG_POP(); right before DBUG_RETURN in every such a function.
+EEE
+
+$re=join('|', @ARGV);
+$skip='';
+
+while(<STDIN>) {
+ print unless $skip;
+ next unless /^(?:.*: )*((?:\| )*)([<>])($re)\n/o;
+ if ($2 eq '>') {
+ $skip=$1.$3 unless $skip;
+ next;
+ }
+ next if $skip ne $1.$3;
+ $skip='';
+ print;
+}
diff --git a/dbug/tests-t.pl b/dbug/tests-t.pl
new file mode 100755
index 00000000000..de9ed6f6ab9
--- /dev/null
+++ b/dbug/tests-t.pl
@@ -0,0 +1,496 @@
+#!/usr/bin/env perl
+
+#
+# A driver program to test DBUG features - runs tests (shell commands)
+# from the end of file to invoke tests.c, which does the real dbug work.
+#
+
+use Test::More;
+
+$exe=$0;
+
+die unless $exe =~ s/(tests)-t(\.exe)?$/$1$2 /;
+
+# load tests
+@tests=();
+while (<DATA>) {
+ if (/^% \.\/tests /) {
+ push @tests, [ $' ]
+ } elsif (/^#/) {
+ next;
+ } else {
+ push @{$tests[$#tests]}, $_
+ }
+}
+
+plan skip_all => "because dbug is disabled" if system $exe;
+
+plan tests => scalar(@tests);
+
+for (@tests) {
+ $t=$exe . shift @$_;
+ chomp($t);
+ open F, '-|', $t or die "open($t|): $!";
+ local $";
+ $out=join($", <F>); close(F);
+ # special cases are handled here:
+ $out =~ s/Memory: 0x[0-9A-Fa-f]+/Memory: 0x####/g if $t =~ /dump/;
+ # compare ("\n" at the beginning makes better output in case of errors)
+ is("\n$out","\n@$_", $t);
+}
+
+__DATA__
+% ./tests -#d
+func2: info: s=ok
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d
+func2: info: s=ok
+% ./tests d,ret3
+=> evaluate: OFF
+=> evaluate_if: OFF
+#
+## Testing negative lists
+#
+% ./tests d:-d,ret3
+func2: info: s=ko
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,ret3
+func2: info: s=ko
+% ./tests t:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+% ./tests t:d,info:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests t:d,info:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate
+=> evaluate: ON
+=> evaluate_if: OFF
+% ./tests t:d,info:-d,ret3:-f,func2 d,evaluate_if
+=> evaluate: OFF
+=> evaluate_if: ON
+% ./tests t:d:-d,ret3:-f,func2 d,evaluate_if
+=> evaluate: OFF
+=> evaluate_if: ON
+% ./tests t:d:-d,ret3:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+#
+## Adding incremental settings to the brew
+#
+% ./tests t:d:-d,ret3:-f,func2 +d,evaluate_if
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> evaluate: OFF
+=> evaluate_if: ON
+| | >func3
+| | <func3
+<main
+#
+## DBUG_DUMP
+#
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x#### Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A
+74
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x#### Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A
+74
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2:+d,dump
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x#### Bytes: (27)
+64 2C 64 75 6D 70 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D 66 2C 66 75 6E 63 32 3A
+74
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+| dump: Memory: 0x#### Bytes: (35)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D
+66 2C 66 75 6E 63 32 3A 74
+=> evaluate: OFF
+=> evaluate_if: OFF
+| explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P
+dbug: >main
+dbug-tests: | >func1
+dbug-tests: | | | >func3
+dbug-tests: | | | <func3
+dbug-tests: | <func1
+dbug-tests: | dump: Memory: 0x#### Bytes: (37)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D
+66 2C 66 75 6E 63 32 3A 50 3A 74
+=> evaluate: OFF
+=> evaluate_if: OFF
+dbug-tests: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:P:t
+dbug-tests: | | >func3
+dbug-tests: | | <func3
+dbug-tests: <main
+% ./tests t:d:-d,ret3:f:-f,func2 +d,dump,explain:P:F
+dbug: tests.c: >main
+dbug-tests: tests.c: | >func1
+dbug-tests: tests.c: | | | >func3
+dbug-tests: tests.c: | | | <func3
+dbug-tests: tests.c: | <func1
+dbug-tests: tests.c: | dump: Memory: 0x#### Bytes: (39)
+64 2C 64 75 6D 70 2C 65 78 70 6C 61 69 6E 3A 2D 64 2C 72 65 74 33 3A 66 3A 2D
+66 2C 66 75 6E 63 32 3A 46 3A 50 3A 74
+=> evaluate: OFF
+=> evaluate_if: OFF
+dbug-tests: tests.c: | explain: dbug explained: d,dump,explain:-d,ret3:f:-f,func2:F:P:t
+dbug-tests: tests.c: | | >func3
+dbug-tests: tests.c: | | <func3
+dbug-tests: tests.c: <main
+#
+## DBUG_EXPLAIN, DBUG_PUSH, DBUG_POP, DBUG_SET
+#
+% ./tests t:d:-d,ret3:f:-f,func2
+>main
+| >func1
+| | | >func3
+| | | <func3
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:f:-f,func2:t
+| | >func3
+| | <func3
+<main
+% ./tests t:d:-d,ret3
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:-d,ret3:t
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,push
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,push,explain
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| explain: dbug explained: d,info,push,explain:-d,ret3:t
+| >func2
+| | >func3
+| | <func3
+| | info: s=ko
+| <func2
+<main
+% ./tests d,info:-d,ret3:d,explain
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,pop
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests d,info:-d,ret3:d,explain t:d,pop
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,pop +t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+main: explain: dbug explained: d,info,explain,pop:-d,ret3
+func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,set
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+ tests.c: main: explain: dbug explained: d,info,explain,set:-d,ret3:F
+ tests.c: func2: info: s=ko
+% ./tests d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+ tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+ tests.c: | >func2
+ tests.c: | | >func3
+ tests.c: | | <func3
+ tests.c: | | info: s=ko
+ tests.c: | <func2
+ tests.c: <main
+% ./tests t d,info:-d,ret3:d,explain,set:t
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ko
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+ tests.c: | explain: dbug explained: d,info,explain,set:-d,ret3:F:t
+ tests.c: | >func2
+ tests.c: | | >func3
+ tests.c: | | <func3
+ tests.c: | | info: s=ko
+ tests.c: | <func2
+ tests.c: <main
+% ./tests t d,info:-d,ret3:d,explain,set,pop
+func2: info: s=ko
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+% ./tests t:f,func2
+| | >func2
+| | <func2
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| <func2
+#
+## Testing SUBDIR rules
+#
+% ./tests t:-f,func2/:d
+>main
+| >func1
+| <func1
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+| explain: dbug explained: d:f:-f,func2/:t
+<main
+% ./tests t:f,func1/:d
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | | info: s=ok
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests t:f,main/:d,pop
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+% ./tests f,main/:d,push
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+#
+## Testing FixTraceFlags() - when we need to traverse the call stack
+# (these tests fail with FixTraceFlags() disabled)
+#
+# delete the INCLUDE rule up the stack
+% ./tests t:f,func1/ --push1=t:f,func3/
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+=> push1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| | >func3
+| | <func3
+# delete the EXCLUDE rule up the stack
+% ./tests t:-f,func1/ --push1=t
+>main
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# add the INCLUDE rule up the stack
+% ./tests t:f,func3 --push1=t:f,main/
+| | | >func3
+| | | <func3
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# add the EXCLUDE rule up the stack
+% ./tests t --push1=t:-f,main/
+>main
+| >func1
+| | >func2
+| | | >func3
+| | | <func3
+| | <func2
+=> push1
+=> evaluate: OFF
+=> evaluate_if: OFF
+# change the defaults
+% ./tests t:f,func3 --push1=t
+| | | >func3
+| | | <func3
+=> push1
+| <func1
+=> evaluate: OFF
+=> evaluate_if: OFF
+| >func2
+| | >func3
+| | <func3
+| <func2
+<main
+# repeated keyword
+% ./tests d:-d,info,info
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,info
+% ./tests d:-d,info/,info
+=> execute
+=> evaluate: ON
+=> evaluate_if: OFF
+main: explain: dbug explained: d:-d,info/
diff --git a/dbug/tests.c b/dbug/tests.c
new file mode 100644
index 00000000000..d76266d34a3
--- /dev/null
+++ b/dbug/tests.c
@@ -0,0 +1,87 @@
+/*
+ A program to test DBUG features. Used by tests-t.pl
+*/
+
+char *push1=0;
+
+#include <my_global.h> /* This includes dbug.h */
+#include <my_pthread.h>
+#include <string.h>
+
+const char *func3()
+{
+ DBUG_ENTER("func3");
+ DBUG_RETURN(DBUG_EVALUATE("ret3", "ok", "ko"));
+}
+
+void func2()
+{
+ const char *s;
+ DBUG_ENTER("func2");
+ s=func3();
+ DBUG_PRINT("info", ("s=%s", s));
+ DBUG_VOID_RETURN;
+}
+
+int func1()
+{
+ DBUG_ENTER("func1");
+ func2();
+ if (push1)
+ {
+ DBUG_PUSH(push1);
+ fprintf(DBUG_FILE, "=> push1\n");
+ }
+ DBUG_RETURN(10);
+}
+
+int main (int argc, char *argv[])
+{
+ int i;
+#ifdef DBUG_OFF
+ return 1;
+#endif
+ if (argc == 1)
+ return 0;
+
+#if defined(HAVE_PTHREAD_INIT) && defined(THREAD)
+ pthread_init(); /* Must be called before DBUG_ENTER */
+#endif
+#ifdef THREAD
+ my_thread_global_init();
+#endif
+ dup2(1, 2);
+ for (i = 1; i < argc; i++)
+ {
+ if (strncmp(argv[i], "--push1=", 8) == 0)
+ push1=argv[i]+8;
+ else
+ DBUG_PUSH (argv[i]);
+ }
+ {
+ DBUG_ENTER ("main");
+ DBUG_PROCESS ("dbug-tests");
+ func1();
+ DBUG_EXECUTE_IF("dump",
+ {
+ char s[1000];
+ DBUG_EXPLAIN(s, sizeof(s)-1);
+ DBUG_DUMP("dump", (uchar*)s, strlen(s));
+ });
+ DBUG_EXECUTE_IF("push", DBUG_PUSH("+t"); );
+ DBUG_EXECUTE("execute", fprintf(DBUG_FILE, "=> execute\n"); );
+ DBUG_EXECUTE_IF("set", DBUG_SET("+F"); );
+ fprintf(DBUG_FILE, "=> evaluate: %s\n",
+ DBUG_EVALUATE("evaluate", "ON", "OFF"));
+ fprintf(DBUG_FILE, "=> evaluate_if: %s\n",
+ DBUG_EVALUATE_IF("evaluate_if", "ON", "OFF"));
+ DBUG_EXECUTE_IF("pop", DBUG_POP(); );
+ {
+ char s[1000] __attribute__((unused));
+ DBUG_EXPLAIN(s, sizeof(s)-1);
+ DBUG_PRINT("explain", ("dbug explained: %s", s));
+ }
+ func2();
+ DBUG_RETURN (0);
+ }
+}
diff --git a/dbug/user.r b/dbug/user.r
index 19de840d0ad..527ad1f43cd 100644
--- a/dbug/user.r
+++ b/dbug/user.r
@@ -511,7 +511,7 @@ possible since all code preceding the first call to
.B DBUG_PUSH
is
essentially invisible to
-.B dbug
+.I dbug
(this can be worked around by
inserting a temporary
.B DBUG_PUSH(argv[1])
@@ -707,7 +707,7 @@ EX:\ \fCDBUG_PROCESS\ (argv[0]);\fR
.SP 1
.LI DBUG_PUSH\
Sets a new debugger state by pushing the current
-.B dbug
+.I dbug
state onto an internal stack and setting up the new state using the
debug control string passed as the macro argument. The most common
usage is to set the state specified by a debug control string
@@ -768,14 +768,14 @@ the 'd' flag. Used to conditionally execute "dangerous" actions, e.g
to crash the program testing how recovery works, or to introduce an
artificial delay checking for race conditions.
.SP 1
-EX:\ \fCDBUG_EXECUTE_IF\ ("crashme",\ abort\ ());\fR
+EX:\ \fCDBUG_EXECUTE_IF\ ("crashme",\ DBUG_ABORT()\ ());\fR
.SP 1
.LI DBUG_EVALUATE\
The DBUG_EVALUATE macro is similar to DBUG_EXECUTE, but it can be used in
the expression context. The first argument is the debug keyword that is used to
choose whether the second (keyword is enabled) or the third (keyword is not
enabled) argument is evaluated. When
-.B dbug
+.I dbug
is compiled off, the third argument is evaluated.
.SP 1
EX:\fC
@@ -795,7 +795,7 @@ EX:\fC
.br
if (prepare_transaction () ||
.br
- DBUG_EVALUATE ("crashme", (abort (), 0), 0) ||
+ DBUG_EVALUATE ("crashme", (DBUG_ABORT(), 0), 0) ||
.br
commit_transaction () )\fR
.SP 1
@@ -874,6 +874,12 @@ library. So there will be no need to disable asserts separately with NDEBUG.
.SP 1
EX:\ \fCDBUG_ASSERT(\ a\ >\ 0\ );\fR
.SP 1
+.LI DBUG_ABORT\
+This macro could be used instead of abort(). It flushes DBUG_FILE stream
+to ensure that no
+.I dbug
+output is lost and then calls abort().
+.SP 1
.LI DBUG_EXPLAIN\
Generates control string corresponding to the current debug state.
The macro takes two arguments - a buffer to store the result string
@@ -909,17 +915,17 @@ via the
.B DBUG_PUSH
or
.B DBUG_SET
-macros. Control string consists of colon separate flags. Colons
+macros. Control string consists of colon separated flags. Colons
that are part of ':\\', ':/', or '::' are not considered flag
separators. A flag may take an argument or a list of arguments.
If a control string starts from a '+' sign it works
.I incrementally,
-that is, it can modify existing state without overriding it. In such a
-string every flag may be preceded by a '+' or '-' to enable or disable
-a corresponding option in the debugger state. This section summarizes
-the currently available debugger options and the flag characters which
-enable or disable them. Argument lists enclosed in '[' and ']' are
-optional.
+that is, it can modify existing state without overriding it. Every
+flag may be preceded by a '+' or '-' to enable or disable a
+corresponding option in the debugger state or to add or remove
+arguments to the list. This section summarizes the currently available
+debugger options and the flag characters which enable or disable them.
+Argument lists enclosed in '[' and ']' are optional.
.SP 2
.BL 22
.LI a[,file]
@@ -943,6 +949,15 @@ Default is zero.
.LI f[,functions]
Limit debugger actions to the specified list of functions.
An empty list of functions implies that all functions are selected.
+Every function in the list may optionally be followed by a '/' -
+this will implicitly select all the functions down the call stack.
+.SP 1
+EX: \fCf,func1,func2/:-f,func3,func4/\fR
+.SP 1
+This would enable debugger in functions 'func1()', 'func2()' and all
+functions called from it (directly or indirectly). But not in
+functions 'func3()' or 'func4()' and all functions called from
+it.
.LI F
Mark each debugger output line with the name of the source file
containing the macro causing the output.
diff --git a/dbug/vargs.h b/dbug/vargs.h
deleted file mode 100644
index 4609c8301bb..00000000000
--- a/dbug/vargs.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/******************************************************************************
- * *
- * N O T I C E *
- * *
- * Copyright Abandoned, 1987, Fred Fish *
- * *
- * *
- * This previously copyrighted work has been placed into the public *
- * domain by the author and may be freely used for any purpose, *
- * private or commercial. *
- * *
- * Because of the number of inquiries I was receiving about the use *
- * of this product in commercially developed works I have decided to *
- * simply make it public domain to further its unrestricted use. I *
- * specifically would be most happy to see this material become a *
- * part of the standard Unix distributions by AT&T and the Berkeley *
- * Computer Science Research Group, and a standard part of the GNU *
- * system from the Free Software Foundation. *
- * *
- * I would appreciate it, as a courtesy, if this notice is left in *
- * all copies and derivative works. Thank you. *
- * *
- * The author makes no warranty of any kind with respect to this *
- * product and explicitly disclaims any implied warranties of mer- *
- * chantability or fitness for any particular purpose. *
- * *
- ******************************************************************************
- */
-
-
-/*
- * FILE
- *
- * vargs.h include file for environments without varargs.h
- *
- * SCCS
- *
- * @(#)vargs.h 1.2 5/8/88
- *
- * SYNOPSIS
- *
- * #include "vargs.h"
- *
- * DESCRIPTION
- *
- * This file implements a varargs macro set for use in those
- * environments where there is no system supplied varargs. This
- * generally works because systems which don't supply a varargs
- * package are precisely those which don't strictly need a varargs
- * package. Using this one then allows us to minimize source
- * code changes. So in some sense, this is a "portable" varargs
- * since it is only used for convenience, when it is not strictly
- * needed.
- *
- */
-
-/*
- * These macros allow us to rebuild an argument list on the stack
- * given only a va_list. We can use these to fake a function like
- * vfprintf, which gets a fixed number of arguments, the last of
- * which is a va_list, by rebuilding a stack and calling the variable
- * argument form fprintf. Of course this only works when vfprintf
- * is not available in the host environment, and thus is not available
- * for fprintf to call (which would give us an infinite loop).
- *
- * Note that ARGS_TYPE is a long, which lets us get several bytes
- * at a time while also preventing lots of "possible pointer alignment
- * problem" messages from lint. The messages are valid, because this
- * IS nonportable, but then we should only be using it in very
- * nonrestrictive environments, and using the real varargs where it
- * really counts.
- *
- */
-
-#define ARG0 a0
-#define ARG1 a1
-#define ARG2 a2
-#define ARG3 a3
-#define ARG4 a4
-#define ARG5 a5
-#define ARG6 a6
-#define ARG7 a7
-#define ARG8 a8
-#define ARG9 a9
-
-#define ARGS_TYPE long
-#define ARGS_LIST ARG0,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7,ARG8,ARG9
-#define ARGS_DCL auto ARGS_TYPE ARGS_LIST
-
-/*
- * A pointer of type "va_list" points to a section of memory
- * containing an array of variable sized arguments of unknown
- * number. This pointer is initialized by the va_start
- * macro to point to the first byte of the first argument.
- * We can then use it to walk through the argument list by
- * incrementing it by the size of the argument being referenced.
- */
-
-typedef char *va_list;
-
-/*
- * The first variable argument overlays va_alist, which is
- * nothing more than a "handle" which allows us to get the
- * address of the first argument on the stack. Note that
- * by definition, the va_dcl macro includes the terminating
- * semicolon, which makes use of va_dcl in the source code
- * appear to be missing a semicolon.
- */
-
-#define va_dcl ARGS_TYPE va_alist;
-
-/*
- * The va_start macro takes a variable of type "va_list" and
- * initializes it. In our case, it initializes a local variable
- * of type "pointer to char" to point to the first argument on
- * the stack.
- */
-
-#define va_start(list) list = (char *) &va_alist
-
-/*
- * The va_end macro is a null operation for our use.
- */
-
-#define va_end(list)
-
-/*
- * The va_arg macro is the tricky one. This one takes
- * a va_list as the first argument, and a type as the second
- * argument, and returns a value of the appropriate type
- * while advancing the va_list to the following argument.
- * For our case, we first increment the va_list arg by the
- * size of the type being recovered, cast the result to
- * a pointer of the appropriate type, and then dereference
- * that pointer as an array to get the previous arg (which
- * is the one we wanted.
- */
-
-#define va_arg(list,type) ((type *) (list += sizeof (type)))[-1]
diff --git a/extra/Makefile.am b/extra/Makefile.am
index 75422c4ee11..0ef679edcac 100644
--- a/extra/Makefile.am
+++ b/extra/Makefile.am
@@ -22,7 +22,8 @@ BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \
$(top_builddir)/include/sql_state.h \
$(top_builddir)/include/mysqld_ername.h
pkginclude_HEADERS= $(BUILT_SOURCES)
-DISTCLEANFILES = $(BUILT_SOURCES)
+EXTRA_PROGRAMS = comp_err
+DISTCLEANFILES = $(BUILT_SOURCES) $(EXTRA_PROGRAMS)
SUBDIRS = @yassl_dir@
DIST_SUBDIRS = yassl
@@ -50,7 +51,6 @@ bin_PROGRAMS += innochecksum
endif
noinst_PROGRAMS = charset2html
-EXTRA_PROGRAMS = comp_err
EXTRA_DIST = CMakeLists.txt
perror.o: perror.c
diff --git a/extra/replace.c b/extra/replace.c
index 9b7695eddcb..e254a5e7176 100644
--- a/extra/replace.c
+++ b/extra/replace.c
@@ -136,6 +136,7 @@ int main(int argc, char *argv[])
}
}
free_buffer();
+ my_free(replace, MYF(0));
my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
exit(error ? 2 : 0);
return 0; /* No compiler warning */
diff --git a/include/Makefile.am b/include/Makefile.am
index 64f73af8606..6ace3b6acf8 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -29,8 +29,8 @@ pkginclude_HEADERS = $(HEADERS_ABI) my_dbug.h m_string.h my_sys.h \
m_ctype.h my_attribute.h $(HEADERS_GEN_CONFIGURE) \
$(HEADERS_GEN_MAKE)
-noinst_HEADERS = config-win.h config-netware.h my_bit.h \
- heap.h my_bitmap.h my_uctype.h \
+noinst_HEADERS = config-win.h config-netware.h lf.h my_bit.h \
+ heap.h maria.h myisamchk.h my_bitmap.h my_uctype.h \
myisam.h myisampack.h myisammrg.h ft_global.h\
mysys_err.h my_base.h help_start.h help_end.h \
my_nosys.h my_alarm.h queues.h rijndael.h sha1.h \
@@ -38,9 +38,9 @@ noinst_HEADERS = config-win.h config-netware.h my_bit.h \
thr_lock.h t_ctype.h violite.h my_md5.h base64.h \
my_handler.h my_time.h \
my_vle.h my_user.h my_atomic.h atomic/nolock.h \
- atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \
- atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h
-
+ atomic/rwlock.h atomic/x86-gcc.h atomic/generic-msvc.h \
+ atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h \
+ wqueue.h waiting_threads.h
EXTRA_DIST = mysql.h.pp mysql/plugin.h.pp
# Remove built files and the symlinked directories
diff --git a/include/atomic/gcc_builtins.h b/include/atomic/gcc_builtins.h
index 509701b30a5..3eba2fff984 100644
--- a/include/atomic/gcc_builtins.h
+++ b/include/atomic/gcc_builtins.h
@@ -25,7 +25,10 @@
#ifdef MY_ATOMIC_MODE_DUMMY
#define make_atomic_load_body(S) ret= *a
#define make_atomic_store_body(S) *a= v
+#define MY_ATOMIC_MODE "gcc-builtins-up"
+
#else
+#define MY_ATOMIC_MODE "gcc-builtins-smp"
#define make_atomic_load_body(S) \
ret= __sync_fetch_and_or(a, 0);
#define make_atomic_store_body(S) \
diff --git a/include/atomic/generic-msvc.h b/include/atomic/generic-msvc.h
new file mode 100644
index 00000000000..58c6e7d8b9a
--- /dev/null
+++ b/include/atomic/generic-msvc.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _atomic_h_cleanup_
+#define _atomic_h_cleanup_ "atomic/generic-msvc.h"
+/*
+ We don't implement anything specific for MY_ATOMIC_MODE_DUMMY, always use
+ intrinsics.
+ 8 and 16-bit atomics are not implemented, but it can be done if necessary.
+*/
+
+/*
+ x86 compilers (both VS2003 or VS2005) never use instrinsics, but generate
+ function calls to kernel32 instead, even in the optimized build.
+ We force intrinsics as described in MSDN documentation for
+ _InterlockedCompareExchange.
+*/
+#ifdef _M_IX86
+
+#if (_MSC_VER >= 1400)
+#include <intrin.h>
+#else
+/*Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics*/
+LONG _InterlockedExchange (LONG volatile *Target,LONG Value);
+LONG _InterlockedCompareExchange (LONG volatile *Target, LONG Value, LONG Comp);
+LONG _InterlockedExchangeAdd (LONG volatile *Addend, LONG Value);
+#pragma intrinsic(_InterlockedExchangeAdd)
+#pragma intrinsic(_InterlockedCompareExchange)
+#pragma intrinsic(_InterlockedExchange)
+#endif
+
+#define InterlockedExchange _InterlockedExchange
+#define InterlockedExchangeAdd _InterlockedExchangeAdd
+#define InterlockedCompareExchange _InterlockedCompareExchange
+/*
+ No need to do something special for InterlockedCompareExchangePointer
+ as it is a #define to InterlockedCompareExchange. The same applies to
+ InterlockedExchangePointer.
+*/
+#endif /*_M_IX86*/
+
+#define MY_ATOMIC_MODE "msvc-intrinsics"
+#define IL_EXCHG_ADD32(X,Y) InterlockedExchangeAdd((volatile LONG *)(X),(Y))
+#define IL_COMP_EXCHG32(X,Y,Z) InterlockedCompareExchange((volatile LONG *)(X),(Y),(Z))
+#define IL_COMP_EXCHGptr InterlockedCompareExchangePointer
+#define IL_EXCHG32(X,Y) InterlockedExchange((volatile LONG *)(X),(Y))
+#define IL_EXCHGptr InterlockedExchangePointer
+#define make_atomic_add_body(S) \
+ v= IL_EXCHG_ADD ## S (a, v)
+#define make_atomic_cas_body(S) \
+ int ## S initial_cmp= *cmp; \
+ int ## S initial_a= IL_COMP_EXCHG ## S (a, set, initial_cmp); \
+ if (!(ret= (initial_a == initial_cmp))) *cmp= initial_a;
+#define make_atomic_swap_body(S) \
+ v= IL_EXCHG ## S (a, v)
+
+/*
+ my_yield_processor (equivalent of x86 PAUSE instruction) should be used
+ to improve performance on hyperthreaded CPUs. Intel recommends to use it in
+ spin loops also on non-HT machines to reduce power consumption (see e.g
+ http://softwarecommunity.intel.com/articles/eng/2004.htm)
+
+ Running benchmarks for spinlocks implemented with InterlockedCompareExchange
+ and YieldProcessor shows that much better performance is achieved by calling
+ YieldProcessor in a loop - that is, yielding longer. On Intel boxes setting
+ loop count in the range 200-300 brought best results.
+ */
+#ifndef YIELD_LOOPS
+#define YIELD_LOOPS 200
+#endif
+
+static __inline int my_yield_processor()
+{
+ int i;
+ for(i=0; i<YIELD_LOOPS; i++)
+ {
+#if (_MSC_VER <= 1310)
+ /* On older compilers YieldProcessor is not available, use inline assembly*/
+ __asm { rep nop }
+#else
+ YieldProcessor();
+#endif
+ }
+ return 1;
+}
+
+#define LF_BACKOFF my_yield_processor()
+#else /* cleanup */
+
+#undef IL_EXCHG_ADD32
+#undef IL_COMP_EXCHG32
+#undef IL_COMP_EXCHGptr
+#undef IL_EXCHG32
+#undef IL_EXCHGptr
+
+#endif
diff --git a/include/atomic/nolock.h b/include/atomic/nolock.h
index 10ac17884b6..cafd916981d 100644
--- a/include/atomic/nolock.h
+++ b/include/atomic/nolock.h
@@ -13,26 +13,27 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#if defined(__i386__) || defined(_M_IX86) || defined(HAVE_GCC_ATOMIC_BUILTINS)
-
-#ifdef MY_ATOMIC_MODE_DUMMY
-# define LOCK ""
-#else
-# define LOCK "lock"
-#endif
-
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
-#include "gcc_builtins.h"
-#elif __GNUC__
-#include "x86-gcc.h"
-#elif defined(_MSC_VER)
-#include "x86-msvc.h"
-#endif
+#if defined(__i386__) || defined(_MSC_VER) || \
+ defined(__x86_64__) || defined(HAVE_GCC_ATOMIC_BUILTINS)
+
+# ifdef MY_ATOMIC_MODE_DUMMY
+# define LOCK_prefix ""
+# else
+# define LOCK_prefix "lock"
+# endif
+
+# ifdef HAVE_GCC_ATOMIC_BUILTINS
+# include "gcc_builtins.h"
+# elif __GNUC__
+# include "x86-gcc.h"
+# elif defined(_MSC_VER)
+# include "generic-msvc.h"
+# endif
#endif
#ifdef make_atomic_cas_body
-typedef struct { } my_atomic_rwlock_t;
+typedef char my_atomic_rwlock_t __attribute__ ((unused));
#define my_atomic_rwlock_destroy(name)
#define my_atomic_rwlock_init(name)
#define my_atomic_rwlock_rdlock(name)
diff --git a/include/atomic/rwlock.h b/include/atomic/rwlock.h
index 18b77e93d80..57fbf35d18b 100644
--- a/include/atomic/rwlock.h
+++ b/include/atomic/rwlock.h
@@ -13,7 +13,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t;
+typedef struct {pthread_mutex_t rw;} my_atomic_rwlock_t;
+#define MY_ATOMIC_MODE_RWLOCKS 1
#ifdef MY_ATOMIC_MODE_DUMMY
/*
@@ -31,17 +32,22 @@ typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t;
#define my_atomic_rwlock_wrunlock(name)
#define MY_ATOMIC_MODE "dummy (non-atomic)"
#else
-#define my_atomic_rwlock_destroy(name) pthread_rwlock_destroy(& (name)->rw)
-#define my_atomic_rwlock_init(name) pthread_rwlock_init(& (name)->rw, 0)
-#define my_atomic_rwlock_rdlock(name) pthread_rwlock_rdlock(& (name)->rw)
-#define my_atomic_rwlock_wrlock(name) pthread_rwlock_wrlock(& (name)->rw)
-#define my_atomic_rwlock_rdunlock(name) pthread_rwlock_unlock(& (name)->rw)
-#define my_atomic_rwlock_wrunlock(name) pthread_rwlock_unlock(& (name)->rw)
-#define MY_ATOMIC_MODE "rwlocks"
+/*
+ we're using read-write lock macros but map them to mutex locks, and they're
+ faster. Still, having semantically rich API we can change the
+ underlying implementation, if necessary.
+*/
+#define my_atomic_rwlock_destroy(name) pthread_mutex_destroy(& (name)->rw)
+#define my_atomic_rwlock_init(name) pthread_mutex_init(& (name)->rw, 0)
+#define my_atomic_rwlock_rdlock(name) pthread_mutex_lock(& (name)->rw)
+#define my_atomic_rwlock_wrlock(name) pthread_mutex_lock(& (name)->rw)
+#define my_atomic_rwlock_rdunlock(name) pthread_mutex_unlock(& (name)->rw)
+#define my_atomic_rwlock_wrunlock(name) pthread_mutex_unlock(& (name)->rw)
+#define MY_ATOMIC_MODE "mutex"
#endif
#define make_atomic_add_body(S) int ## S sav; sav= *a; *a+= v; v=sav;
-#define make_atomic_swap_body(S) int ## S sav; sav= *a; *a= v; v=sav;
+#define make_atomic_fas_body(S) int ## S sav; sav= *a; *a= v; v=sav;
#define make_atomic_cas_body(S) if ((ret= (*a == *cmp))) *a= set; else *cmp=*a;
#define make_atomic_load_body(S) ret= *a;
#define make_atomic_store_body(S) *a= v;
diff --git a/include/atomic/x86-gcc.h b/include/atomic/x86-gcc.h
index d79dadbf05e..5a34bc22f9e 100644
--- a/include/atomic/x86-gcc.h
+++ b/include/atomic/x86-gcc.h
@@ -19,10 +19,18 @@
architectures support double-word (128-bit) cas.
*/
-#ifdef MY_ATOMIC_NO_XADD
-#define MY_ATOMIC_MODE "gcc-x86" LOCK "-no-xadd"
+#ifdef __x86_64__
+# ifdef MY_ATOMIC_NO_XADD
+# define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix "-no-xadd"
+# else
+# define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix
+# endif
#else
-#define MY_ATOMIC_MODE "gcc-x86" LOCK
+# ifdef MY_ATOMIC_NO_XADD
+# define MY_ATOMIC_MODE "gcc-x86" LOCK_prefix "-no-xadd"
+# else
+# define MY_ATOMIC_MODE "gcc-x86" LOCK_prefix
+# endif
#endif
/* fix -ansi errors while maintaining readability */
@@ -32,12 +40,12 @@
#ifndef MY_ATOMIC_NO_XADD
#define make_atomic_add_body(S) \
- asm volatile (LOCK "; xadd %0, %1;" : "+r" (v) , "+m" (*a))
+ asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a))
#endif
-#define make_atomic_swap_body(S) \
- asm volatile ("; xchg %0, %1;" : "+r" (v) , "+m" (*a))
+#define make_atomic_fas_body(S) \
+ asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a))
#define make_atomic_cas_body(S) \
- asm volatile (LOCK "; cmpxchg %3, %0; setz %2;" \
+ asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \
: "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set))
#ifdef MY_ATOMIC_MODE_DUMMY
@@ -46,13 +54,16 @@
#else
/*
Actually 32-bit reads/writes are always atomic on x86
- But we add LOCK here anyway to force memory barriers
+ But we add LOCK_prefix here anyway to force memory barriers
*/
#define make_atomic_load_body(S) \
ret=0; \
- asm volatile (LOCK "; cmpxchg %2, %0" \
+ asm volatile (LOCK_prefix "; cmpxchg %2, %0" \
: "+m" (*a), "+a" (ret): "r" (ret))
#define make_atomic_store_body(S) \
- asm volatile ("; xchg %0, %1;" : "+m" (*a) : "r" (v))
+ asm volatile ("; xchg %0, %1;" : "+m" (*a), "+r" (v))
#endif
+/* TODO test on intel whether the below helps. on AMD it makes no difference */
+//#define LF_BACKOFF ({asm volatile ("rep; nop"); 1; })
+
diff --git a/include/atomic/x86-msvc.h b/include/atomic/x86-msvc.h
deleted file mode 100644
index c4885bb8451..00000000000
--- a/include/atomic/x86-msvc.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Copyright (C) 2006 MySQL AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/*
- XXX 64-bit atomic operations can be implemented using
- cmpxchg8b, if necessary
-*/
-
-// Would it be better to use intrinsics ?
-// (InterlockedCompareExchange, InterlockedCompareExchange16
-// InterlockedExchangeAdd, InterlockedExchange)
-
-#ifndef _atomic_h_cleanup_
-#define _atomic_h_cleanup_ "atomic/x86-msvc.h"
-
-#define MY_ATOMIC_MODE "msvc-x86" LOCK
-
-#define make_atomic_add_body(S) \
- _asm { \
- _asm mov reg_ ## S, v \
- _asm LOCK xadd *a, reg_ ## S \
- _asm movzx v, reg_ ## S \
- }
-#define make_atomic_cas_body(S) \
- _asm { \
- _asm mov areg_ ## S, *cmp \
- _asm mov reg2_ ## S, set \
- _asm LOCK cmpxchg *a, reg2_ ## S \
- _asm mov *cmp, areg_ ## S \
- _asm setz al \
- _asm movzx ret, al \
- }
-#define make_atomic_swap_body(S) \
- _asm { \
- _asm mov reg_ ## S, v \
- _asm xchg *a, reg_ ## S \
- _asm mov v, reg_ ## S \
- }
-
-#ifdef MY_ATOMIC_MODE_DUMMY
-#define make_atomic_load_body(S) ret=*a
-#define make_atomic_store_body(S) *a=v
-#else
-/*
- Actually 32-bit reads/writes are always atomic on x86
- But we add LOCK here anyway to force memory barriers
-*/
-#define make_atomic_load_body(S) \
- _asm { \
- _asm mov areg_ ## S, 0 \
- _asm mov reg2_ ## S, areg_ ## S \
- _asm LOCK cmpxchg *a, reg2_ ## S \
- _asm mov ret, areg_ ## S \
- }
-#define make_atomic_store_body(S) \
- _asm { \
- _asm mov reg_ ## S, v \
- _asm xchg *a, reg_ ## S \
- }
-#endif
-
-#define reg_8 al
-#define reg_16 ax
-#define reg_32 eax
-#define areg_8 al
-#define areg_16 ax
-#define areg_32 eax
-#define reg2_8 bl
-#define reg2_16 bx
-#define reg2_32 ebx
-
-#else /* cleanup */
-
-#undef reg_8
-#undef reg_16
-#undef reg_32
-#undef areg_8
-#undef areg_16
-#undef areg_32
-#undef reg2_8
-#undef reg2_16
-#undef reg2_32
-#endif
-
diff --git a/include/config-win.h b/include/config-win.h
index ab0926af864..a85761ea389 100644
--- a/include/config-win.h
+++ b/include/config-win.h
@@ -32,6 +32,7 @@ functions */
#endif
#include <sys/locking.h>
+#include <sys/stat.h> /* chmod() constants*/
#include <winsock2.h>
#include <math.h> /* Because of rint() */
#include <fcntl.h>
@@ -93,6 +94,15 @@ functions */
#define S_IROTH S_IREAD /* for my_lib */
+/*
+ Constants used by chmod. Note, that group/others is ignored
+ - because unsupported by Windows due to different access control model.
+*/
+#define S_IRWXU S_IREAD|S_IWRITE
+#define S_IRWXG 0
+#define S_IRWXO 0
+typedef int mode_t;
+
#ifdef __BORLANDC__
#define FILE_BINARY O_BINARY /* my_fopen in binary mode */
#define O_TEMPORARY 0
diff --git a/include/ft_global.h b/include/ft_global.h
index 752371d6bc6..dba8a6e75e5 100644
--- a/include/ft_global.h
+++ b/include/ft_global.h
@@ -65,6 +65,17 @@ void ft_free_stopwords(void);
FT_INFO *ft_init_search(uint,void *, uint, uchar *, uint,CHARSET_INFO *, uchar *);
my_bool ft_boolean_check_syntax_string(const uchar *);
+/* Internal symbols for fulltext between maria and MyISAM */
+
+#define HA_FT_WTYPE HA_KEYTYPE_FLOAT
+#define HA_FT_WLEN 4
+#define FT_SEGS 2
+
+#define ft_sintXkorr(A) mi_sint4korr(A)
+#define ft_intXstore(T,A) mi_int4store(T,A)
+
+extern const HA_KEYSEG ft_keysegs[FT_SEGS];
+
#ifdef __cplusplus
}
#endif
diff --git a/include/hash.h b/include/hash.h
index f4b82454b81..f649b39a3cb 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -66,6 +66,7 @@ extern "C" {
typedef uchar *(*my_hash_get_key)(const uchar *,size_t*,my_bool);
typedef void (*my_hash_free_key)(void *);
+typedef my_bool (*my_hash_walk_action)(void *,void *);
typedef struct st_hash {
size_t key_offset,key_length; /* Length of key if const length */
@@ -104,6 +105,7 @@ my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key,
size_t old_key_length);
void my_hash_replace(HASH *hash, HASH_SEARCH_STATE *state, uchar *new_row);
my_bool my_hash_check(HASH *hash); /* Only in debug library */
+my_bool my_hash_iterate(HASH *hash, my_hash_walk_action action, void *argument);
#define my_hash_clear(H) bzero((char*) (H), sizeof(*(H)))
#define my_hash_inited(H) ((H)->array.buffer != 0)
diff --git a/include/keycache.h b/include/keycache.h
index a6005bae878..8c4ee4afe81 100644
--- a/include/keycache.h
+++ b/include/keycache.h
@@ -132,7 +132,8 @@ extern void end_key_cache(KEY_CACHE *keycache, my_bool cleanup);
/* Functions to handle multiple key caches */
extern my_bool multi_keycache_init(void);
extern void multi_keycache_free(void);
-extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length);
+extern KEY_CACHE *multi_key_cache_search(uchar *key, uint length,
+ KEY_CACHE *def);
extern my_bool multi_key_cache_set(const uchar *key, uint length,
KEY_CACHE *key_cache);
extern void multi_key_cache_change(KEY_CACHE *old_data,
diff --git a/include/lf.h b/include/lf.h
new file mode 100644
index 00000000000..11c06099399
--- /dev/null
+++ b/include/lf.h
@@ -0,0 +1,262 @@
+/* Copyright (C) 2007-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _lf_h
+#define _lf_h
+
+#include <my_atomic.h>
+
+/*
+ Helpers to define both func() and _func(), where
+ func() is a _func() protected by my_atomic_rwlock_wrlock()
+*/
+
+#define lock_wrap(f, t, proto_args, args, lock) \
+t _ ## f proto_args; \
+static inline t f proto_args \
+{ \
+ t ret; \
+ my_atomic_rwlock_wrlock(lock); \
+ ret= _ ## f args; \
+ my_atomic_rwlock_wrunlock(lock); \
+ return ret; \
+}
+
+#define lock_wrap_void(f, proto_args, args, lock) \
+void _ ## f proto_args; \
+static inline void f proto_args \
+{ \
+ my_atomic_rwlock_wrlock(lock); \
+ _ ## f args; \
+ my_atomic_rwlock_wrunlock(lock); \
+}
+
+#define nolock_wrap(f, t, proto_args, args) \
+t _ ## f proto_args; \
+static inline t f proto_args \
+{ \
+ return _ ## f args; \
+}
+
+#define nolock_wrap_void(f, proto_args, args) \
+void _ ## f proto_args; \
+static inline void f proto_args \
+{ \
+ _ ## f args; \
+}
+
+/*
+ wait-free dynamic array, see lf_dynarray.c
+
+ 4 levels of 256 elements each mean 4311810304 elements in an array - it
+ should be enough for a while
+*/
+#define LF_DYNARRAY_LEVEL_LENGTH 256
+#define LF_DYNARRAY_LEVELS 4
+
+typedef struct {
+ void * volatile level[LF_DYNARRAY_LEVELS];
+ uint size_of_element;
+ my_atomic_rwlock_t lock;
+} LF_DYNARRAY;
+
+typedef int (*lf_dynarray_func)(void *, void *);
+
+void lf_dynarray_init(LF_DYNARRAY *array, uint element_size);
+void lf_dynarray_destroy(LF_DYNARRAY *array);
+
+nolock_wrap(lf_dynarray_value, void *,
+ (LF_DYNARRAY *array, uint idx),
+ (array, idx))
+lock_wrap(lf_dynarray_lvalue, void *,
+ (LF_DYNARRAY *array, uint idx),
+ (array, idx),
+ &array->lock)
+nolock_wrap(lf_dynarray_iterate, int,
+ (LF_DYNARRAY *array, lf_dynarray_func func, void *arg),
+ (array, func, arg))
+
+/*
+ pin manager for memory allocator, lf_alloc-pin.c
+*/
+
+#define LF_PINBOX_PINS 4
+#define LF_PURGATORY_SIZE 10
+
+typedef void lf_pinbox_free_func(void *, void *, void*);
+
+typedef struct {
+ LF_DYNARRAY pinarray;
+ lf_pinbox_free_func *free_func;
+ void *free_func_arg;
+ uint free_ptr_offset;
+ uint32 volatile pinstack_top_ver; /* this is a versioned pointer */
+ uint32 volatile pins_in_array; /* number of elements in array */
+} LF_PINBOX;
+
+typedef struct {
+ void * volatile pin[LF_PINBOX_PINS];
+ LF_PINBOX *pinbox;
+ void **stack_ends_here;
+ void *purgatory;
+ uint32 purgatory_count;
+ uint32 volatile link;
+/* we want sizeof(LF_PINS) to be 128 to avoid false sharing */
+ char pad[128-sizeof(uint32)*2
+ -sizeof(LF_PINBOX *)
+ -sizeof(void*)
+ -sizeof(void *)*(LF_PINBOX_PINS+1)];
+} LF_PINS;
+
+/*
+ shortcut macros to do an atomic_wrlock on a structure that uses pins
+ (e.g. lf_hash).
+*/
+#define lf_rwlock_by_pins(PINS) \
+ my_atomic_rwlock_wrlock(&(PINS)->pinbox->pinarray.lock)
+#define lf_rwunlock_by_pins(PINS) \
+ my_atomic_rwlock_wrunlock(&(PINS)->pinbox->pinarray.lock)
+
+/*
+ compile-time assert, to require "no less than N" pins
+ it's enough if it'll fail on at least one compiler, so
+ we'll enable it on GCC only, which supports zero-length arrays.
+*/
+#if defined(__GNUC__) && defined(MY_LF_EXTRA_DEBUG)
+#define LF_REQUIRE_PINS(N) \
+ static const char require_pins[LF_PINBOX_PINS-N] \
+ __attribute__ ((unused)); \
+ static const int LF_NUM_PINS_IN_THIS_FILE= N;
+#define _lf_pin(PINS, PIN, ADDR) \
+ ( \
+ assert(PIN < LF_NUM_PINS_IN_THIS_FILE), \
+ my_atomic_storeptr(&(PINS)->pin[PIN], (ADDR)) \
+ )
+#else
+#define LF_REQUIRE_PINS(N)
+#define _lf_pin(PINS, PIN, ADDR) my_atomic_storeptr(&(PINS)->pin[PIN], (ADDR))
+#endif
+
+#define _lf_unpin(PINS, PIN) _lf_pin(PINS, PIN, NULL)
+#define lf_pin(PINS, PIN, ADDR) \
+ do { \
+ lf_rwlock_by_pins(PINS); \
+ _lf_pin(PINS, PIN, ADDR); \
+ lf_rwunlock_by_pins(PINS); \
+ } while (0)
+#define lf_unpin(PINS, PIN) lf_pin(PINS, PIN, NULL)
+#define _lf_assert_pin(PINS, PIN) assert((PINS)->pin[PIN] != 0)
+#define _lf_assert_unpin(PINS, PIN) assert((PINS)->pin[PIN] == 0)
+
+void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset,
+ lf_pinbox_free_func *free_func, void * free_func_arg);
+void lf_pinbox_destroy(LF_PINBOX *pinbox);
+
+lock_wrap(lf_pinbox_get_pins, LF_PINS *,
+ (LF_PINBOX *pinbox),
+ (pinbox),
+ &pinbox->pinarray.lock)
+lock_wrap_void(lf_pinbox_put_pins,
+ (LF_PINS *pins),
+ (pins),
+ &pins->pinbox->pinarray.lock)
+lock_wrap_void(lf_pinbox_free,
+ (LF_PINS *pins, void *addr),
+ (pins, addr),
+ &pins->pinbox->pinarray.lock)
+
+/*
+ memory allocator, lf_alloc-pin.c
+*/
+
+typedef struct st_lf_allocator {
+ LF_PINBOX pinbox;
+ uchar * volatile top;
+ uint element_size;
+ uint32 volatile mallocs;
+ void (*constructor)(uchar *); /* called, when an object is malloc()'ed */
+ void (*destructor)(uchar *); /* called, when an object is free()'d */
+} LF_ALLOCATOR;
+
+void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset);
+void lf_alloc_destroy(LF_ALLOCATOR *allocator);
+uint lf_alloc_pool_count(LF_ALLOCATOR *allocator);
+/*
+ shortcut macros to access underlying pinbox functions from an LF_ALLOCATOR
+ see _lf_pinbox_get_pins() and _lf_pinbox_put_pins()
+*/
+#define _lf_alloc_free(PINS, PTR) _lf_pinbox_free((PINS), (PTR))
+#define lf_alloc_free(PINS, PTR) lf_pinbox_free((PINS), (PTR))
+#define _lf_alloc_get_pins(A) _lf_pinbox_get_pins(&(A)->pinbox)
+#define lf_alloc_get_pins(A) lf_pinbox_get_pins(&(A)->pinbox)
+#define _lf_alloc_put_pins(PINS) _lf_pinbox_put_pins(PINS)
+#define lf_alloc_put_pins(PINS) lf_pinbox_put_pins(PINS)
+#define lf_alloc_direct_free(ALLOC, ADDR) my_free((uchar*)(ADDR), MYF(0))
+
+lock_wrap(lf_alloc_new, void *,
+ (LF_PINS *pins),
+ (pins),
+ &pins->pinbox->pinarray.lock)
+
+/*
+ extendible hash, lf_hash.c
+*/
+#include <hash.h>
+
+#define LF_HASH_UNIQUE 1
+
+/* lf_hash overhead per element (that is, sizeof(LF_SLIST) */
+extern const int LF_HASH_OVERHEAD;
+
+typedef struct {
+ LF_DYNARRAY array; /* hash itself */
+ LF_ALLOCATOR alloc; /* allocator for elements */
+ hash_get_key get_key; /* see HASH */
+ CHARSET_INFO *charset; /* see HASH */
+ uint key_offset, key_length; /* see HASH */
+ uint element_size; /* size of memcpy'ed area on insert */
+ uint flags; /* LF_HASH_UNIQUE, etc */
+ int32 volatile size; /* size of array */
+ int32 volatile count; /* number of elements in the hash */
+} LF_HASH;
+
+void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
+ uint key_offset, uint key_length, hash_get_key get_key,
+ CHARSET_INFO *charset);
+void lf_hash_destroy(LF_HASH *hash);
+int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data);
+void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen);
+int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen);
+/*
+ shortcut macros to access underlying pinbox functions from an LF_HASH
+ see _lf_pinbox_get_pins() and _lf_pinbox_put_pins()
+*/
+#define _lf_hash_get_pins(HASH) _lf_alloc_get_pins(&(HASH)->alloc)
+#define lf_hash_get_pins(HASH) lf_alloc_get_pins(&(HASH)->alloc)
+#define _lf_hash_put_pins(PINS) _lf_pinbox_put_pins(PINS)
+#define lf_hash_put_pins(PINS) lf_pinbox_put_pins(PINS)
+#define lf_hash_search_unpin(PINS) lf_unpin((PINS), 2)
+/*
+ cleanup
+*/
+
+#undef lock_wrap_void
+#undef lock_wrap
+#undef nolock_wrap_void
+#undef nolock_wrap
+
+#endif
+
diff --git a/include/m_string.h b/include/m_string.h
index c24bfd7aa6c..2fadd11af89 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -134,6 +134,12 @@ extern size_t my_bcmp(const uchar *s1,const uchar *s2,size_t len);
#define bzero_if_purify(A,B)
#endif /* HAVE_purify */
+#if defined(_lint) || defined(FORCE_INIT_OF_VARS)
+#define LINT_INIT_STRUCT(var) bzero(&var, sizeof(var)) /* No uninitialize-warning */
+#else
+#define LINT_INIT_STRUCT(var)
+#endif
+
#ifndef bmove512
extern void bmove512(uchar *dst,const uchar *src,size_t len);
#endif
@@ -266,4 +272,12 @@ typedef struct st_mysql_lex_string LEX_STRING;
#define USTRING_WITH_LEN(X) ((uchar*) X), ((size_t) (sizeof(X) - 1))
#define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1))
+/* A variant with const and unsigned */
+struct st_mysql_const_unsigned_lex_string
+{
+ const uchar *str;
+ size_t length;
+};
+typedef struct st_mysql_const_unsigned_lex_string LEX_CUSTRING;
+
#endif
diff --git a/include/maria.h b/include/maria.h
new file mode 100644
index 00000000000..c5bd8641c38
--- /dev/null
+++ b/include/maria.h
@@ -0,0 +1,476 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* This file should be included when using maria functions */
+
+#ifndef _maria_h
+#define _maria_h
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifndef _my_base_h
+#include <my_base.h>
+#endif
+#ifndef _m_ctype_h
+#include <m_ctype.h>
+#endif
+#include "../storage/maria/ma_pagecache.h"
+#include "my_handler.h"
+#include "ft_global.h"
+#include <myisamchk.h>
+#include <mysql/plugin.h>
+
+#define MARIA_CANNOT_ROLLBACK
+
+/*
+ Limit max keys according to HA_MAX_POSSIBLE_KEY; See myisamchk.h for details
+*/
+
+#if MAX_INDEXES > HA_MAX_POSSIBLE_KEY
+#define MARIA_MAX_KEY HA_MAX_POSSIBLE_KEY /* Max allowed keys */
+#else
+#define MARIA_MAX_KEY MAX_INDEXES /* Max allowed keys */
+#endif
+
+#define MARIA_NAME_IEXT ".MAI"
+#define MARIA_NAME_DEXT ".MAD"
+/* Max extra space to use when sorting keys */
+#define MARIA_MAX_TEMP_LENGTH 2*1024L*1024L*1024L
+/* Possible values for maria_block_size (must be power of 2) */
+#define MARIA_KEY_BLOCK_LENGTH 8192 /* default key block length */
+#define MARIA_MIN_KEY_BLOCK_LENGTH 1024 /* Min key block length */
+#define MARIA_MAX_KEY_BLOCK_LENGTH 32768
+/* Minimal page cache when we only want to be able to scan a table */
+#define MARIA_MIN_PAGE_CACHE_SIZE (8192L*16L)
+
+/*
+ In the following macros '_keyno_' is 0 .. keys-1.
+ If there can be more keys than bits in the key_map, the highest bit
+ is for all upper keys. They cannot be switched individually.
+ This means that clearing of high keys is ignored, setting one high key
+ sets all high keys.
+*/
+#define MARIA_KEYMAP_BITS (8 * SIZEOF_LONG_LONG)
+#define MARIA_KEYMAP_HIGH_MASK (ULL(1) << (MARIA_KEYMAP_BITS - 1))
+#define maria_get_mask_all_keys_active(_keys_) \
+ (((_keys_) < MARIA_KEYMAP_BITS) ? \
+ ((ULL(1) << (_keys_)) - ULL(1)) : \
+ (~ ULL(0)))
+#if MARIA_MAX_KEY > MARIA_KEYMAP_BITS
+#define maria_is_key_active(_keymap_,_keyno_) \
+ (((_keyno_) < MARIA_KEYMAP_BITS) ? \
+ test((_keymap_) & (ULL(1) << (_keyno_))) : \
+ test((_keymap_) & MARIA_KEYMAP_HIGH_MASK))
+#define maria_set_key_active(_keymap_,_keyno_) \
+ (_keymap_)|= (((_keyno_) < MARIA_KEYMAP_BITS) ? \
+ (ULL(1) << (_keyno_)) : \
+ MARIA_KEYMAP_HIGH_MASK)
+#define maria_clear_key_active(_keymap_,_keyno_) \
+ (_keymap_)&= (((_keyno_) < MARIA_KEYMAP_BITS) ? \
+ (~ (ULL(1) << (_keyno_))) : \
+ (~ (ULL(0))) /*ignore*/ )
+#else
+#define maria_is_key_active(_keymap_,_keyno_) \
+ test((_keymap_) & (ULL(1) << (_keyno_)))
+#define maria_set_key_active(_keymap_,_keyno_) \
+ (_keymap_)|= (ULL(1) << (_keyno_))
+#define maria_clear_key_active(_keymap_,_keyno_) \
+ (_keymap_)&= (~ (ULL(1) << (_keyno_)))
+#endif
+#define maria_is_any_key_active(_keymap_) \
+ test((_keymap_))
+#define maria_is_all_keys_active(_keymap_,_keys_) \
+ ((_keymap_) == maria_get_mask_all_keys_active(_keys_))
+#define maria_set_all_keys_active(_keymap_,_keys_) \
+ (_keymap_)= maria_get_mask_all_keys_active(_keys_)
+#define maria_clear_all_keys_active(_keymap_) \
+ (_keymap_)= 0
+#define maria_intersect_keys_active(_to_,_from_) \
+ (_to_)&= (_from_)
+#define maria_is_any_intersect_keys_active(_keymap1_,_keys_,_keymap2_) \
+ ((_keymap1_) & (_keymap2_) & \
+ maria_get_mask_all_keys_active(_keys_))
+#define maria_copy_keys_active(_to_,_maxkeys_,_from_) \
+ (_to_)= (maria_get_mask_all_keys_active(_maxkeys_) & \
+ (_from_))
+
+ /* Param to/from maria_info */
+
+typedef ulonglong MARIA_RECORD_POS;
+
+typedef struct st_maria_info
+{
+ ha_rows records; /* Records in database */
+ ha_rows deleted; /* Deleted records in database */
+ MARIA_RECORD_POS recpos; /* Pos for last used record */
+ MARIA_RECORD_POS newrecpos; /* Pos if we write new record */
+ MARIA_RECORD_POS dup_key_pos; /* Position to record with dup key */
+ my_off_t data_file_length; /* Length of data file */
+ my_off_t max_data_file_length, index_file_length;
+ my_off_t max_index_file_length, delete_length;
+ ulonglong auto_increment;
+ ulonglong key_map; /* Which keys are used */
+ time_t create_time; /* When table was created */
+ time_t check_time;
+ time_t update_time;
+ ulong record_offset;
+ double *rec_per_key; /* for sql optimizing */
+ ulong reclength; /* Recordlength */
+ ulong mean_reclength; /* Mean recordlength (if packed) */
+ char *data_file_name, *index_file_name;
+ enum data_file_type data_file_type;
+ uint keys; /* Number of keys in use */
+ uint options; /* HA_OPTION_... used */
+ uint reflength;
+ int errkey, /* With key was dupplicated on err */
+ sortkey; /* clustered by this key */
+ File filenr; /* (uniq) filenr for datafile */
+} MARIA_INFO;
+
+
+typedef struct st_maria_create_info
+{
+ const char *index_file_name, *data_file_name; /* If using symlinks */
+ ha_rows max_rows;
+ ha_rows reloc_rows;
+ ulonglong auto_increment;
+ ulonglong data_file_length;
+ ulonglong key_file_length;
+ /* Size of null bitmap at start of row */
+ uint null_bytes;
+ uint old_options;
+ enum data_file_type org_data_file_type;
+ uint8 language;
+ my_bool with_auto_increment, transactional;
+} MARIA_CREATE_INFO;
+
+struct st_maria_share;
+struct st_maria_handler; /* For referense */
+typedef struct st_maria_handler MARIA_HA;
+struct st_maria_s_param;
+struct st_maria_keydef;
+
+typedef struct st_maria_key /* Internal info about a key */
+{
+ uchar *data; /* Data for key */
+ struct st_maria_keydef *keyinfo; /* Definition for key */
+ uint data_length; /* Length of key data */
+ uint ref_length; /* record ref + transid */
+ uint32 flag; /* 0 or SEARCH_PART_KEY */
+} MARIA_KEY;
+
+
+typedef struct st_maria_keydef /* Key definition with open & info */
+{
+ struct st_maria_share *share; /* Pointer to base (set in open) */
+#ifdef THREAD
+ rw_lock_t root_lock; /* locking of tree */
+#endif
+ uint16 keysegs; /* Number of key-segment */
+ uint16 flag; /* NOSAME, PACK_USED */
+
+ uint8 key_alg; /* BTREE, RTREE */
+ uint8 key_nr; /* key number (auto) */
+ uint16 block_length; /* Length of keyblock (auto) */
+ uint16 underflow_block_length; /* When to execute underflow */
+ uint16 keylength; /* Tot length of keyparts (auto) */
+ uint16 minlength; /* min length of (packed) key (auto) */
+ uint16 maxlength; /* max length of (packed) key (auto) */
+ uint32 write_comp_flag; /* compare flag for write key (auto) */
+ uint32 version; /* For concurrent read/write */
+ uint32 ftparser_nr; /* distinct ftparser number */
+
+ HA_KEYSEG *seg, *end;
+ struct st_mysql_ftparser *parser; /* Fulltext [pre]parser */
+ int (*bin_search)(const MARIA_KEY *key, uchar *page,
+ uint32 comp_flag, uchar **ret_pos, uchar *buff,
+ my_bool *was_last_key);
+ uint (*get_key)(MARIA_KEY *key, uint page_flag, uint nod_flag,
+ uchar **page);
+ uchar *(*skip_key)(MARIA_KEY *key, uint page_flag, uint nod_flag,
+ uchar *page);
+ int (*pack_key)(const MARIA_KEY *key, uint nod_flag,
+ uchar *next_key, uchar *org_key, uchar *prev_key,
+ struct st_maria_s_param *s_temp);
+ void (*store_key)(struct st_maria_keydef *keyinfo, uchar *key_pos,
+ struct st_maria_s_param *s_temp);
+ my_bool (*ck_insert)(MARIA_HA *inf, MARIA_KEY *key);
+ int (*ck_delete)(MARIA_HA *inf, MARIA_KEY *klen);
+ MARIA_KEY *(*make_key)(MARIA_HA *info, MARIA_KEY *int_key, uint keynr,
+ uchar *key, const uchar *record,
+ MARIA_RECORD_POS filepos, ulonglong trid);
+} MARIA_KEYDEF;
+
+
+#define MARIA_UNIQUE_HASH_LENGTH 4
+
+typedef struct st_maria_unique_def /* Segment definition of unique */
+{
+ uint16 keysegs; /* Number of key-segment */
+ uint8 key; /* Mapped to which key */
+ uint8 null_are_equal;
+ HA_KEYSEG *seg, *end;
+} MARIA_UNIQUEDEF;
+
+typedef struct st_maria_decode_tree /* Decode huff-table */
+{
+ uint16 *table;
+ uint quick_table_bits;
+ uchar *intervalls;
+} MARIA_DECODE_TREE;
+
+
+struct st_maria_bit_buff;
+
+/*
+ Note that null markers should always be first in a row !
+ When creating a column, one should only specify:
+ type, length, null_bit and null_pos
+*/
+
+typedef struct st_maria_columndef /* column information */
+{
+ enum en_fieldtype type;
+ uint32 offset; /* Offset to position in row */
+ uint16 length; /* length of field */
+ uint16 column_nr;
+ /* Intern variable (size of total storage area for the row) */
+ uint16 fill_length;
+ uint16 null_pos; /* Position for null marker */
+ uint16 empty_pos; /* Position for empty marker */
+ uint8 null_bit; /* If column may be NULL */
+ /* Intern. Set if column should be zero packed (part of empty_bits) */
+ uint8 empty_bit;
+
+#ifndef NOT_PACKED_DATABASES
+ void(*unpack)(struct st_maria_columndef *rec,
+ struct st_maria_bit_buff *buff,
+ uchar *start, uchar *end);
+ enum en_fieldtype base_type;
+ uint space_length_bits, pack_type;
+ MARIA_DECODE_TREE *huff_tree;
+#endif
+} MARIA_COLUMNDEF;
+
+
+extern ulong maria_block_size, maria_checkpoint_frequency;
+extern ulong maria_concurrent_insert;
+extern my_bool maria_flush, maria_single_user, maria_page_checksums;
+extern my_bool maria_delay_key_write;
+extern my_off_t maria_max_temp_length;
+extern ulong maria_bulk_insert_tree_size, maria_data_pointer_size;
+extern PAGECACHE maria_pagecache_var, *maria_pagecache;
+extern MY_TMPDIR *maria_tmpdir;
+/*
+ This is used to check if a symlink points into the mysql data home,
+ which is normally forbidden as it can be used to get access to
+ not privileged data
+*/
+extern int (*maria_test_invalid_symlink)(const char *filename);
+
+ /* Prototypes for maria-functions */
+
+extern int maria_init(void);
+extern void maria_end(void);
+extern int maria_close(MARIA_HA *file);
+extern int maria_delete(MARIA_HA *file, const uchar *buff);
+extern MARIA_HA *maria_open(const char *name, int mode,
+ uint wait_if_locked);
+extern MARIA_HA *maria_clone(struct st_maria_share *share, int mode);
+extern int maria_panic(enum ha_panic_function function);
+extern int maria_rfirst(MARIA_HA *file, uchar *buf, int inx);
+extern int maria_rkey(MARIA_HA *file, uchar *buf, int inx,
+ const uchar *key, key_part_map keypart_map,
+ enum ha_rkey_function search_flag);
+extern int maria_rlast(MARIA_HA *file, uchar *buf, int inx);
+extern int maria_rnext(MARIA_HA *file, uchar *buf, int inx);
+extern int maria_rnext_same(MARIA_HA *info, uchar *buf);
+extern int maria_rprev(MARIA_HA *file, uchar *buf, int inx);
+extern int maria_rrnd(MARIA_HA *file, uchar *buf,
+ MARIA_RECORD_POS pos);
+extern int maria_scan_init(MARIA_HA *file);
+extern int maria_scan(MARIA_HA *file, uchar *buf);
+extern void maria_scan_end(MARIA_HA *file);
+extern int maria_rsame(MARIA_HA *file, uchar *record, int inx);
+extern int maria_rsame_with_pos(MARIA_HA *file, uchar *record,
+ int inx, MARIA_RECORD_POS pos);
+extern int maria_update(MARIA_HA *file, const uchar *old,
+ uchar *new_record);
+extern int maria_write(MARIA_HA *file, uchar *buff);
+extern MARIA_RECORD_POS maria_position(MARIA_HA *file);
+extern int maria_status(MARIA_HA *info, MARIA_INFO *x, uint flag);
+extern int maria_lock_database(MARIA_HA *file, int lock_type);
+extern int maria_create(const char *name, enum data_file_type record_type,
+ uint keys, MARIA_KEYDEF *keydef,
+ uint columns, MARIA_COLUMNDEF *columndef,
+ uint uniques, MARIA_UNIQUEDEF *uniquedef,
+ MARIA_CREATE_INFO *create_info, uint flags);
+extern int maria_delete_table(const char *name);
+extern int maria_rename(const char *from, const char *to);
+extern int maria_extra(MARIA_HA *file,
+ enum ha_extra_function function, void *extra_arg);
+extern int maria_reset(MARIA_HA *file);
+extern ha_rows maria_records_in_range(MARIA_HA *info, int inx,
+ key_range *min_key, key_range *max_key);
+extern int maria_is_changed(MARIA_HA *info);
+extern int maria_delete_all_rows(MARIA_HA *info);
+extern uint maria_get_pointer_length(ulonglong file_length, uint def);
+extern int maria_commit(MARIA_HA *info);
+extern int maria_begin(MARIA_HA *info);
+extern void maria_disable_logging(MARIA_HA *info);
+extern void maria_enable_logging(MARIA_HA *info);
+
+/* this is used to pass to mysql_mariachk_table */
+
+#define MARIA_CHK_REPAIR 1 /* equivalent to mariachk -r */
+#define MARIA_CHK_VERIFY 2 /* Verify, run repair if failure */
+
+typedef uint maria_bit_type;
+
+typedef struct st_maria_bit_buff
+{ /* Used for packing of record */
+ maria_bit_type current_byte;
+ uint bits;
+ uchar *pos, *end, *blob_pos, *blob_end;
+ uint error;
+} MARIA_BIT_BUFF;
+
+
+typedef struct st_maria_sort_info
+{
+#ifdef THREAD
+ /* sync things */
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+#endif
+ MARIA_HA *info, *new_info;
+ HA_CHECK *param;
+ char *buff;
+ SORT_KEY_BLOCKS *key_block, *key_block_end;
+ SORT_FT_BUF *ft_buf;
+ my_off_t filelength, dupp, buff_length;
+ pgcache_page_no_t page;
+ ha_rows max_records;
+ uint current_key, total_keys;
+ uint got_error, threads_running;
+ myf myf_rw;
+ enum data_file_type new_data_file_type, org_data_file_type;
+} MARIA_SORT_INFO;
+
+typedef struct st_maria_sort_param
+{
+ pthread_t thr;
+ IO_CACHE read_cache, tempfile, tempfile_for_exceptions;
+ DYNAMIC_ARRAY buffpek;
+ MARIA_BIT_BUFF bit_buff; /* For parallel repair of packrec. */
+
+ MARIA_KEYDEF *keyinfo;
+ MARIA_SORT_INFO *sort_info;
+ HA_KEYSEG *seg;
+ uchar **sort_keys;
+ uchar *rec_buff;
+ void *wordlist, *wordptr;
+ MEM_ROOT wordroot;
+ uchar *record;
+ MY_TMPDIR *tmpdir;
+
+ /*
+ The next two are used to collect statistics, see maria_update_key_parts for
+ description.
+ */
+ ulonglong unique[HA_MAX_KEY_SEG+1];
+ ulonglong notnull[HA_MAX_KEY_SEG+1];
+
+ MARIA_RECORD_POS pos,max_pos,filepos,start_recpos, current_filepos;
+ uint key, key_length,real_key_length,sortbuff_size;
+ uint maxbuffers, keys, find_length, sort_keys_length;
+ my_bool fix_datafile, master;
+ my_bool calc_checksum; /* calculate table checksum */
+ size_t rec_buff_size;
+
+ int (*key_cmp)(struct st_maria_sort_param *, const void *, const void *);
+ int (*key_read)(struct st_maria_sort_param *, uchar *);
+ int (*key_write)(struct st_maria_sort_param *, const uchar *);
+ void (*lock_in_memory)(HA_CHECK *);
+ int (*write_keys)(struct st_maria_sort_param *, register uchar **,
+ uint , struct st_buffpek *, IO_CACHE *);
+ uint (*read_to_buffer)(IO_CACHE *,struct st_buffpek *, uint);
+ int (*write_key)(struct st_maria_sort_param *, IO_CACHE *,uchar *,
+ uint, uint);
+} MARIA_SORT_PARAM;
+
+
+/* functions in maria_check */
+void maria_chk_init(HA_CHECK *param);
+void maria_chk_init_for_check(HA_CHECK *param, MARIA_HA *info);
+int maria_chk_status(HA_CHECK *param, MARIA_HA *info);
+int maria_chk_del(HA_CHECK *param, MARIA_HA *info, ulonglong test_flag);
+int maria_chk_size(HA_CHECK *param, MARIA_HA *info);
+int maria_chk_key(HA_CHECK *param, MARIA_HA *info);
+int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend);
+int maria_repair(HA_CHECK *param, MARIA_HA *info, char * name, my_bool);
+int maria_sort_index(HA_CHECK *param, MARIA_HA *info, char * name);
+int maria_zerofill(HA_CHECK *param, MARIA_HA *info, const char *name);
+int maria_repair_by_sort(HA_CHECK *param, MARIA_HA *info,
+ const char *name, my_bool rep_quick);
+int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
+ const char *name, my_bool rep_quick);
+int maria_change_to_newfile(const char *filename, const char *old_ext,
+ const char *new_ext, myf myflags);
+void maria_lock_memory(HA_CHECK *param);
+int maria_update_state_info(HA_CHECK *param, MARIA_HA *info, uint update);
+void maria_update_key_parts(MARIA_KEYDEF *keyinfo, double *rec_per_key_part,
+ ulonglong *unique, ulonglong *notnull,
+ ulonglong records);
+int maria_filecopy(HA_CHECK *param, File to, File from, my_off_t start,
+ my_off_t length, const char *type);
+int maria_movepoint(MARIA_HA *info, uchar *record, my_off_t oldpos,
+ my_off_t newpos, uint prot_key);
+int maria_write_data_suffix(MARIA_SORT_INFO *sort_info, my_bool fix_datafile);
+int maria_test_if_almost_full(MARIA_HA *info);
+int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename);
+int maria_disable_indexes(MARIA_HA *info);
+int maria_enable_indexes(MARIA_HA *info);
+int maria_indexes_are_disabled(MARIA_HA *info);
+void maria_disable_non_unique_index(MARIA_HA *info, ha_rows rows);
+my_bool maria_test_if_sort_rep(MARIA_HA *info, ha_rows rows, ulonglong key_map,
+ my_bool force);
+
+int maria_init_bulk_insert(MARIA_HA *info, ulong cache_size, ha_rows rows);
+void maria_flush_bulk_insert(MARIA_HA *info, uint inx);
+void maria_end_bulk_insert(MARIA_HA *info, my_bool table_will_be_deleted);
+int maria_assign_to_pagecache(MARIA_HA *info, ulonglong key_map,
+ PAGECACHE *key_cache);
+void maria_change_pagecache(PAGECACHE *old_key_cache,
+ PAGECACHE *new_key_cache);
+int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves);
+void maria_versioning(MARIA_HA *info, my_bool versioning);
+void maria_ignore_trids(MARIA_HA *info);
+
+/* fulltext functions */
+FT_INFO *maria_ft_init_search(uint,void *, uint, uchar *, uint,
+ CHARSET_INFO *, uchar *);
+
+/* 'Almost-internal' Maria functions */
+
+void _ma_update_auto_increment_key(HA_CHECK *param, MARIA_HA *info,
+ my_bool repair);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/my_alloc.h b/include/my_alloc.h
index 93b7438a1df..6ade4d08980 100644
--- a/include/my_alloc.h
+++ b/include/my_alloc.h
@@ -26,8 +26,8 @@
typedef struct st_used_mem
{ /* struct for once_alloc (block) */
struct st_used_mem *next; /* Next block in use */
- unsigned int left; /* memory left in block */
- unsigned int size; /* size of block */
+ size_t left; /* memory left in block */
+ size_t size; /* size of block */
} USED_MEM;
diff --git a/include/my_atomic.h b/include/my_atomic.h
index ed439e5fe87..40d762f8ff0 100644
--- a/include/my_atomic.h
+++ b/include/my_atomic.h
@@ -13,6 +13,42 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/*
+ This header defines five atomic operations:
+
+ my_atomic_add#(&var, what)
+ add 'what' to *var, and return the old value of *var
+
+ my_atomic_fas#(&var, what)
+ 'Fetch And Store'
+ store 'what' in *var, and return the old value of *var
+
+ my_atomic_cas#(&var, &old, new)
+ 'Compare And Swap'
+ if *var is equal to *old, then store 'new' in *var, and return TRUE
+ otherwise store *var in *old, and return FALSE
+
+ my_atomic_load#(&var)
+ return *var
+
+ my_atomic_store#(&var, what)
+ store 'what' in *var
+
+ '#' is substituted by a size suffix - 8, 16, 32, or ptr
+ (e.g. my_atomic_add8, my_atomic_fas32, my_atomic_casptr).
+
+ NOTE This operations are not always atomic, so they always must be
+ enclosed in my_atomic_rwlock_rdlock(lock)/my_atomic_rwlock_rdunlock(lock)
+ or my_atomic_rwlock_wrlock(lock)/my_atomic_rwlock_wrunlock(lock).
+ Hint: if a code block makes intensive use of atomic ops, it make sense
+ to take/release rwlock once for the whole block, not for every statement.
+
+ On architectures where these operations are really atomic, rwlocks will
+ be optimized away.
+ 8- and 16-bit atomics aren't implemented for windows (see generic-msvc.h),
+ but can be added, if necessary.
+*/
+
#ifndef my_atomic_rwlock_init
#define intptr void *
@@ -22,116 +58,198 @@
#endif
#ifndef make_atomic_cas_body
+/* nolock.h was not able to generate even a CAS function, fall back */
#include "atomic/rwlock.h"
-#endif
-
+#else
+/* define missing functions by using the already generated ones */
#ifndef make_atomic_add_body
-#define make_atomic_add_body(S) \
+#define make_atomic_add_body(S) \
int ## S tmp=*a; \
while (!my_atomic_cas ## S(a, &tmp, tmp+v)); \
v=tmp;
#endif
+#ifndef make_atomic_fas_body
+#define make_atomic_fas_body(S) \
+ int ## S tmp=*a; \
+ while (!my_atomic_cas ## S(a, &tmp, v)); \
+ v=tmp;
+#endif
+#ifndef make_atomic_load_body
+#define make_atomic_load_body(S) \
+ ret= 0; /* avoid compiler warning */ \
+ (void)(my_atomic_cas ## S(a, &ret, ret));
+#endif
+#ifndef make_atomic_store_body
+#define make_atomic_store_body(S) \
+ (void)(my_atomic_fas ## S (a, v));
+#endif
+#endif
+
+/*
+ transparent_union doesn't work in g++
+ Bug ?
+
+ Darwin's gcc doesn't want to put pointers in a transparent_union
+ when built with -arch ppc64. Complains:
+ warning: 'transparent_union' attribute ignored
+*/
+#if defined(__GNUC__) && !defined(__cplusplus) && \
+ ! (defined(__APPLE__) && defined(_ARCH_PPC64))
+/*
+ we want to be able to use my_atomic_xxx functions with
+ both signed and unsigned integers. But gcc will issue a warning
+ "passing arg N of `my_atomic_XXX' as [un]signed due to prototype"
+ if the signedness of the argument doesn't match the prototype, or
+ "pointer targets in passing argument N of my_atomic_XXX differ in signedness"
+ if int* is used where uint* is expected (or vice versa).
+ Let's shut these warnings up
+*/
+#define make_transparent_unions(S) \
+ typedef union { \
+ int ## S i; \
+ uint ## S u; \
+ } U_ ## S __attribute__ ((transparent_union)); \
+ typedef union { \
+ int ## S volatile *i; \
+ uint ## S volatile *u; \
+ } Uv_ ## S __attribute__ ((transparent_union));
+#define uintptr intptr
+make_transparent_unions(8)
+make_transparent_unions(16)
+make_transparent_unions(32)
+make_transparent_unions(ptr)
+#undef uintptr
+#undef make_transparent_unions
+#define a U_a.i
+#define cmp U_cmp.i
+#define v U_v.i
+#define set U_set.i
+#else
+#define U_8 int8
+#define U_16 int16
+#define U_32 int32
+#define U_ptr intptr
+#define Uv_8 int8
+#define Uv_16 int16
+#define Uv_32 int32
+#define Uv_ptr intptr
+#define U_a volatile *a
+#define U_cmp *cmp
+#define U_v v
+#define U_set set
+#endif /* __GCC__ transparent_union magic */
#ifdef HAVE_INLINE
-#define make_atomic_add(S) \
-STATIC_INLINE int ## S my_atomic_add ## S( \
- int ## S volatile *a, int ## S v) \
-{ \
- make_atomic_add_body(S); \
- return v; \
+#define make_atomic_cas(S) \
+STATIC_INLINE int my_atomic_cas ## S(Uv_ ## S U_a, \
+ Uv_ ## S U_cmp, U_ ## S U_set) \
+{ \
+ int8 ret; \
+ make_atomic_cas_body(S); \
+ return ret; \
}
-#define make_atomic_swap(S) \
-STATIC_INLINE int ## S my_atomic_swap ## S( \
- int ## S volatile *a, int ## S v) \
-{ \
- make_atomic_swap_body(S); \
- return v; \
+#define make_atomic_add(S) \
+STATIC_INLINE int ## S my_atomic_add ## S( \
+ Uv_ ## S U_a, U_ ## S U_v) \
+{ \
+ make_atomic_add_body(S); \
+ return v; \
}
-#define make_atomic_cas(S) \
-STATIC_INLINE int my_atomic_cas ## S(int ## S volatile *a, \
- int ## S *cmp, int ## S set) \
-{ \
- int8 ret; \
- make_atomic_cas_body(S); \
- return ret; \
+#define make_atomic_fas(S) \
+STATIC_INLINE int ## S my_atomic_fas ## S( \
+ Uv_ ## S U_a, U_ ## S U_v) \
+{ \
+ make_atomic_fas_body(S); \
+ return v; \
}
-#define make_atomic_load(S) \
-STATIC_INLINE int ## S my_atomic_load ## S(int ## S volatile *a) \
-{ \
- int ## S ret; \
- make_atomic_load_body(S); \
- return ret; \
+#define make_atomic_load(S) \
+STATIC_INLINE int ## S my_atomic_load ## S(Uv_ ## S U_a) \
+{ \
+ int ## S ret; \
+ make_atomic_load_body(S); \
+ return ret; \
}
-#define make_atomic_store(S) \
-STATIC_INLINE void my_atomic_store ## S( \
- int ## S volatile *a, int ## S v) \
-{ \
- make_atomic_store_body(S); \
+#define make_atomic_store(S) \
+STATIC_INLINE void my_atomic_store ## S( \
+ Uv_ ## S U_a, U_ ## S U_v) \
+{ \
+ make_atomic_store_body(S); \
}
#else /* no inline functions */
-#define make_atomic_add(S) \
-extern int ## S my_atomic_add ## S(int ## S volatile *a, int ## S v);
+#define make_atomic_add(S) \
+extern int ## S my_atomic_add ## S(Uv_ ## S U_a, U_ ## S U_v);
-#define make_atomic_swap(S) \
-extern int ## S my_atomic_swap ## S(int ## S volatile *a, int ## S v);
+#define make_atomic_fas(S) \
+extern int ## S my_atomic_fas ## S(Uv_ ## S U_a, U_ ## S U_v);
-#define make_atomic_cas(S) \
-extern int my_atomic_cas ## S(int ## S volatile *a, int ## S *cmp, int ## S set);
+#define make_atomic_cas(S) \
+extern int my_atomic_cas ## S(Uv_ ## S U_a, Uv_ ## S U_cmp, U_ ## S U_set);
-#define make_atomic_load(S) \
-extern int ## S my_atomic_load ## S(int ## S volatile *a);
+#define make_atomic_load(S) \
+extern int ## S my_atomic_load ## S(Uv_ ## S U_a);
-#define make_atomic_store(S) \
-extern void my_atomic_store ## S(int ## S volatile *a, int ## S v);
+#define make_atomic_store(S) \
+extern void my_atomic_store ## S(Uv_ ## S U_a, U_ ## S U_v);
#endif
-make_atomic_cas( 8)
-make_atomic_cas(16)
make_atomic_cas(32)
make_atomic_cas(ptr)
-make_atomic_add( 8)
-make_atomic_add(16)
make_atomic_add(32)
-make_atomic_load( 8)
-make_atomic_load(16)
make_atomic_load(32)
make_atomic_load(ptr)
-make_atomic_store( 8)
-make_atomic_store(16)
+make_atomic_fas(32)
+make_atomic_fas(ptr)
+
make_atomic_store(32)
make_atomic_store(ptr)
-make_atomic_swap( 8)
-make_atomic_swap(16)
-make_atomic_swap(32)
-make_atomic_swap(ptr)
+#ifdef _atomic_h_cleanup_
+#include _atomic_h_cleanup_
+#undef _atomic_h_cleanup_
+#endif
+#undef U_8
+#undef U_16
+#undef U_32
+#undef U_ptr
+#undef a
+#undef cmp
+#undef v
+#undef set
+#undef U_a
+#undef U_cmp
+#undef U_v
+#undef U_set
#undef make_atomic_add
#undef make_atomic_cas
#undef make_atomic_load
#undef make_atomic_store
-#undef make_atomic_swap
+#undef make_atomic_fas
#undef make_atomic_add_body
#undef make_atomic_cas_body
#undef make_atomic_load_body
#undef make_atomic_store_body
-#undef make_atomic_swap_body
+#undef make_atomic_fas_body
#undef intptr
-#ifdef _atomic_h_cleanup_
-#include _atomic_h_cleanup_
-#undef _atomic_h_cleanup_
+/*
+ the macro below defines (as an expression) the code that
+ will be run in spin-loops. Intel manuals recummend to have PAUSE there.
+ It is expected to be defined in include/atomic/ *.h files
+*/
+#ifndef LF_BACKOFF
+#define LF_BACKOFF (1)
#endif
#define MY_ATOMIC_OK 0
diff --git a/include/my_base.h b/include/my_base.h
index 22f518b0f9a..a2079f6745c 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -195,7 +195,9 @@ enum ha_extra_function {
begin and end of a statement.
*/
HA_EXTRA_ATTACH_CHILDREN,
- HA_EXTRA_DETACH_CHILDREN
+ HA_EXTRA_DETACH_CHILDREN,
+ /* Inform handler we will force a close as part of flush */
+ HA_EXTRA_PREPARE_FOR_FORCED_CLOSE
};
/* Compatible option, to be deleted in 6.0 */
@@ -238,7 +240,10 @@ enum ha_base_keytype {
#define HA_MAX_KEYTYPE 31 /* Must be log2-1 */
- /* These flags kan be OR:ed to key-flag */
+/*
+ These flags kan be OR:ed to key-flag
+ Note that these can only be up to 16 bits!
+*/
#define HA_NOSAME 1 /* Set if not dupplicated records */
#define HA_PACK_KEY 2 /* Pack string key to previous key */
@@ -249,11 +254,13 @@ enum ha_base_keytype {
#define HA_SPATIAL 1024 /* For spatial search */
#define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */
#define HA_GENERATED_KEY 8192 /* Automaticly generated key */
+#define HA_RTREE_INDEX 16384 /* For RTREE search */
/* The combination of the above can be used for key type comparison. */
#define HA_KEYFLAG_MASK (HA_NOSAME | HA_PACK_KEY | HA_AUTO_KEY | \
HA_BINARY_PACK_KEY | HA_FULLTEXT | HA_UNIQUE_CHECK | \
- HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY)
+ HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY | \
+ HA_RTREE_INDEX)
#define HA_KEY_HAS_PART_KEY_SEG 65536 /* Key contains partial segments */
@@ -307,8 +314,10 @@ enum ha_base_keytype {
#define HA_OPTION_RELIES_ON_SQL_LAYER 512
#define HA_OPTION_NULL_FIELDS 1024
#define HA_OPTION_PAGE_CHECKSUM 2048
-#define HA_OPTION_TEMP_COMPRESS_RECORD ((uint) 16384) /* set by isamchk */
-#define HA_OPTION_READ_ONLY_DATA ((uint) 32768) /* Set by isamchk */
+#define HA_OPTION_TEMP_COMPRESS_RECORD (1L << 15) /* set by isamchk */
+#define HA_OPTION_READ_ONLY_DATA (1L << 16) /* Set by isamchk */
+#define HA_OPTION_NO_CHECKSUM (1L << 17)
+#define HA_OPTION_NO_DELAY_KEY_WRITE (1L << 18)
/* Bits in flag to create() */
@@ -431,17 +440,17 @@ enum ha_base_keytype {
/* row not actually updated: new values same as the old values */
#define HA_ERR_RECORD_IS_THE_SAME 169
/* It is not possible to log this statement */
-#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this
- statement */
-#define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to
- illegal data being read */
+#define HA_ERR_LOGGING_IMPOSSIBLE 170
+/* The event was corrupt, leading to illegal data being read */
+#define HA_ERR_CORRUPT_EVENT 171
#define HA_ERR_NEW_FILE 172 /* New file format */
-#define HA_ERR_ROWS_EVENT_APPLY 173 /* The event could not be processed
- no other hanlder error happened */
+/* The event could not be processed no other handler error happened */
+#define HA_ERR_ROWS_EVENT_APPLY 173
#define HA_ERR_INITIALIZATION 174 /* Error during initialization */
#define HA_ERR_FILE_TOO_SHORT 175 /* File too short */
#define HA_ERR_WRONG_CRC 176 /* Wrong CRC on page */
-#define HA_ERR_LAST 176 /* Copy of last error nr */
+#define HA_ERR_ROW_NOT_VISIBLE 177
+#define HA_ERR_LAST 177 /* Copy of last error nr */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
@@ -474,6 +483,14 @@ typedef ulong key_part_map;
#define MBR_DATA 16384
#define SEARCH_NULL_ARE_EQUAL 32768 /* NULL in keys are equal */
#define SEARCH_NULL_ARE_NOT_EQUAL 65536 /* NULL in keys are not equal */
+/* Use this when inserting a key in position order */
+#define SEARCH_INSERT SEARCH_NULL_ARE_NOT_EQUAL*2
+/* Only part of the key is specified while reading */
+#define SEARCH_PART_KEY SEARCH_INSERT*2
+/* Used when user key (key 2) contains transaction id's */
+#define SEARCH_USER_KEY_HAS_TRANSID SEARCH_PART_KEY*2
+/* Used when page key (key 1) contains transaction id's */
+#define SEARCH_PAGE_KEY_HAS_TRANSID SEARCH_USER_KEY_HAS_TRANSID*2
/* bits in opt_flag */
#define QUICK_USED 1
diff --git a/include/my_dbug.h b/include/my_dbug.h
index a77e439b5db..4e883563759 100644
--- a/include/my_dbug.h
+++ b/include/my_dbug.h
@@ -16,58 +16,62 @@
#ifndef _dbug_h
#define _dbug_h
-#ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
#endif
#if !defined(DBUG_OFF) && !defined(_lint)
-struct _db_code_state_;
-extern int _db_keyword_(struct _db_code_state_ *cs, const char *keyword);
-extern int _db_strict_keyword_(const char *keyword);
+
+struct _db_stack_frame_ {
+ const char *func; /* function name of the previous stack frame */
+ const char *file; /* filename of the function of previous frame */
+ uint level; /* this nesting level, highest bit enables tracing */
+ struct _db_stack_frame_ *prev; /* pointer to the previous frame */
+};
+
+struct _db_code_state_;
+extern my_bool _dbug_on_;
+extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int);
extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len);
extern int _db_explain_init_(char *buf, size_t len);
-extern void _db_setjmp_(void);
-extern void _db_longjmp_(void);
+extern void _db_setjmp_(void);
+extern void _db_longjmp_(void);
extern void _db_process_(const char *name);
-extern void _db_push_(const char *control);
-extern void _db_pop_(void);
-extern void _db_set_(struct _db_code_state_ *cs, const char *control);
+extern void _db_push_(const char *control);
+extern void _db_pop_(void);
+extern void _db_set_(const char *control);
extern void _db_set_init_(const char *control);
-extern void _db_enter_(const char *_func_,const char *_file_,uint _line_,
- const char **_sfunc_,const char **_sfile_,
- uint *_slevel_, char ***);
-extern void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_,
- uint *_slevel_);
-extern void _db_pargs_(uint _line_,const char *keyword);
-extern void _db_doprnt_ _VARARGS((const char *format,...))
+extern void _db_enter_(const char *_func_, const char *_file_, uint _line_,
+ struct _db_stack_frame_ *_stack_frame_);
+extern void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_);
+extern void _db_pargs_(uint _line_,const char *keyword);
+extern void _db_doprnt_ _VARARGS((const char *format,...))
ATTRIBUTE_FORMAT(printf, 1, 2);
-extern void _db_dump_(uint _line_,const char *keyword,
+extern void _db_dump_(uint _line_,const char *keyword,
const unsigned char *memory, size_t length);
-extern void _db_end_(void);
-extern void _db_lock_file_(void);
-extern void _db_unlock_file_(void);
-extern FILE *_db_fp_(void);
+extern void _db_end_(void);
+extern void _db_lock_file_(void);
+extern void _db_unlock_file_(void);
+extern FILE *_db_fp_(void);
+extern void _db_flush_();
-#define DBUG_ENTER(a) const char *_db_func_, *_db_file_; uint _db_level_; \
- char **_db_framep_; \
- _db_enter_ (a,__FILE__,__LINE__,&_db_func_,&_db_file_,&_db_level_, \
- &_db_framep_)
-#define DBUG_LEAVE \
- _db_return_ (__LINE__, &_db_func_, &_db_file_, &_db_level_)
+#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \
+ _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
+#define DBUG_LEAVE _db_return_ (__LINE__, &_db_stack_frame_)
#define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0)
#define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0)
#define DBUG_EXECUTE(keyword,a1) \
- do {if (_db_keyword_(0, (keyword))) { a1 }} while(0)
+ do {if (_db_keyword_(0, (keyword), 0)) { a1 }} while(0)
#define DBUG_EXECUTE_IF(keyword,a1) \
- do {if (_db_strict_keyword_ (keyword)) { a1 } } while(0)
+ do {if (_db_keyword_(0, (keyword), 1)) { a1 }} while(0)
#define DBUG_EVALUATE(keyword,a1,a2) \
- (_db_keyword_(0,(keyword)) ? (a1) : (a2))
+ (_db_keyword_(0,(keyword), 0) ? (a1) : (a2))
#define DBUG_EVALUATE_IF(keyword,a1,a2) \
- (_db_strict_keyword_((keyword)) ? (a1) : (a2))
+ (_db_keyword_(0,(keyword), 1) ? (a1) : (a2))
#define DBUG_PRINT(keyword,arglist) \
do {_db_pargs_(__LINE__,keyword); _db_doprnt_ arglist;} while(0)
#define DBUG_PUSH(a1) _db_push_ (a1)
#define DBUG_POP() _db_pop_ ()
-#define DBUG_SET(a1) _db_set_ (0, (a1))
+#define DBUG_SET(a1) _db_set_ (a1)
#define DBUG_SET_INITIAL(a1) _db_set_init_ (a1)
#define DBUG_PROCESS(a1) _db_process_(a1)
#define DBUG_FILE _db_fp_()
@@ -80,36 +84,55 @@ extern FILE *_db_fp_(void);
#define DBUG_ASSERT(A) assert(A)
#define DBUG_EXPLAIN(buf,len) _db_explain_(0, (buf),(len))
#define DBUG_EXPLAIN_INITIAL(buf,len) _db_explain_init_((buf),(len))
+#define DEBUGGER_OFF do { _dbug_on_= 0; } while(0)
+#define DEBUGGER_ON do { _dbug_on_= 1; } while(0)
#define IF_DBUG(A) A
-#else /* No debugger */
+#ifndef __WIN__
+#define DBUG_ABORT() (_db_flush_(), abort())
+#else
+/*
+ Avoid popup with abort/retry/ignore buttons. When BUG#31745 is fixed we can
+ call abort() instead of _exit(3) (now it would cause a "test signal" popup).
+*/
+#include <crtdbg.h>
+#define DBUG_ABORT() (_db_flush_(),\
+ (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE),\
+ (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\
+ _exit(3))
+#endif
+
+#else /* No debugger */
#define DBUG_ENTER(a1)
#define DBUG_LEAVE
-#define DBUG_RETURN(a1) do { return(a1); } while(0)
-#define DBUG_VOID_RETURN do { return; } while(0)
-#define DBUG_EXECUTE(keyword,a1) do { } while(0)
-#define DBUG_EXECUTE_IF(keyword,a1) do { } while(0)
+#define DBUG_RETURN(a1) do { return(a1); } while(0)
+#define DBUG_VOID_RETURN do { return; } while(0)
+#define DBUG_EXECUTE(keyword,a1) do { } while(0)
+#define DBUG_EXECUTE_IF(keyword,a1) do { } while(0)
#define DBUG_EVALUATE(keyword,a1,a2) (a2)
#define DBUG_EVALUATE_IF(keyword,a1,a2) (a2)
-#define DBUG_PRINT(keyword,arglist) do { } while(0)
-#define DBUG_PUSH(a1)
-#define DBUG_SET(a1)
-#define DBUG_SET_INITIAL(a1)
-#define DBUG_POP()
-#define DBUG_PROCESS(a1)
+#define DBUG_PRINT(keyword,arglist) do { } while(0)
+#define DBUG_PUSH(a1) do { } while(0)
+#define DBUG_SET(a1) do { } while(0)
+#define DBUG_SET_INITIAL(a1) do { } while(0)
+#define DBUG_POP() do { } while(0)
+#define DBUG_PROCESS(a1) do { } while(0)
#define DBUG_SETJMP(a1) setjmp(a1)
#define DBUG_LONGJMP(a1) longjmp(a1)
-#define DBUG_DUMP(keyword,a1,a2)
-#define DBUG_END()
-#define DBUG_ASSERT(A) do { } while(0)
-#define DBUG_LOCK_FILE
+#define DBUG_DUMP(keyword,a1,a2) do { } while(0)
+#define DBUG_END() do { } while(0)
+#define DBUG_ASSERT(A) do { } while(0)
+#define DBUG_LOCK_FILE do { } while(0)
#define DBUG_FILE (stderr)
-#define DBUG_UNLOCK_FILE
+#define DBUG_UNLOCK_FILE do { } while(0)
#define DBUG_EXPLAIN(buf,len)
#define DBUG_EXPLAIN_INITIAL(buf,len)
+#define DEBUGGER_OFF do { } while(0)
+#define DEBUGGER_ON do { } while(0)
#define IF_DBUG(A)
+#define DBUG_ABORT() abort()
#endif
-#ifdef __cplusplus
+#ifdef __cplusplus
}
#endif
#endif
diff --git a/include/my_global.h b/include/my_global.h
index ac49d48e78d..554b26a1602 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -156,9 +156,14 @@
#define __builtin_expect(x, expected_value) (x)
#endif
-#define likely(x) __builtin_expect((x),1)
-#define unlikely(x) __builtin_expect((x),0)
-
+/**
+ The semantics of builtin_expect() are that
+ 1) its two arguments are long
+ 2) it's likely that they are ==
+ Those of our likely(x) are that x can be bool/int/longlong/pointer.
+*/
+#define likely(x) __builtin_expect(((x) != 0),1)
+#define unlikely(x) __builtin_expect(((x) != 0),0)
/*
The macros below are useful in optimising places where it has been
@@ -410,6 +415,7 @@ C_MODE_END
#ifndef stdin
#include <stdio.h>
#endif
+#include <stdarg.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
@@ -431,6 +437,9 @@ C_MODE_END
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
#ifdef HAVE_SYS_TIMEB_H
#include <sys/timeb.h> /* Avoid warnings on SCO */
#endif
@@ -469,14 +478,13 @@ C_MODE_END
#include <assert.h>
/* an assert that works at compile-time. only for constant expression */
-#ifndef __GNUC__
+#ifdef _some_old_compiler_that_does_not_understand_the_construct_below_
#define compile_time_assert(X) do { } while(0)
#else
#define compile_time_assert(X) \
do \
{ \
- char compile_time_assert[(X) ? 1 : -1] \
- __attribute__ ((unused)); \
+ typedef char compile_time_assert[(X) ? 1 : -1]; \
} while(0)
#endif
@@ -570,7 +578,7 @@ typedef unsigned short ushort;
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
#define sgn(a) (((a) < 0) ? -1 : ((a) > 0) ? 1 : 0)
-#define swap_variables(t, a, b) { t dummy; dummy= a; a= b; b= dummy; }
+#define swap_variables(t, a, b) { t swap_dummy; swap_dummy= a; a= b; b= swap_dummy; }
#define test(a) ((a) ? 1 : 0)
#define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0)
#define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0)
@@ -636,6 +644,7 @@ C_MODE_END
# endif
#endif
+typedef char my_bool; /* Small bool */
#include <my_dbug.h>
#define MIN_ARRAY_SIZE 0 /* Zero or One. Gcc allows zero*/
@@ -1073,7 +1082,6 @@ typedef off_t os_off_t;
typedef uint8 int7; /* Most effective integer 0 <= x <= 127 */
typedef short int15; /* Most effective integer 0 <= x <= 32767 */
typedef int myf; /* Type of MyFlags in my_funcs */
-typedef char my_bool; /* Small bool */
#if !defined(bool) && (!defined(HAVE_BOOL) || !defined(__cplusplus))
typedef char bool; /* Ordinary boolean values 0 1 */
#endif
@@ -1140,9 +1148,7 @@ typedef char bool; /* Ordinary boolean values 0 1 */
#define SCALE_SEC 100
#define SCALE_USEC 10000
#define MY_HOW_OFTEN_TO_ALARM 2 /* How often we want info on screen */
-#define MY_HOW_OFTEN_TO_WRITE 1000 /* How often we want info on screen */
-
-
+#define MY_HOW_OFTEN_TO_WRITE 10000 /* How often we want info on screen */
/*
Define-funktions for reading and storing in machine independent format
@@ -1151,7 +1157,7 @@ typedef char bool; /* Ordinary boolean values 0 1 */
/* Optimized store functions for Intel x86 */
#if defined(__i386__) || defined(_WIN32)
-#define sint2korr(A) (*((int16 *) (A)))
+#define sint2korr(A) (*((const int16 *) (A)))
#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
(((uint32) 255L << 24) | \
(((uint32) (uchar) (A)[2]) << 16) |\
@@ -1160,8 +1166,8 @@ typedef char bool; /* Ordinary boolean values 0 1 */
(((uint32) (uchar) (A)[2]) << 16) |\
(((uint32) (uchar) (A)[1]) << 8) | \
((uint32) (uchar) (A)[0])))
-#define sint4korr(A) (*((long *) (A)))
-#define uint2korr(A) (*((uint16 *) (A)))
+#define sint4korr(A) (*((const long *) (A)))
+#define uint2korr(A) (*((const uint16 *) (A)))
#if defined(HAVE_purify) && !defined(_WIN32)
#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
@@ -1173,9 +1179,9 @@ typedef char bool; /* Ordinary boolean values 0 1 */
Please, note, uint3korr reads 4 bytes (not 3) !
It means, that you have to provide enough allocated space !
*/
-#define uint3korr(A) (long) (*((unsigned int *) (A)) & 0xFFFFFF)
+#define uint3korr(A) (long) (*((const unsigned int *) (A)) & 0xFFFFFF)
#endif /* HAVE_purify && !_WIN32 */
-#define uint4korr(A) (*((uint32 *) (A)))
+#define uint4korr(A) (*((const uint32 *) (A)))
#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16) +\
@@ -1187,8 +1193,8 @@ typedef char bool; /* Ordinary boolean values 0 1 */
(((uint32) ((uchar) (A)[3])) << 24)) + \
(((ulonglong) ((uchar) (A)[4])) << 32) + \
(((ulonglong) ((uchar) (A)[5])) << 40))
-#define uint8korr(A) (*((ulonglong *) (A)))
-#define sint8korr(A) (*((longlong *) (A)))
+#define uint8korr(A) (*((const ulonglong *) (A)))
+#define sint8korr(A) (*((const longlong *) (A)))
#define int2store(T,A) *((uint16*) (T))= (uint16) (A)
#define int3store(T,A) do { *(T)= (uchar) ((A));\
*(T+1)=(uchar) (((uint) (A) >> 8));\
@@ -1213,17 +1219,17 @@ typedef union {
} doubleget_union;
#define doubleget(V,M) \
do { doubleget_union _tmp; \
- _tmp.m[0] = *((long*)(M)); \
- _tmp.m[1] = *(((long*) (M))+1); \
+ _tmp.m[0] = *((const long*)(M)); \
+ _tmp.m[1] = *(((const long*) (M))+1); \
(V) = _tmp.v; } while(0)
-#define doublestore(T,V) do { *((long *) T) = ((doubleget_union *)&V)->m[0]; \
- *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; \
+#define doublestore(T,V) do { *((long *) T) = ((const doubleget_union *)&V)->m[0]; \
+ *(((long *) T)+1) = ((const doubleget_union *)&V)->m[1]; \
} while (0)
-#define float4get(V,M) do { *((float *) &(V)) = *((float*) (M)); } while(0)
+#define float4get(V,M) do { *((float *) &(V)) = *((const float*) (M)); } while(0)
#define float8get(V,M) doubleget((V),(M))
-#define float4store(V,M) memcpy((uchar*) V,(uchar*) (&M),sizeof(float))
-#define floatstore(T,V) memcpy((uchar*)(T), (uchar*)(&V),sizeof(float))
-#define floatget(V,M) memcpy((uchar*) &V,(uchar*) (M),sizeof(float))
+#define float4store(V,M) memcpy((uchar*) V,(const uchar*) (&M),sizeof(float))
+#define floatstore(T,V) memcpy((uchar*)(T), (const uchar*)(&V),sizeof(float))
+#define floatget(V,M) memcpy((uchar*) &V,(const uchar*) (M),sizeof(float))
#define float8store(V,M) doublestore((V),(M))
#else
@@ -1517,17 +1523,45 @@ inline void operator delete[](void*, void*) { /* Do nothing */ }
#if !defined(max)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
+#endif
/*
Only Linux is known to need an explicit sync of the directory to make sure a
file creation/deletion/renaming in(from,to) this directory durable.
*/
#ifdef TARGET_OS_LINUX
#define NEED_EXPLICIT_SYNC_DIR 1
+#else
+/*
+ On linux default rwlock scheduling policy is good enough for
+ waiting_threads.c, on other systems use our special implementation
+ (which is slower).
+
+ QQ perhaps this should be tested in configure ? how ?
+*/
+#define WT_RWLOCKS_USE_MUTEXES 1
#endif
#if !defined(__cplusplus) && !defined(bool)
#define bool In_C_you_should_use_my_bool_instead()
#endif
+/* Provide __func__ macro definition for platforms that miss it. */
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+# define __func__ __FUNCTION__
+# else
+# define __func__ "<unknown>"
+# endif
+#elif defined(_MSC_VER)
+# if _MSC_VER < 1300
+# define __func__ "<unknown>"
+# else
+# define __func__ __FUNCTION__
+# endif
+#elif defined(__BORLANDC__)
+# define __func__ __FUNC__
+#else
+# define __func__ "<unknown>"
+#endif
+
#endif /* my_global_h */
diff --git a/include/my_handler.h b/include/my_handler.h
index a3376cb74a2..537cf68c150 100644
--- a/include/my_handler.h
+++ b/include/my_handler.h
@@ -19,6 +19,7 @@
#define _my_handler_h
#include "myisampack.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -36,14 +37,15 @@ extern "C" {
#define HA_MAX_POSSIBLE_KEY 255 /* For myisamchk */
/*
The following defines can be increased if necessary.
- But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and HA_MAX_KEY_LENGTH.
+ But beware the dependency of HA_MAX_POSSIBLE_KEY_BUFF and HA_MAX_KEY_LENGTH.
*/
#define HA_MAX_KEY_LENGTH 1000 /* Max length in bytes */
#define HA_MAX_KEY_SEG 16 /* Max segments for key */
-#define HA_MAX_POSSIBLE_KEY_BUFF (HA_MAX_KEY_LENGTH + 24+ 6+6)
+#define HA_MAX_POSSIBLE_KEY_BUFF (HA_MAX_KEY_LENGTH + 24+ 6+6)
#define HA_MAX_KEY_BUFF (HA_MAX_KEY_LENGTH+HA_MAX_KEY_SEG*6+8+8)
+#define HA_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */
typedef struct st_HA_KEYSEG /* Key-portion */
{
@@ -61,22 +63,22 @@ typedef struct st_HA_KEYSEG /* Key-portion */
} HA_KEYSEG;
#define get_key_length(length,key) \
-{ if (*(uchar*) (key) != 255) \
- length= (uint) *(uchar*) ((key)++); \
+{ if (*(const uchar*) (key) != 255) \
+ length= (uint) *(const uchar*) ((key)++); \
else \
{ length= mi_uint2korr((key)+1); (key)+=3; } \
}
#define get_key_length_rdonly(length,key) \
-{ if (*(uchar*) (key) != 255) \
- length= ((uint) *(uchar*) ((key))); \
+{ if (*(const uchar*) (key) != 255) \
+ length= ((uint) *(const uchar*) ((key))); \
else \
{ length= mi_uint2korr((key)+1); } \
}
#define get_key_pack_length(length,length_pack,key) \
-{ if (*(uchar*) (key) != 255) \
- { length= (uint) *(uchar*) ((key)++); length_pack= 1; }\
+{ if (*(const uchar*) (key) != 255) \
+ { length= (uint) *(const uchar*) ((key)++); length_pack= 1; }\
else \
{ length=mi_uint2korr((key)+1); (key)+= 3; length_pack= 3; } \
}
@@ -106,13 +108,13 @@ typedef struct st_HA_KEYSEG /* Key-portion */
#define clr_rec_bits(bit_ptr, bit_ofs, bit_len) \
set_rec_bits(0, bit_ptr, bit_ofs, bit_len)
-extern int ha_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint ,
- my_bool, my_bool);
-extern int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
- register uchar *b, uint key_length, uint nextflag,
- uint *diff_pos);
+extern int ha_compare_text(CHARSET_INFO *, const uchar *, uint,
+ const uchar *, uint , my_bool, my_bool);
+extern int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a,
+ register const uchar *b, uint key_length,
+ uint32 nextflag, uint *diff_pos);
-extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a);
+extern HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, const uchar *a);
extern void my_handler_error_register(void);
extern void my_handler_error_unregister(void);
/*
diff --git a/include/my_pthread.h b/include/my_pthread.h
index 151cb34faff..538457a523a 100644
--- a/include/my_pthread.h
+++ b/include/my_pthread.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -79,25 +79,27 @@ typedef void * (__cdecl *pthread_handler)(void *);
so it can be used directly as a 64 bit value. The value
stored is in 100ns units.
*/
- union ft64 {
+union ft64 {
FILETIME ft;
__int64 i64;
- };
+};
+
struct timespec {
union ft64 tv;
/* The max timeout value in millisecond for pthread_cond_timedwait */
long max_timeout_msec;
};
-#define set_timespec(ABSTIME,SEC) { \
- GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \
- (ABSTIME).tv.i64+= (__int64)(SEC)*10000000; \
- (ABSTIME).max_timeout_msec= (long)((SEC)*1000); \
-}
-#define set_timespec_nsec(ABSTIME,NSEC) { \
- GetSystemTimeAsFileTime(&((ABSTIME).tv.ft)); \
- (ABSTIME).tv.i64+= (__int64)(NSEC)/100; \
- (ABSTIME).max_timeout_msec= (long)((NSEC)/1000000); \
-}
+
+#define set_timespec_time_nsec(ABSTIME,TIME,NSEC) do { \
+ (ABSTIME).tv.i64= (TIME)+(__int64)(NSEC)/100; \
+ (ABSTIME).max_timeout_msec= (long)((NSEC)/1000000); \
+} while(0)
+
+#define set_timespec_nsec(ABSTIME,NSEC) do { \
+ union ft64 tv; \
+ GetSystemTimeAsFileTime(&tv.ft); \
+ set_timespec_time_nsec((ABSTIME), tv.i64, (NSEC)); \
+} while(0)
void win_pthread_init(void);
int win_pthread_setspecific(void *A,void *B,uint length);
@@ -125,6 +127,8 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/
#define HAVE_LOCALTIME_R 1
#define _REENTRANT 1
#define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1
+#define PTHREAD_STACK_MIN 65536
+
/*
Windows has two ways to use thread local storage. The most efficient
@@ -158,7 +162,7 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/
#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0)
#define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
#define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A))
-#define pthread_mutex_unlock(A) LeaveCriticalSection(A)
+#define pthread_mutex_unlock(A) (LeaveCriticalSection(A),0)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
#define pthread_kill(A,B) pthread_dummy((A) ? 0 : ESRCH)
@@ -172,6 +176,7 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/
#define pthread_detach_this_thread()
#define pthread_condattr_init(A)
#define pthread_condattr_destroy(A)
+#define pthread_yield() Sleep(0) /* according to MSDN */
#define my_pthread_getprio(thread_id) pthread_dummy(0)
@@ -234,13 +239,13 @@ int my_sigwait(const sigset_t *set,int *sig);
#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
#ifndef SAFE_MUTEX
-#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
-extern int my_pthread_mutex_init(pthread_mutex_t *mp,
- const pthread_mutexattr_t *attr);
+#define pthread_mutex_init(a,b) my_pthread_mutex_noposix_init((a),(b))
+extern int my_pthread_mutex_noposix_init(pthread_mutex_t *mp,
+ const pthread_mutexattr_t *attr);
#endif /* SAFE_MUTEX */
-#define pthread_cond_init(a,b) my_pthread_cond_init((a),(b))
-extern int my_pthread_cond_init(pthread_cond_t *mp,
- const pthread_condattr_t *attr);
+#define pthread_cond_init(a,b) my_pthread_cond_noposix_init((a),(b))
+extern int my_pthread_cond_noposix_init(pthread_cond_t *mp,
+ const pthread_condattr_t *attr);
#endif /* HAVE_NONPOSIX_PTHREAD_MUTEX_INIT */
#if defined(HAVE_SIGTHREADMASK) && !defined(HAVE_PTHREAD_SIGMASK)
@@ -399,64 +404,80 @@ void my_pthread_attr_getstacksize(pthread_attr_t *attrib, size_t *size);
int my_pthread_mutex_trylock(pthread_mutex_t *mutex);
#endif
+#if !defined(HAVE_PTHREAD_YIELD_ONE_ARG) && !defined(HAVE_PTHREAD_YIELD_ZERO_ARG)
+/* no pthread_yield() available */
+#ifdef HAVE_SCHED_YIELD
+#define pthread_yield() sched_yield()
+#elif defined(HAVE_PTHREAD_YIELD_NP) /* can be Mac OS X */
+#define pthread_yield() pthread_yield_np()
+#elif defined(HAVE_THR_YIELD)
+#define pthread_yield() thr_yield()
+#endif
+#endif
+
/*
The defines set_timespec and set_timespec_nsec should be used
for calculating an absolute time at which
pthread_cond_timedwait should timeout
*/
-#ifdef HAVE_TIMESPEC_TS_SEC
-#ifndef set_timespec
-#define set_timespec(ABSTIME,SEC) \
-{ \
- (ABSTIME).ts_sec=time(0) + (time_t) (SEC); \
- (ABSTIME).ts_nsec=0; \
-}
-#endif /* !set_timespec */
+
+#define set_timespec(ABSTIME,SEC) set_timespec_nsec((ABSTIME),(SEC)*1000000000ULL)
+
#ifndef set_timespec_nsec
-#define set_timespec_nsec(ABSTIME,NSEC) \
-{ \
- ulonglong now= my_getsystime() + (NSEC/100); \
- (ABSTIME).ts_sec= (now / ULL(10000000)); \
- (ABSTIME).ts_nsec= (now % ULL(10000000) * 100 + ((NSEC) % 100)); \
-}
+#define set_timespec_nsec(ABSTIME,NSEC) \
+ set_timespec_time_nsec((ABSTIME),my_getsystime(),(NSEC))
#endif /* !set_timespec_nsec */
+
+/* adapt for two different flavors of struct timespec */
+#ifdef HAVE_TIMESPEC_TS_SEC
+#define MY_tv_sec ts_sec
+#define MY_tv_nsec ts_nsec
#else
-#ifndef set_timespec
-#define set_timespec(ABSTIME,SEC) \
-{\
- struct timeval tv;\
- gettimeofday(&tv,0);\
- (ABSTIME).tv_sec=tv.tv_sec+(time_t) (SEC);\
- (ABSTIME).tv_nsec=tv.tv_usec*1000;\
-}
-#endif /* !set_timespec */
-#ifndef set_timespec_nsec
-#define set_timespec_nsec(ABSTIME,NSEC) \
-{\
- ulonglong now= my_getsystime() + (NSEC/100); \
- (ABSTIME).tv_sec= (time_t) (now / ULL(10000000)); \
- (ABSTIME).tv_nsec= (long) (now % ULL(10000000) * 100 + ((NSEC) % 100)); \
-}
-#endif /* !set_timespec_nsec */
+#define MY_tv_sec tv_sec
+#define MY_tv_nsec tv_nsec
#endif /* HAVE_TIMESPEC_TS_SEC */
- /* safe_mutex adds checking to mutex for easier debugging */
+#ifndef set_timespec_time_nsec
+#define set_timespec_time_nsec(ABSTIME,TIME,NSEC) do { \
+ ulonglong nsec= (NSEC); \
+ ulonglong now= (TIME) + (nsec/100); \
+ (ABSTIME).MY_tv_sec= (now / ULL(10000000)); \
+ (ABSTIME).MY_tv_nsec= (now % ULL(10000000) * 100 + (nsec % 100)); \
+} while(0)
+#endif /* !set_timespec_time_nsec */
+
+/* safe_mutex adds checking to mutex for easier debugging */
#if defined(__NETWARE__) && !defined(SAFE_MUTEX_DETECT_DESTROY)
#define SAFE_MUTEX_DETECT_DESTROY
#endif
+struct st_hash;
typedef struct st_safe_mutex_t
{
pthread_mutex_t global,mutex;
- const char *file;
+ const char *file, *name;
uint line,count;
+ myf create_flags, active_flags;
+ ulong id;
pthread_t thread;
+ struct st_hash *locked_mutex, *used_mutex;
+ struct st_safe_mutex_t *prev, *next;
#ifdef SAFE_MUTEX_DETECT_DESTROY
struct st_safe_mutex_info_t *info; /* to track destroying of mutexes */
#endif
} safe_mutex_t;
+typedef struct st_safe_mutex_deadlock_t
+{
+ const char *file, *name;
+ safe_mutex_t *mutex;
+ uint line;
+ ulong count;
+ ulong id;
+ my_bool warning_only;
+} safe_mutex_deadlock_t;
+
#ifdef SAFE_MUTEX_DETECT_DESTROY
/*
Used to track the destroying of mutexes. This needs to be a seperate
@@ -474,8 +495,10 @@ typedef struct st_safe_mutex_info_t
#endif /* SAFE_MUTEX_DETECT_DESTROY */
int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr,
+ const char *name, myf my_flags,
const char *file, uint line);
-int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line);
+int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
+ uint line);
int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line);
int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line);
int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file,
@@ -484,8 +507,12 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
struct timespec *abstime, const char *file, uint line);
void safe_mutex_global_init(void);
void safe_mutex_end(FILE *file);
+void safe_mutex_free_deadlock_data(safe_mutex_t *mp);
/* Wrappers if safe mutex is actually used */
+#define MYF_TRY_LOCK 1
+#define MYF_NO_DEADLOCK_DETECTION 2
+
#ifdef SAFE_MUTEX
#undef pthread_mutex_init
#undef pthread_mutex_lock
@@ -497,13 +524,15 @@ void safe_mutex_end(FILE *file);
#undef pthread_cond_wait
#undef pthread_cond_timedwait
#undef pthread_mutex_trylock
-#define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__)
-#define pthread_mutex_lock(A) safe_mutex_lock((A), FALSE, __FILE__, __LINE__)
+#define my_pthread_mutex_init(A,B,C,D) safe_mutex_init((A),(B),(C),(D),__FILE__,__LINE__)
+#define pthread_mutex_init(A,B) safe_mutex_init((A),(B),#A,0,__FILE__,__LINE__)
+#define pthread_mutex_lock(A) safe_mutex_lock((A), 0, __FILE__, __LINE__)
+#define my_pthread_mutex_lock(A,B) safe_mutex_lock((A), (B), __FILE__, __LINE__)
#define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__)
#define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__)
#define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__)
#define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__)
-#define pthread_mutex_trylock(A) safe_mutex_lock((A), TRUE, __FILE__, __LINE__)
+#define pthread_mutex_trylock(A) safe_mutex_lock((A), MYF_TRY_LOCK, __FILE__, __LINE__)
#define pthread_mutex_t safe_mutex_t
#define safe_mutex_assert_owner(mp) \
DBUG_ASSERT((mp)->count > 0 && \
@@ -512,8 +541,11 @@ void safe_mutex_end(FILE *file);
DBUG_ASSERT(! (mp)->count || \
! pthread_equal(pthread_self(), (mp)->thread))
#else
+#define my_pthread_mutex_init(A,B,C,D) pthread_mutex_init((A),(B))
+#define my_pthread_mutex_lock(A,B) pthread_mutex_lock(A)
#define safe_mutex_assert_owner(mp)
#define safe_mutex_assert_not_owner(mp)
+#define safe_mutex_free_deadlock_data(mp)
#endif /* SAFE_MUTEX */
#if defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
@@ -663,6 +695,9 @@ extern int pthread_dummy(int);
#endif
#endif
+#define MY_PTHREAD_LOCK_READ 0
+#define MY_PTHREAD_LOCK_WRITE 1
+
struct st_my_thread_var
{
int thr_errno;
@@ -677,6 +712,9 @@ struct st_my_thread_var
my_bool init;
struct st_my_thread_var *next,**prev;
void *opt_info;
+ uint lock_type; /* used by conditional release the queue */
+ void *stack_ends_here;
+ safe_mutex_t *mutex_in_use;
#ifndef DBUG_OFF
void *dbug;
char name[THREAD_NAME_SIZE+1];
@@ -684,7 +722,10 @@ struct st_my_thread_var
};
extern struct st_my_thread_var *_my_thread_var(void) __attribute__ ((const));
+extern void **my_thread_var_dbug();
+extern safe_mutex_t **my_thread_var_mutex_in_use();
extern uint my_thread_end_wait_time;
+extern my_bool safe_mutex_deadlock_detector;
#define my_thread_var (_my_thread_var())
#define my_errno my_thread_var->thr_errno
/*
diff --git a/include/my_sys.h b/include/my_sys.h
index 60122eab94e..07e56f1c91f 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -62,12 +62,14 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */
#define MY_REDEL_MAKE_BACKUP 256
#define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */
-#define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */
+#define MY_SHORT_WAIT 64 /* my_lock() don't wait if can't lock */
+#define MY_FORCE_LOCK 128 /* use my_lock() even if disable_locking */
+#define MY_NO_WAIT 256 /* my_lock() don't wait at all */
#define MY_ZEROFILL 32 /* my_malloc(), fill array with zero */
#define MY_ALLOW_ZERO_PTR 64 /* my_realloc() ; zero ptr -> malloc */
#define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */
#define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */
-#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy: Don't overwrite file */
+#define MY_DONT_OVERWRITE_FILE 2048 /* my_copy: Don't overwrite file */
#define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */
#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */
@@ -90,9 +92,11 @@ extern int NEAR my_errno; /* Last error in mysys */
#define ME_COLOUR1 ((1 << ME_HIGHBYTE)) /* Possibly error-colours */
#define ME_COLOUR2 ((2 << ME_HIGHBYTE))
#define ME_COLOUR3 ((3 << ME_HIGHBYTE))
-#define ME_FATALERROR 1024 /* Fatal statement error */
-#define ME_NO_WARNING_FOR_ERROR 2048 /* Don't push a warning for error */
-#define ME_NO_SP_HANDLER 4096 /* Don't call stored routine error handlers */
+#define ME_JUST_INFO 1024 /**< not error but just info */
+#define ME_JUST_WARNING 2048 /**< not error but just warning */
+#define ME_FATALERROR 4096 /* Fatal statement error */
+#define ME_NO_WARNING_FOR_ERROR 8192 /* Don't push a warning for error */
+#define ME_NO_SP_HANDLER 16384 /* Don't call stored routine error handlers */
/* Bits in last argument to fn_format */
#define MY_REPLACE_DIR 1 /* replace dir in name with 'dir' */
@@ -211,6 +215,7 @@ extern int errno; /* declare errno */
extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
extern char *home_dir; /* Home directory for user */
extern const char *my_progname; /* program-name (printed in errors) */
+extern const char *my_progname_short; /* like above but without directory */
extern char NEAR curr_dir[]; /* Current directory for user */
extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags);
extern int (*fatal_error_handler_hook)(uint my_err, const char *str,
@@ -218,6 +223,9 @@ extern int (*fatal_error_handler_hook)(uint my_err, const char *str,
extern uint my_file_limit;
extern ulong my_thread_stack_size;
+extern const char *(*proc_info_hook)(void *, const char *, const char *,
+ const char *, const unsigned int);
+
#ifdef HAVE_LARGE_PAGES
extern my_bool my_use_large_pages;
extern uint my_large_page_size;
@@ -288,7 +296,13 @@ enum flush_type
As my_disable_flush_pagecache_blocks is always 0, the following option
is strictly equivalent to FLUSH_KEEP
*/
- FLUSH_FORCE_WRITE
+ FLUSH_FORCE_WRITE,
+ /**
+ @brief like FLUSH_KEEP but return immediately if file is already being
+ flushed (even partially) by another thread; only for page cache,
+ forbidden for key cache.
+ */
+ FLUSH_KEEP_LAZY
};
typedef struct st_record_cache /* Used when cacheing records */
@@ -547,6 +561,7 @@ my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */
*(info)->current_pos)
typedef uint32 ha_checksum;
+extern ha_checksum my_crc_dbug_check;
/* Define the type of function to be passed to process_default_option_files */
typedef int (*Process_option_func)(void *ctx, const char *group_name,
@@ -644,6 +659,7 @@ extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags);
extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags);
extern int my_fclose(FILE *fd,myf MyFlags);
extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
+extern int my_chmod(const char *name, mode_t mode, myf my_flags);
extern int my_sync(File fd, myf my_flags);
extern int my_sync_dir(const char *dir_name, myf my_flags);
extern int my_sync_dir_by_file(const char *file_name, myf my_flags);
@@ -651,6 +667,8 @@ extern int my_error _VARARGS((int nr,myf MyFlags, ...));
extern int my_printf_error _VARARGS((uint my_err, const char *format,
myf MyFlags, ...))
ATTRIBUTE_FORMAT(printf, 2, 4);
+extern int my_printv_error(uint error, const char *format, myf MyFlags,
+ va_list ap);
extern int my_error_register(const char **errmsgs, int first, int last);
extern const char **my_error_unregister(int first, int last);
extern int my_message(uint my_err, const char *str,myf MyFlags);
@@ -794,7 +812,7 @@ extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array,uint element_size,
extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
uint init_alloc,uint alloc_increment
CALLER_INFO_PROTO);
-extern my_bool insert_dynamic(DYNAMIC_ARRAY *array,uchar * element);
+extern my_bool insert_dynamic(DYNAMIC_ARRAY *array, const uchar * element);
extern uchar *alloc_dynamic(DYNAMIC_ARRAY *array);
extern uchar *pop_dynamic(DYNAMIC_ARRAY*);
extern my_bool set_dynamic(DYNAMIC_ARRAY *array,uchar * element,uint array_index);
@@ -865,6 +883,12 @@ extern int unpackfrm(uchar **, size_t *, const uchar *);
extern ha_checksum my_checksum(ha_checksum crc, const uchar *mem,
size_t count);
+#ifndef DBUG_OFF
+extern void my_debug_put_break_here(void);
+#else
+#define my_debug_put_break_here() do {} while(0)
+#endif
+
extern void my_sleep(ulong m_seconds);
extern ulong crc32(ulong crc, const uchar *buf, uint len);
extern uint my_set_max_open_files(uint files);
@@ -923,6 +947,22 @@ int my_getpagesize(void);
int my_msync(int, void *, size_t, int);
+#define MY_UUID_SIZE 16
+#define MY_UUID_STRING_LENGTH (8+1+4+1+4+1+4+1+12)
+
+void my_uuid_init(ulong seed1, ulong seed2);
+void my_uuid(uchar *guid);
+void my_uuid2str(const uchar *guid, char *s);
+void my_uuid_end();
+
+struct my_rnd_struct {
+ unsigned long seed1,seed2,max_value;
+ double max_value_dbl;
+};
+
+void my_rnd_init(struct my_rnd_struct *rand_st, ulong seed1, ulong seed2);
+double my_rnd(struct my_rnd_struct *rand_st);
+
/* character sets */
extern uint get_charset_number(const char *cs_name, uint cs_flags);
extern uint get_collation_number(const char *name);
diff --git a/include/my_tree.h b/include/my_tree.h
index 24bbdd54019..e387b25d431 100644
--- a/include/my_tree.h
+++ b/include/my_tree.h
@@ -66,8 +66,8 @@ void init_tree(TREE *tree, ulong default_alloc_size, ulong memory_limit,
tree_element_free free_element, void *custom_arg);
void delete_tree(TREE*);
void reset_tree(TREE*);
- /* similar to delete tree, except we do not my_free() blocks in mem_root
- */
+
+ /* similar to delete tree, except we do not my_free() blocks in mem_root */
#define is_tree_inited(tree) ((tree)->root != 0)
/* Functions on leafs */
@@ -86,6 +86,7 @@ void *tree_search_next(TREE *tree, TREE_ELEMENT ***last_pos, int l_offs,
int r_offs);
ha_rows tree_record_pos(TREE *tree, const void *key,
enum ha_rkey_function search_flag, void *custom_arg);
+#define reset_free_element(tree) (tree)->free= 0
#define TREE_ELEMENT_EXTRA_SIZE (sizeof(TREE_ELEMENT) + sizeof(void*))
diff --git a/include/myisam.h b/include/myisam.h
index d7bfdf7191e..5a5d21e999e 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -31,10 +31,11 @@ extern "C" {
#include "keycache.h"
#endif
#include "my_handler.h"
+#include <myisamchk.h>
#include <mysql/plugin.h>
/*
- Limit max keys according to HA_MAX_POSSIBLE_KEY
+ Limit max keys according to HA_MAX_POSSIBLE_KEY; See myisamchk.h for details
*/
#if MAX_INDEXES > HA_MAX_POSSIBLE_KEY
@@ -44,15 +45,7 @@ extern "C" {
#endif
#define MI_MAX_POSSIBLE_KEY_BUFF HA_MAX_POSSIBLE_KEY_BUFF
-/*
- The following defines can be increased if necessary.
- But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and MI_MAX_KEY_LENGTH.
-*/
-#define MI_MAX_KEY_LENGTH 1000 /* Max length in bytes */
-#define MI_MAX_KEY_SEG 16 /* Max segments for key */
-#define MI_MAX_KEY_BUFF (MI_MAX_KEY_LENGTH+MI_MAX_KEY_SEG*6+8+8)
-#define MI_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */
#define MI_NAME_IEXT ".MYI"
#define MI_NAME_DEXT ".MYD"
/* Max extra space to use when sorting keys */
@@ -233,7 +226,7 @@ struct st_mi_bit_buff;
typedef struct st_columndef /* column information */
{
- int16 type; /* en_fieldtype */
+ enum en_fieldtype type;
uint16 length; /* length of field */
uint32 offset; /* Offset to position in row */
uint8 null_bit; /* If column may be 0 */
@@ -248,7 +241,6 @@ typedef struct st_columndef /* column information */
#endif
} MI_COLUMNDEF;
-
extern char * myisam_log_filename; /* Name of logfile */
extern ulong myisam_block_size;
extern ulong myisam_concurrent_insert;
@@ -296,7 +288,7 @@ extern int mi_extra(struct st_myisam_info *file,
enum ha_extra_function function,
void *extra_arg);
extern int mi_reset(struct st_myisam_info *file);
-extern ha_rows mi_records_in_range(MI_INFO *info, int inx,
+extern ha_rows mi_records_in_range(MI_INFO *info,int inx,
key_range *min_key, key_range *max_key);
extern int mi_log(int activate_log);
extern int mi_is_changed(struct st_myisam_info *info);
@@ -309,190 +301,112 @@ extern uint mi_get_pointer_length(ulonglong file_length, uint def);
#define MYISAMCHK_REPAIR 1 /* equivalent to myisamchk -r */
#define MYISAMCHK_VERIFY 2 /* Verify, run repair if failure */
-/*
- Definitions needed for myisamchk.c
+typedef uint mi_bit_type;
- Entries marked as "QQ to be removed" are NOT used to
- pass check/repair options to mi_check.c. They are used
- internally by myisamchk.c or/and ha_myisam.cc and should NOT
- be stored together with other flags. They should be removed
- from the following list to make addition of new flags possible.
-*/
+typedef struct st_mi_bit_buff
+{ /* Used for packing of record */
+ mi_bit_type current_byte;
+ uint bits;
+ uchar *pos, *end, *blob_pos, *blob_end;
+ uint error;
+} MI_BIT_BUFF;
-#define T_AUTO_INC 1
-#define T_AUTO_REPAIR 2 /* QQ to be removed */
-#define T_BACKUP_DATA 4
-#define T_CALC_CHECKSUM 8
-#define T_CHECK 16 /* QQ to be removed */
-#define T_CHECK_ONLY_CHANGED 32 /* QQ to be removed */
-#define T_CREATE_MISSING_KEYS 64
-#define T_DESCRIPT 128
-#define T_DONT_CHECK_CHECKSUM 256
-#define T_EXTEND 512
-#define T_FAST (1L << 10) /* QQ to be removed */
-#define T_FORCE_CREATE (1L << 11) /* QQ to be removed */
-#define T_FORCE_UNIQUENESS (1L << 12)
-#define T_INFO (1L << 13)
-#define T_MEDIUM (1L << 14)
-#define T_QUICK (1L << 15) /* QQ to be removed */
-#define T_READONLY (1L << 16) /* QQ to be removed */
-#define T_REP (1L << 17)
-#define T_REP_BY_SORT (1L << 18) /* QQ to be removed */
-#define T_REP_PARALLEL (1L << 19) /* QQ to be removed */
-#define T_RETRY_WITHOUT_QUICK (1L << 20)
-#define T_SAFE_REPAIR (1L << 21)
-#define T_SILENT (1L << 22)
-#define T_SORT_INDEX (1L << 23) /* QQ to be removed */
-#define T_SORT_RECORDS (1L << 24) /* QQ to be removed */
-#define T_STATISTICS (1L << 25)
-#define T_UNPACK (1L << 26)
-#define T_UPDATE_STATE (1L << 27)
-#define T_VERBOSE (1L << 28)
-#define T_VERY_SILENT (1L << 29)
-#define T_WAIT_FOREVER (1L << 30)
-#define T_WRITE_LOOP ((ulong) 1L << 31)
-
-#define T_REP_ANY (T_REP | T_REP_BY_SORT | T_REP_PARALLEL)
-/*
- Flags used by myisamchk.c or/and ha_myisam.cc that are NOT passed
- to mi_check.c follows:
-*/
-
-#define TT_USEFRM 1
-#define TT_FOR_UPGRADE 2
-
-#define O_NEW_INDEX 1 /* Bits set in out_flag */
-#define O_NEW_DATA 2
-#define O_DATA_LOST 4
-
-/* these struct is used by my_check to tell it what to do */
-
-typedef struct st_sort_key_blocks /* Used when sorting */
+typedef struct st_sort_info
{
- uchar *buff,*end_pos;
- uchar lastkey[MI_MAX_POSSIBLE_KEY_BUFF];
- uint last_length;
- int inited;
-} SORT_KEY_BLOCKS;
-
-
-/*
- MyISAM supports several statistics collection methods. Currently statistics
- collection method is not stored in MyISAM file and has to be specified for
- each table analyze/repair operation in MI_CHECK::stats_method.
-*/
+#ifdef THREAD
+ /* sync things */
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+#endif
+ MI_INFO *info;
+ HA_CHECK *param;
+ uchar *buff;
+ SORT_KEY_BLOCKS *key_block, *key_block_end;
+ SORT_FT_BUF *ft_buf;
+ my_off_t filelength, dupp, buff_length;
+ ha_rows max_records;
+ uint current_key, total_keys;
+ uint got_error, threads_running;
+ myf myf_rw;
+ enum data_file_type new_data_file_type;
+} MI_SORT_INFO;
-typedef enum
+typedef struct st_mi_sort_param
{
- /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */
- MI_STATS_METHOD_NULLS_NOT_EQUAL,
- /* Treat NULLs as equal when collecting statistics (like 4.0 did) */
- MI_STATS_METHOD_NULLS_EQUAL,
- /* Ignore NULLs - count only tuples without NULLs in the index components */
- MI_STATS_METHOD_IGNORE_NULLS
-} enum_mi_stats_method;
-
-typedef struct st_mi_check_param
-{
- ulonglong auto_increment_value;
- ulonglong max_data_file_length;
- ulonglong keys_in_use;
- ulonglong max_record_length;
- my_off_t search_after_block;
- my_off_t new_file_pos,key_file_blocks;
- my_off_t keydata,totaldata,key_blocks,start_check_pos;
- ha_rows total_records,total_deleted;
- ha_checksum record_checksum,glob_crc;
- ulong use_buffers,read_buffer_length,write_buffer_length,
- sort_buffer_length,sort_key_blocks;
- uint out_flag,warning_printed,error_printed,verbose;
- uint opt_sort_key,total_files,max_level;
- uint testflag, key_cache_block_size;
- uint8 language;
- my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
- my_bool retry_repair, force_sort;
- char temp_filename[FN_REFLEN],*isam_file_name;
- MY_TMPDIR *tmpdir;
- int tmpfile_createflag;
- myf myf_rw;
- IO_CACHE read_cache;
+ pthread_t thr;
+ IO_CACHE read_cache, tempfile, tempfile_for_exceptions;
+ DYNAMIC_ARRAY buffpek;
+ MI_BIT_BUFF bit_buff; /* For parallel repair of packrec. */
+ MI_KEYDEF *keyinfo;
+ MI_SORT_INFO *sort_info;
+ HA_KEYSEG *seg;
+ uchar **sort_keys;
+ uchar *rec_buff;
+ void *wordlist, *wordptr;
+ MEM_ROOT wordroot;
+ uchar *record;
+ MY_TMPDIR *tmpdir;
+
/*
The next two are used to collect statistics, see update_key_parts for
description.
*/
- ulonglong unique_count[MI_MAX_KEY_SEG+1];
- ulonglong notnull_count[MI_MAX_KEY_SEG+1];
-
- ha_checksum key_crc[HA_MAX_POSSIBLE_KEY];
- ulong rec_per_key_part[MI_MAX_KEY_SEG*HA_MAX_POSSIBLE_KEY];
- void *thd;
- const char *db_name, *table_name;
- const char *op_name;
- enum_mi_stats_method stats_method;
-} MI_CHECK;
-
-typedef struct st_sort_ft_buf
-{
- uchar *buf, *end;
- int count;
- uchar lastkey[MI_MAX_KEY_BUFF];
-} SORT_FT_BUF;
+ ulonglong unique[HA_MAX_KEY_SEG+1];
+ ulonglong notnull[HA_MAX_KEY_SEG+1];
+
+ my_off_t pos,max_pos,filepos,start_recpos;
+ uint key, key_length,real_key_length,sortbuff_size;
+ uint maxbuffers, keys, find_length, sort_keys_length;
+ my_bool fix_datafile, master;
+ my_bool calc_checksum; /* calculate table checksum */
+
+ int (*key_cmp)(struct st_mi_sort_param *, const void *, const void *);
+ int (*key_read)(struct st_mi_sort_param *,void *);
+ int (*key_write)(struct st_mi_sort_param *, const void *);
+ void (*lock_in_memory)(HA_CHECK *);
+ NEAR int (*write_keys)(struct st_mi_sort_param *, register uchar **,
+ uint , struct st_buffpek *, IO_CACHE *);
+ NEAR uint (*read_to_buffer)(IO_CACHE *,struct st_buffpek *, uint);
+ NEAR int (*write_key)(struct st_mi_sort_param *, IO_CACHE *,uchar *,
+ uint, uint);
+} MI_SORT_PARAM;
-typedef struct st_sort_info
-{
- my_off_t filelength,dupp,buff_length;
- ha_rows max_records;
- uint current_key, total_keys;
- myf myf_rw;
- enum data_file_type new_data_file_type;
- MI_INFO *info;
- MI_CHECK *param;
- uchar *buff;
- SORT_KEY_BLOCKS *key_block,*key_block_end;
- SORT_FT_BUF *ft_buf;
- /* sync things */
- uint got_error, threads_running;
-#ifdef THREAD
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-#endif
-} SORT_INFO;
/* functions in mi_check */
-void myisamchk_init(MI_CHECK *param);
-int chk_status(MI_CHECK *param, MI_INFO *info);
-int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag);
-int chk_size(MI_CHECK *param, MI_INFO *info);
-int chk_key(MI_CHECK *param, MI_INFO *info);
-int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend);
-int mi_repair(MI_CHECK *param, register MI_INFO *info,
+void myisamchk_init(HA_CHECK *param);
+int chk_status(HA_CHECK *param, MI_INFO *info);
+int chk_del(HA_CHECK *param, register MI_INFO *info, ulonglong test_flag);
+int chk_size(HA_CHECK *param, MI_INFO *info);
+int chk_key(HA_CHECK *param, MI_INFO *info);
+int chk_data_link(HA_CHECK *param, MI_INFO *info, my_bool extend);
+int mi_repair(HA_CHECK *param, register MI_INFO *info,
char * name, int rep_quick);
-int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name);
-int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
+int mi_sort_index(HA_CHECK *param, register MI_INFO *info, char * name);
+int mi_repair_by_sort(HA_CHECK *param, register MI_INFO *info,
const char * name, int rep_quick);
-int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
+int mi_repair_parallel(HA_CHECK *param, register MI_INFO *info,
const char * name, int rep_quick);
int change_to_newfile(const char * filename, const char * old_ext,
const char * new_ext, uint raid_chunks,
myf myflags);
-int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type,
+int lock_file(HA_CHECK *param, File file, my_off_t start, int lock_type,
const char *filetype, const char *filename);
-void lock_memory(MI_CHECK *param);
-void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
+void lock_memory(HA_CHECK *param);
+void update_auto_increment_key(HA_CHECK *param, MI_INFO *info,
my_bool repair);
-int update_state_info(MI_CHECK *param, MI_INFO *info,uint update);
+int update_state_info(HA_CHECK *param, MI_INFO *info,uint update);
void update_key_parts(MI_KEYDEF *keyinfo, ulong *rec_per_key_part,
ulonglong *unique, ulonglong *notnull,
ulonglong records);
-int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
+int filecopy(HA_CHECK *param, File to,File from,my_off_t start,
my_off_t length, const char *type);
int movepoint(MI_INFO *info,uchar *record,my_off_t oldpos,
my_off_t newpos, uint prot_key);
-int write_data_suffix(SORT_INFO *sort_info, my_bool fix_datafile);
+int write_data_suffix(MI_SORT_INFO *sort_info, my_bool fix_datafile);
int test_if_almost_full(MI_INFO *info);
-int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename);
+int recreate_table(HA_CHECK *param, MI_INFO **org_info, char *filename);
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, ulonglong key_map,
my_bool force);
@@ -506,6 +420,13 @@ void mi_change_key_cache(KEY_CACHE *old_key_cache,
KEY_CACHE *new_key_cache);
int mi_preload(MI_INFO *info, ulonglong key_map, my_bool ignore_leaves);
+int write_data_suffix(MI_SORT_INFO *sort_info, my_bool fix_datafile);
+int flush_pending_blocks(MI_SORT_PARAM *param);
+int sort_ft_buf_flush(MI_SORT_PARAM *sort_param);
+int thr_write_keys(MI_SORT_PARAM *sort_param);
+int sort_write_record(MI_SORT_PARAM *sort_param);
+int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ulong);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/myisamchk.h b/include/myisamchk.h
new file mode 100644
index 00000000000..f4651b81f8b
--- /dev/null
+++ b/include/myisamchk.h
@@ -0,0 +1,176 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Definitions needed for myisamchk/mariachk.c */
+
+/*
+ Entries marked as "QQ to be removed" are NOT used to
+ pass check/repair options to xxx_check.c. They are used
+ internally by xxxchk.c or/and ha_xxxx.cc and should NOT
+ be stored together with other flags. They should be removed
+ from the following list to make addition of new flags possible.
+*/
+
+#ifndef _myisamchk_h
+#define _myisamchk_h
+
+#define T_AUTO_INC 1
+#define T_AUTO_REPAIR 2 /* QQ to be removed */
+#define T_BACKUP_DATA 4
+#define T_CALC_CHECKSUM 8
+#define T_CHECK 16 /* QQ to be removed */
+#define T_CHECK_ONLY_CHANGED 32 /* QQ to be removed */
+#define T_CREATE_MISSING_KEYS 64
+#define T_DESCRIPT 128
+#define T_DONT_CHECK_CHECKSUM 256
+#define T_EXTEND 512
+#define T_FAST (1L << 10) /* QQ to be removed */
+#define T_FORCE_CREATE (1L << 11) /* QQ to be removed */
+#define T_FORCE_UNIQUENESS (1L << 12)
+#define T_INFO (1L << 13)
+#define T_MEDIUM (1L << 14)
+#define T_QUICK (1L << 15) /* QQ to be removed */
+#define T_READONLY (1L << 16) /* QQ to be removed */
+#define T_REP (1L << 17)
+#define T_REP_BY_SORT (1L << 18) /* QQ to be removed */
+#define T_REP_PARALLEL (1L << 19) /* QQ to be removed */
+#define T_RETRY_WITHOUT_QUICK (1L << 20)
+#define T_SAFE_REPAIR (1L << 21)
+#define T_SILENT (1L << 22)
+#define T_SORT_INDEX (1L << 23) /* QQ to be removed */
+#define T_SORT_RECORDS (1L << 24) /* QQ to be removed */
+#define T_STATISTICS (1L << 25)
+#define T_UNPACK (1L << 26)
+#define T_UPDATE_STATE (1L << 27)
+#define T_VERBOSE (1L << 28)
+#define T_VERY_SILENT (1L << 29)
+#define T_WAIT_FOREVER (1L << 30)
+#define T_WRITE_LOOP ((ulong) 1L << 31)
+#define T_ZEROFILL ((ulonglong) 1L << 32)
+#define T_ZEROFILL_KEEP_LSN ((ulonglong) 1L << 33)
+/** If repair should not bump create_rename_lsn */
+#define T_NO_CREATE_RENAME_LSN ((ulonglong) 1L << 33)
+
+#define T_REP_ANY (T_REP | T_REP_BY_SORT | T_REP_PARALLEL)
+
+/*
+ Flags used by xxxxchk.c or/and ha_xxxx.cc that are NOT passed
+ to xxxcheck.c follows:
+*/
+
+#define TT_USEFRM 1
+#define TT_FOR_UPGRADE 2
+
+#define O_NEW_INDEX 1 /* Bits set in out_flag */
+#define O_NEW_DATA 2
+#define O_DATA_LOST 4
+
+typedef struct st_sort_key_blocks /* Used when sorting */
+{
+ uchar *buff, *end_pos;
+ uchar lastkey[HA_MAX_POSSIBLE_KEY_BUFF];
+ uint last_length;
+ int inited;
+} SORT_KEY_BLOCKS;
+
+
+/*
+ MARIA/MYISAM supports several statistics collection
+ methods. Currently statistics collection method is not stored in
+ MARIA file and has to be specified for each table analyze/repair
+ operation in MI_CHECK::stats_method.
+*/
+
+typedef enum
+{
+ /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */
+ MI_STATS_METHOD_NULLS_NOT_EQUAL,
+ /* Treat NULLs as equal when collecting statistics (like 4.0 did) */
+ MI_STATS_METHOD_NULLS_EQUAL,
+ /* Ignore NULLs - count only tuples without NULLs in the index components */
+ MI_STATS_METHOD_IGNORE_NULLS
+} enum_handler_stats_method;
+
+
+typedef struct st_handler_check_param
+{
+ char *isam_file_name;
+ MY_TMPDIR *tmpdir;
+ void *thd;
+ const char *db_name, *table_name, *op_name;
+ ulonglong auto_increment_value;
+ ulonglong max_data_file_length;
+ ulonglong keys_in_use;
+ ulonglong max_record_length;
+ /*
+ The next two are used to collect statistics, see update_key_parts for
+ description.
+ */
+ ulonglong unique_count[HA_MAX_KEY_SEG + 1];
+ ulonglong notnull_count[HA_MAX_KEY_SEG + 1];
+
+ my_off_t search_after_block;
+ my_off_t new_file_pos, key_file_blocks;
+ my_off_t keydata, totaldata, key_blocks, start_check_pos;
+ my_off_t used, empty, splits, del_length, link_used, lost;
+ ha_rows total_records, total_deleted, records,del_blocks;
+ ha_rows full_page_count, tail_count;
+ ha_checksum record_checksum, glob_crc;
+ ha_checksum key_crc[HA_MAX_POSSIBLE_KEY];
+ ha_checksum tmp_key_crc[HA_MAX_POSSIBLE_KEY];
+ ha_checksum tmp_record_checksum;
+ ulonglong org_key_map;
+ ulonglong testflag;
+
+ /* Following is used to check if rows are visible */
+ ulonglong max_trid, max_found_trid;
+ ulonglong not_visible_rows_found;
+
+ size_t use_buffers, read_buffer_length, write_buffer_length;
+ size_t sort_buffer_length, sort_key_blocks;
+ ulong rec_per_key_part[HA_MAX_KEY_SEG * HA_MAX_POSSIBLE_KEY];
+ double new_rec_per_key_part[HA_MAX_KEY_SEG * HA_MAX_POSSIBLE_KEY];
+ uint out_flag, warning_printed, error_printed, verbose;
+ uint opt_sort_key, total_files, max_level;
+ uint key_cache_block_size, pagecache_block_size;
+ int tmpfile_createflag, err_count;
+ myf myf_rw;
+ uint8 language;
+ my_bool using_global_keycache, opt_lock_memory, opt_follow_links;
+ my_bool retry_repair, force_sort, calc_checksum, static_row_size;
+ char temp_filename[FN_REFLEN];
+ IO_CACHE read_cache;
+ enum_handler_stats_method stats_method;
+} HA_CHECK;
+
+
+typedef struct st_sort_ftbuf
+{
+ uchar *buf, *end;
+ int count;
+ uchar lastkey[HA_MAX_KEY_BUFF];
+} SORT_FT_BUF;
+
+
+typedef struct st_buffpek {
+ my_off_t file_pos; /* Where we are in the sort file */
+ uchar *base, *key; /* Key pointers */
+ ha_rows count; /* Number of rows in table */
+ ulong mem_count; /* numbers of keys in memory */
+ ulong max_keys; /* Max keys in buffert */
+} BUFFPEK;
+
+#endif /* _myisamchk_h */
diff --git a/include/myisampack.h b/include/myisampack.h
index 7d4871bd1cb..34a085e4e5a 100644
--- a/include/myisampack.h
+++ b/include/myisampack.h
@@ -24,58 +24,58 @@
#define mi_sint1korr(A) ((int8)(*A))
#define mi_uint1korr(A) ((uint8)(*A))
-#define mi_sint2korr(A) ((int16) (((int16) (((uchar*) (A))[1])) +\
- ((int16) ((int16) ((char*) (A))[0]) << 8)))
-#define mi_sint3korr(A) ((int32) (((((uchar*) (A))[0]) & 128) ? \
+#define mi_sint2korr(A) ((int16) (((int16) (((const uchar*) (A))[1])) +\
+ ((int16) ((int16) ((const char*) (A))[0]) << 8)))
+#define mi_sint3korr(A) ((int32) (((((const uchar*) (A))[0]) & 128) ? \
(((uint32) 255L << 24) | \
- (((uint32) ((uchar*) (A))[0]) << 16) |\
- (((uint32) ((uchar*) (A))[1]) << 8) | \
- ((uint32) ((uchar*) (A))[2])) : \
- (((uint32) ((uchar*) (A))[0]) << 16) |\
- (((uint32) ((uchar*) (A))[1]) << 8) | \
- ((uint32) ((uchar*) (A))[2])))
-#define mi_sint4korr(A) ((int32) (((int32) (((uchar*) (A))[3])) +\
- ((int32) (((uchar*) (A))[2]) << 8) +\
- ((int32) (((uchar*) (A))[1]) << 16) +\
- ((int32) ((int16) ((char*) (A))[0]) << 24)))
+ (((uint32) ((const uchar*) (A))[0]) << 16) |\
+ (((uint32) ((const uchar*) (A))[1]) << 8) | \
+ ((uint32) ((const uchar*) (A))[2])) : \
+ (((uint32) ((const uchar*) (A))[0]) << 16) |\
+ (((uint32) ((const uchar*) (A))[1]) << 8) | \
+ ((uint32) ((const uchar*) (A))[2])))
+#define mi_sint4korr(A) ((int32) (((int32) (((const uchar*) (A))[3])) +\
+ ((int32) (((const uchar*) (A))[2]) << 8) +\
+ ((int32) (((const uchar*) (A))[1]) << 16) +\
+ ((int32) ((int16) ((const char*) (A))[0]) << 24)))
#define mi_sint8korr(A) ((longlong) mi_uint8korr(A))
-#define mi_uint2korr(A) ((uint16) (((uint16) (((uchar*) (A))[1])) +\
- ((uint16) (((uchar*) (A))[0]) << 8)))
-#define mi_uint3korr(A) ((uint32) (((uint32) (((uchar*) (A))[2])) +\
- (((uint32) (((uchar*) (A))[1])) << 8) +\
- (((uint32) (((uchar*) (A))[0])) << 16)))
-#define mi_uint4korr(A) ((uint32) (((uint32) (((uchar*) (A))[3])) +\
- (((uint32) (((uchar*) (A))[2])) << 8) +\
- (((uint32) (((uchar*) (A))[1])) << 16) +\
- (((uint32) (((uchar*) (A))[0])) << 24)))
-#define mi_uint5korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[4])) +\
- (((uint32) (((uchar*) (A))[3])) << 8) +\
- (((uint32) (((uchar*) (A))[2])) << 16) +\
- (((uint32) (((uchar*) (A))[1])) << 24)) +\
- (((ulonglong) (((uchar*) (A))[0])) << 32))
-#define mi_uint6korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[5])) +\
- (((uint32) (((uchar*) (A))[4])) << 8) +\
- (((uint32) (((uchar*) (A))[3])) << 16) +\
- (((uint32) (((uchar*) (A))[2])) << 24)) +\
- (((ulonglong) (((uint32) (((uchar*) (A))[1])) +\
- (((uint32) (((uchar*) (A))[0]) << 8)))) <<\
+#define mi_uint2korr(A) ((uint16) (((uint16) (((const uchar*) (A))[1])) +\
+ ((uint16) (((const uchar*) (A))[0]) << 8)))
+#define mi_uint3korr(A) ((uint32) (((uint32) (((const uchar*) (A))[2])) +\
+ (((uint32) (((const uchar*) (A))[1])) << 8) +\
+ (((uint32) (((const uchar*) (A))[0])) << 16)))
+#define mi_uint4korr(A) ((uint32) (((uint32) (((const uchar*) (A))[3])) +\
+ (((uint32) (((const uchar*) (A))[2])) << 8) +\
+ (((uint32) (((const uchar*) (A))[1])) << 16) +\
+ (((uint32) (((const uchar*) (A))[0])) << 24)))
+#define mi_uint5korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[4])) +\
+ (((uint32) (((const uchar*) (A))[3])) << 8) +\
+ (((uint32) (((const uchar*) (A))[2])) << 16) +\
+ (((uint32) (((const uchar*) (A))[1])) << 24)) +\
+ (((ulonglong) (((const uchar*) (A))[0])) << 32))
+#define mi_uint6korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[5])) +\
+ (((uint32) (((const uchar*) (A))[4])) << 8) +\
+ (((uint32) (((const uchar*) (A))[3])) << 16) +\
+ (((uint32) (((const uchar*) (A))[2])) << 24)) +\
+ (((ulonglong) (((uint32) (((const uchar*) (A))[1])) +\
+ (((uint32) (((const uchar*) (A))[0]) << 8)))) <<\
32))
-#define mi_uint7korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[6])) +\
- (((uint32) (((uchar*) (A))[5])) << 8) +\
- (((uint32) (((uchar*) (A))[4])) << 16) +\
- (((uint32) (((uchar*) (A))[3])) << 24)) +\
- (((ulonglong) (((uint32) (((uchar*) (A))[2])) +\
- (((uint32) (((uchar*) (A))[1])) << 8) +\
- (((uint32) (((uchar*) (A))[0])) << 16))) <<\
+#define mi_uint7korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[6])) +\
+ (((uint32) (((const uchar*) (A))[5])) << 8) +\
+ (((uint32) (((const uchar*) (A))[4])) << 16) +\
+ (((uint32) (((const uchar*) (A))[3])) << 24)) +\
+ (((ulonglong) (((uint32) (((const uchar*) (A))[2])) +\
+ (((uint32) (((const uchar*) (A))[1])) << 8) +\
+ (((uint32) (((const uchar*) (A))[0])) << 16))) <<\
32))
-#define mi_uint8korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[7])) +\
- (((uint32) (((uchar*) (A))[6])) << 8) +\
- (((uint32) (((uchar*) (A))[5])) << 16) +\
- (((uint32) (((uchar*) (A))[4])) << 24)) +\
- (((ulonglong) (((uint32) (((uchar*) (A))[3])) +\
- (((uint32) (((uchar*) (A))[2])) << 8) +\
- (((uint32) (((uchar*) (A))[1])) << 16) +\
- (((uint32) (((uchar*) (A))[0])) << 24))) <<\
+#define mi_uint8korr(A) ((ulonglong)(((uint32) (((const uchar*) (A))[7])) +\
+ (((uint32) (((const uchar*) (A))[6])) << 8) +\
+ (((uint32) (((const uchar*) (A))[5])) << 16) +\
+ (((uint32) (((const uchar*) (A))[4])) << 24)) +\
+ (((ulonglong) (((uint32) (((const uchar*) (A))[3])) +\
+ (((uint32) (((const uchar*) (A))[2])) << 8) +\
+ (((uint32) (((const uchar*) (A))[1])) << 16) +\
+ (((uint32) (((const uchar*) (A))[0])) << 24))) <<\
32))
/* This one is for uniformity */
@@ -132,85 +132,85 @@
((uchar*) (T))[3]= ((uchar*) &A)[3]; }
#define mi_float4get(V,M) { float def_temp;\
- ((uchar*) &def_temp)[0]= ((uchar*) (M))[0];\
- ((uchar*) &def_temp)[1]= ((uchar*) (M))[1];\
- ((uchar*) &def_temp)[2]= ((uchar*) (M))[2];\
- ((uchar*) &def_temp)[3]= ((uchar*) (M))[3];\
+ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\
+ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[1]; \
+ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\
+ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\
(V)= def_temp; }
-#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((uchar*) &V)[0];\
- ((uchar*) (T))[1]= ((uchar*) &V)[1];\
- ((uchar*) (T))[2]= ((uchar*) &V)[2];\
- ((uchar*) (T))[3]= ((uchar*) &V)[3];\
- ((uchar*) (T))[4]= ((uchar*) &V)[4];\
- ((uchar*) (T))[5]= ((uchar*) &V)[5];\
- ((uchar*) (T))[6]= ((uchar*) &V)[6];\
- ((uchar*) (T))[7]= ((uchar*) &V)[7]; }
+#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[0];\
+ ((uchar*) (T))[1]= ((const uchar*) &V)[1];\
+ ((uchar*) (T))[2]= ((const uchar*) &V)[2];\
+ ((uchar*) (T))[3]= ((const uchar*) &V)[3];\
+ ((uchar*) (T))[4]= ((const uchar*) &V)[4];\
+ ((uchar*) (T))[5]= ((const uchar*) &V)[5];\
+ ((uchar*) (T))[6]= ((const uchar*) &V)[6];\
+ ((uchar*) (T))[7]= ((const uchar*) &V)[7]; }
#define mi_float8get(V,M) { double def_temp;\
- ((uchar*) &def_temp)[0]= ((uchar*) (M))[0];\
- ((uchar*) &def_temp)[1]= ((uchar*) (M))[1];\
- ((uchar*) &def_temp)[2]= ((uchar*) (M))[2];\
- ((uchar*) &def_temp)[3]= ((uchar*) (M))[3];\
- ((uchar*) &def_temp)[4]= ((uchar*) (M))[4];\
- ((uchar*) &def_temp)[5]= ((uchar*) (M))[5];\
- ((uchar*) &def_temp)[6]= ((uchar*) (M))[6];\
- ((uchar*) &def_temp)[7]= ((uchar*) (M))[7]; \
+ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\
+ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[1];\
+ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\
+ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\
+ ((uchar*) &def_temp)[4]= ((const uchar*) (M))[4];\
+ ((uchar*) &def_temp)[5]= ((const uchar*) (M))[5];\
+ ((uchar*) &def_temp)[6]= ((const uchar*) (M))[6];\
+ ((uchar*) &def_temp)[7]= ((const uchar*) (M))[7]; \
(V)= def_temp; }
#else
-#define mi_float4store(T,A) { ((uchar*) (T))[0]= ((uchar*) &A)[3];\
- ((uchar*) (T))[1]= ((uchar*) &A)[2];\
- ((uchar*) (T))[2]= ((uchar*) &A)[1];\
- ((uchar*) (T))[3]= ((uchar*) &A)[0]; }
+#define mi_float4store(T,A) { ((uchar*) (T))[0]= ((const uchar*) &A)[3];\
+ ((uchar*) (T))[1]= ((const uchar*) &A)[2];\
+ ((uchar*) (T))[2]= ((const uchar*) &A)[1];\
+ ((uchar*) (T))[3]= ((const uchar*) &A)[0]; }
#define mi_float4get(V,M) { float def_temp;\
- ((uchar*) &def_temp)[0]= ((uchar*) (M))[3];\
- ((uchar*) &def_temp)[1]= ((uchar*) (M))[2];\
- ((uchar*) &def_temp)[2]= ((uchar*) (M))[1];\
- ((uchar*) &def_temp)[3]= ((uchar*) (M))[0];\
+ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\
+ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\
+ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\
+ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\
(V)= def_temp; }
#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
-#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((uchar*) &V)[3];\
- ((uchar*) (T))[1]= ((uchar*) &V)[2];\
- ((uchar*) (T))[2]= ((uchar*) &V)[1];\
- ((uchar*) (T))[3]= ((uchar*) &V)[0];\
- ((uchar*) (T))[4]= ((uchar*) &V)[7];\
- ((uchar*) (T))[5]= ((uchar*) &V)[6];\
- ((uchar*) (T))[6]= ((uchar*) &V)[5];\
- ((uchar*) (T))[7]= ((uchar*) &V)[4];}
+#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[3];\
+ ((uchar*) (T))[1]= ((const uchar*) &V)[2];\
+ ((uchar*) (T))[2]= ((const uchar*) &V)[1];\
+ ((uchar*) (T))[3]= ((const uchar*) &V)[0];\
+ ((uchar*) (T))[4]= ((const uchar*) &V)[7];\
+ ((uchar*) (T))[5]= ((const uchar*) &V)[6];\
+ ((uchar*) (T))[6]= ((const uchar*) &V)[5];\
+ ((uchar*) (T))[7]= ((const uchar*) &V)[4];}
#define mi_float8get(V,M) { double def_temp;\
- ((uchar*) &def_temp)[0]= ((uchar*) (M))[3];\
- ((uchar*) &def_temp)[1]= ((uchar*) (M))[2];\
- ((uchar*) &def_temp)[2]= ((uchar*) (M))[1];\
- ((uchar*) &def_temp)[3]= ((uchar*) (M))[0];\
- ((uchar*) &def_temp)[4]= ((uchar*) (M))[7];\
- ((uchar*) &def_temp)[5]= ((uchar*) (M))[6];\
- ((uchar*) &def_temp)[6]= ((uchar*) (M))[5];\
- ((uchar*) &def_temp)[7]= ((uchar*) (M))[4];\
+ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\
+ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\
+ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\
+ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\
+ ((uchar*) &def_temp)[4]= ((const uchar*) (M))[7];\
+ ((uchar*) &def_temp)[5]= ((const uchar*) (M))[6];\
+ ((uchar*) &def_temp)[6]= ((const uchar*) (M))[5];\
+ ((uchar*) &def_temp)[7]= ((const uchar*) (M))[4];\
(V)= def_temp; }
#else
-#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((uchar*) &V)[7];\
- ((uchar*) (T))[1]= ((uchar*) &V)[6];\
- ((uchar*) (T))[2]= ((uchar*) &V)[5];\
- ((uchar*) (T))[3]= ((uchar*) &V)[4];\
- ((uchar*) (T))[4]= ((uchar*) &V)[3];\
- ((uchar*) (T))[5]= ((uchar*) &V)[2];\
- ((uchar*) (T))[6]= ((uchar*) &V)[1];\
- ((uchar*) (T))[7]= ((uchar*) &V)[0];}
+#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[7];\
+ ((uchar*) (T))[1]= ((const uchar*) &V)[6];\
+ ((uchar*) (T))[2]= ((const uchar*) &V)[5];\
+ ((uchar*) (T))[3]= ((const uchar*) &V)[4];\
+ ((uchar*) (T))[4]= ((const uchar*) &V)[3];\
+ ((uchar*) (T))[5]= ((const uchar*) &V)[2];\
+ ((uchar*) (T))[6]= ((const uchar*) &V)[1];\
+ ((uchar*) (T))[7]= ((const uchar*) &V)[0];}
#define mi_float8get(V,M) { double def_temp;\
- ((uchar*) &def_temp)[0]= ((uchar*) (M))[7];\
- ((uchar*) &def_temp)[1]= ((uchar*) (M))[6];\
- ((uchar*) &def_temp)[2]= ((uchar*) (M))[5];\
- ((uchar*) &def_temp)[3]= ((uchar*) (M))[4];\
- ((uchar*) &def_temp)[4]= ((uchar*) (M))[3];\
- ((uchar*) &def_temp)[5]= ((uchar*) (M))[2];\
- ((uchar*) &def_temp)[6]= ((uchar*) (M))[1];\
- ((uchar*) &def_temp)[7]= ((uchar*) (M))[0];\
+ ((uchar*) &def_temp)[0]= ((const uchar*) (M))[7];\
+ ((uchar*) &def_temp)[1]= ((const uchar*) (M))[6];\
+ ((uchar*) &def_temp)[2]= ((const uchar*) (M))[5];\
+ ((uchar*) &def_temp)[3]= ((const uchar*) (M))[4];\
+ ((uchar*) &def_temp)[4]= ((const uchar*) (M))[3];\
+ ((uchar*) &def_temp)[5]= ((const uchar*) (M))[2];\
+ ((uchar*) &def_temp)[6]= ((const uchar*) (M))[1];\
+ ((uchar*) &def_temp)[7]= ((const uchar*) (M))[0];\
(V)= def_temp; }
#endif /* __FLOAT_WORD_ORDER */
#endif /* WORDS_BIGENDIAN */
@@ -223,7 +223,7 @@
#else
#define mi_rowstore(T,A) { mi_int4store(T, 0);\
mi_int4store(((uchar*) (T) + 4), A); }
-#define mi_rowkorr(T) mi_uint4korr((uchar*) (T) + 4)
+#define mi_rowkorr(T) mi_uint4korr((const uchar*) (T) + 4)
#endif
#if SIZEOF_OFF_T > 4
@@ -234,5 +234,5 @@
bfill((char*) (T), 8, 255);\
else { mi_int4store((T), 0);\
mi_int4store(((T) + 4), A); }}
-#define mi_sizekorr(T) mi_uint4korr((uchar*) (T) + 4)
+#define mi_sizekorr(T) mi_uint4korr((const uchar*) (T) + 4)
#endif
diff --git a/include/mysql.h.pp b/include/mysql.h.pp
index 633cde41130..d9e9c7fa96d 100644
--- a/include/mysql.h.pp
+++ b/include/mysql.h.pp
@@ -98,12 +98,11 @@ unsigned long my_net_read(NET *net);
struct sockaddr;
int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen,
unsigned int timeout);
-struct rand_struct {
- unsigned long seed1,seed2,max_value;
- double max_value_dbl;
+struct my_rnd_struct;
+enum Item_result
+{
+ STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT
};
-enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT,
- DECIMAL_RESULT};
typedef struct st_udf_args
{
unsigned int arg_count;
@@ -124,10 +123,8 @@ typedef struct st_udf_init
my_bool const_item;
void *extension;
} UDF_INIT;
-void randominit(struct rand_struct *, unsigned long seed1,
- unsigned long seed2);
-double my_rnd(struct rand_struct *);
-void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st);
+void create_random_string(char *to, unsigned int length,
+ struct my_rnd_struct *rand_st);
void hash_password(unsigned long *to, const char *password, unsigned int password_len);
void make_scrambled_password_323(char *to, const char *password);
void scramble_323(char *to, const char *message, const char *password);
@@ -205,8 +202,8 @@ typedef unsigned long long my_ulonglong;
typedef struct st_used_mem
{
struct st_used_mem *next;
- unsigned int left;
- unsigned int size;
+ size_t left;
+ size_t size;
} USED_MEM;
typedef struct st_mem_root
{
diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h
index a978d44b918..fa38b90046d 100644
--- a/include/mysql/plugin.h
+++ b/include/mysql/plugin.h
@@ -676,7 +676,6 @@ int thd_in_lock_tables(const MYSQL_THD thd);
int thd_tablespace_op(const MYSQL_THD thd);
long long thd_test_options(const MYSQL_THD thd, long long test_options);
int thd_sql_command(const MYSQL_THD thd);
-const char *thd_proc_info(MYSQL_THD thd, const char *info);
void **thd_ha_data(const MYSQL_THD thd, const struct handlerton *hton);
int thd_tx_isolation(const MYSQL_THD thd);
char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length,
@@ -684,6 +683,10 @@ char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length,
/* Increments the row counter, see THD::row_count */
void thd_inc_row_count(MYSQL_THD thd);
+#define thd_proc_info(thd, msg) set_thd_proc_info(thd, msg, __func__, __FILE__, __LINE__)
+const char *set_thd_proc_info(MYSQL_THD, const char * info, const char *func,
+ const char *file, const unsigned int line);
+
/**
Create a temporary file.
diff --git a/include/mysql/plugin.h.pp b/include/mysql/plugin.h.pp
index 50511f515ab..c781bae9a97 100644
--- a/include/mysql/plugin.h.pp
+++ b/include/mysql/plugin.h.pp
@@ -116,12 +116,13 @@ int thd_in_lock_tables(const void* thd);
int thd_tablespace_op(const void* thd);
long long thd_test_options(const void* thd, long long test_options);
int thd_sql_command(const void* thd);
-const char *thd_proc_info(void* thd, const char *info);
void **thd_ha_data(const void* thd, const struct handlerton *hton);
int thd_tx_isolation(const void* thd);
char *thd_security_context(void* thd, char *buffer, unsigned int length,
unsigned int max_query_len);
void thd_inc_row_count(void* thd);
+const char *set_thd_proc_info(void*, const char * info, const char *func,
+ const char *file, const unsigned int line);
int mysql_tmpfile(const char *prefix);
int thd_killed(const void* thd);
unsigned long thd_get_thread_id(const void* thd);
diff --git a/include/mysql_com.h b/include/mysql_com.h
index db5a5eb8741..41941d01fd2 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -416,11 +416,7 @@ void my_net_set_read_timeout(NET *net, uint timeout);
struct sockaddr;
int my_connect(my_socket s, const struct sockaddr *name, unsigned int namelen,
unsigned int timeout);
-
-struct rand_struct {
- unsigned long seed1,seed2,max_value;
- double max_value_dbl;
-};
+struct my_rnd_struct;
#ifdef __cplusplus
}
@@ -428,8 +424,13 @@ struct rand_struct {
/* The following is for user defined functions */
-enum Item_result {STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT,
- DECIMAL_RESULT};
+enum Item_result
+{
+ STRING_RESULT=0, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT
+#ifdef MYSQL_SERVER
+ ,IMPOSSIBLE_RESULT /* Yes, we know this is ugly, don't tell us */
+#endif
+};
typedef struct st_udf_args
{
@@ -474,10 +475,8 @@ extern "C" {
implemented in sql/password.c
*/
-void randominit(struct rand_struct *, unsigned long seed1,
- unsigned long seed2);
-double my_rnd(struct rand_struct *);
-void create_random_string(char *to, unsigned int length, struct rand_struct *rand_st);
+void create_random_string(char *to, unsigned int length,
+ struct my_rnd_struct *rand_st);
void hash_password(unsigned long *to, const char *password, unsigned int password_len);
void make_scrambled_password_323(char *to, const char *password);
diff --git a/include/mysys_err.h b/include/mysys_err.h
index 09e77248c17..7167395f71f 100644
--- a/include/mysys_err.h
+++ b/include/mysys_err.h
@@ -62,7 +62,8 @@ extern const char * NEAR globerrs[]; /* my_error_messages is here */
#define EE_UNKNOWN_COLLATION 28
#define EE_FILENOTFOUND 29
#define EE_FILE_NOT_CLOSED 30
-#define EE_ERROR_LAST 30 /* Copy last error nr */
+#define EE_CANT_CHMOD 31
+#define EE_ERROR_LAST 31 /* Copy last error nr */
/* Add error numbers before EE_ERROR_LAST and change it accordingly. */
/* exit codes for all MySQL programs */
diff --git a/include/thr_lock.h b/include/thr_lock.h
index c7754ada299..261f596f911 100644
--- a/include/thr_lock.h
+++ b/include/thr_lock.h
@@ -131,11 +131,12 @@ typedef struct st_thr_lock {
/* write_lock_count is incremented for write locks and reset on read locks */
ulong write_lock_count;
uint read_no_write_count;
- void (*get_status)(void*, int); /* When one gets a lock */
+ void (*get_status)(void*, my_bool); /* When one gets a lock */
void (*copy_status)(void*,void*);
void (*update_status)(void*); /* Before release of write */
void (*restore_status)(void*); /* Before release of read */
my_bool (*check_status)(void *);
+ my_bool allow_multiple_concurrent_insert;
} THR_LOCK;
diff --git a/include/waiting_threads.h b/include/waiting_threads.h
new file mode 100644
index 00000000000..1e580529938
--- /dev/null
+++ b/include/waiting_threads.h
@@ -0,0 +1,130 @@
+/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _waiting_threads_h
+#define _waiting_threads_h
+
+#include <my_global.h>
+#include <my_sys.h>
+
+#include <lf.h>
+
+C_MODE_START
+
+typedef struct st_wt_resource_id WT_RESOURCE_ID;
+typedef struct st_wt_resource WT_RESOURCE;
+
+typedef struct st_wt_resource_type {
+ my_bool (*compare)(const void *a, const void *b);
+ const void *(*make_key)(const WT_RESOURCE_ID *id, uint *len); /* not used */
+} WT_RESOURCE_TYPE;
+
+struct st_wt_resource_id {
+ ulonglong value;
+ const WT_RESOURCE_TYPE *type;
+};
+/* the below differs from sizeof(WT_RESOURCE_ID) by the amount of padding */
+#define sizeof_WT_RESOURCE_ID (sizeof(ulonglong)+sizeof(void*))
+
+#define WT_WAIT_STATS 24
+#define WT_CYCLE_STATS 32
+extern ulonglong wt_wait_table[WT_WAIT_STATS];
+extern uint32 wt_wait_stats[WT_WAIT_STATS+1];
+extern uint32 wt_cycle_stats[2][WT_CYCLE_STATS+1];
+extern uint32 wt_success_stats;
+
+typedef struct st_wt_thd {
+ /*
+ XXX
+ there's no protection (mutex) against concurrent access of the
+ dynarray below. it is assumed that a caller will have it anyway
+ (not to protect this array but to protect its own - caller's -
+ data structures), and we'll get it for free. A caller needs to
+ ensure that a blocker won't release a resource before a blocked
+ thread starts waiting, which is usually done with a mutex.
+
+ If the above assumption is wrong, we'll need to add a mutex here.
+ */
+ DYNAMIC_ARRAY my_resources;
+ /*
+ 'waiting_for' is modified under waiting_for->lock, and only by thd itself
+ 'waiting_for' is read lock-free (using pinning protocol), but a thd object
+ can read its own 'waiting_for' without any locks or tricks.
+ */
+ WT_RESOURCE *waiting_for;
+ LF_PINS *pins;
+
+ /* pointers to values */
+ const ulong *timeout_short;
+ const ulong *deadlock_search_depth_short;
+ const ulong *timeout_long;
+ const ulong *deadlock_search_depth_long;
+
+ /*
+ weight relates to the desirability of a transaction being killed if it's
+ part of a deadlock. In a deadlock situation transactions with lower weights
+ are killed first.
+
+ Examples of using the weight to implement different selection strategies:
+
+ 1. Latest
+ Keep all weights equal.
+ 2. Random
+ Assight weights at random.
+ (variant: modify a weight randomly before every lock request)
+ 3. Youngest
+ Set weight to -NOW()
+ 4. Minimum locks
+ count locks granted in your lock manager, store the value as a weight
+ 5. Minimum work
+ depends on the definition of "work". For example, store the number
+ of rows modifies in this transaction (or a length of REDO log for a
+ transaction) as a weight.
+
+ It is only statistically relevant and is not protected by any locks.
+ */
+ ulong volatile weight;
+ /*
+ 'killed' is indirectly protected by waiting_for->lock because
+ a killed thread needs to clear its 'waiting_for' and thus needs a lock.
+ That is a thread needs an exclusive lock to read 'killed' reliably.
+ But other threads may change 'killed' from 0 to 1, a shared
+ lock is enough for that.
+ */
+ my_bool killed;
+#ifndef DBUG_OFF
+ const char *name;
+#endif
+} WT_THD;
+
+#define WT_TIMEOUT ETIMEDOUT
+#define WT_OK 0
+#define WT_DEADLOCK -1
+#define WT_DEPTH_EXCEEDED -2
+#define WT_FREE_TO_GO -3
+
+void wt_init(void);
+void wt_end(void);
+void wt_thd_lazy_init(WT_THD *, const ulong *, const ulong *, const ulong *, const ulong *);
+void wt_thd_destroy(WT_THD *);
+int wt_thd_will_wait_for(WT_THD *, WT_THD *, const WT_RESOURCE_ID *);
+int wt_thd_cond_timedwait(WT_THD *, pthread_mutex_t *);
+void wt_thd_release(WT_THD *, const WT_RESOURCE_ID *);
+#define wt_thd_release_all(THD) wt_thd_release((THD), 0)
+my_bool wt_resource_id_memcmp(const void *, const void *);
+
+C_MODE_END
+
+#endif
diff --git a/include/wqueue.h b/include/wqueue.h
new file mode 100644
index 00000000000..658f3d66f12
--- /dev/null
+++ b/include/wqueue.h
@@ -0,0 +1,27 @@
+
+#ifndef _wqueue_h
+#define _wqueue_h
+
+#include <my_global.h>
+#include <my_pthread.h>
+
+/* info about requests in a waiting queue */
+typedef struct st_pagecache_wqueue
+{
+ struct st_my_thread_var *last_thread; /* circular list of waiting
+ threads */
+} WQUEUE;
+
+#ifdef THREAD
+void wqueue_link_into_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
+void wqueue_unlink_from_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
+void wqueue_add_to_queue(WQUEUE *wqueue, struct st_my_thread_var *thread);
+void wqueue_add_and_wait(WQUEUE *wqueue,
+ struct st_my_thread_var *thread,
+ pthread_mutex_t *lock);
+void wqueue_release_queue(WQUEUE *wqueue);
+void wqueue_release_one_locktype_from_queue(WQUEUE *wqueue);
+
+#endif
+
+#endif
diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt
index 55138e4aa06..6e3e29e79b2 100755
--- a/libmysql/CMakeLists.txt
+++ b/libmysql/CMakeLists.txt
@@ -71,10 +71,10 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c
../strings/ctype-simple.c ../strings/ctype-sjis.c ../strings/ctype-tis620.c
../strings/ctype-uca.c ../strings/ctype-ucs2.c ../strings/ctype-ujis.c
../strings/ctype-utf8.c ../strings/ctype-win1250ch.c ../strings/ctype.c
- ../mysys/default.c errmsg.c ../mysys/errors.c
+ ../mysys/default.c errmsg.c ../mysys/errors.c ../mysys/my_sync.c
../mysys/hash.c ../mysys/my_sleep.c ../mysys/default_modify.c
get_password.c ../strings/int2str.c ../strings/is_prefix.c
- libmysql.c ../mysys/list.c ../strings/llstr.c
+ libmysql.c ../mysys/list.c ../strings/llstr.c ../mysys/my_rnd.c
../strings/longlong2str.c manager.c ../mysys/mf_arr_appstr.c ../mysys/mf_cache.c
../mysys/mf_dirname.c ../mysys/mf_fn_ext.c ../mysys/mf_format.c
../mysys/mf_iocache.c ../mysys/mf_iocache2.c ../mysys/mf_loadpath.c
diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared
index 43e86ea31e8..cbee8673164 100644
--- a/libmysql/Makefile.shared
+++ b/libmysql/Makefile.shared
@@ -66,7 +66,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
my_compress.lo array.lo my_once.lo list.lo my_net.lo \
charset.lo charset-def.lo hash.lo mf_iocache.lo \
mf_iocache2.lo my_seek.lo my_sleep.lo \
- my_pread.lo mf_cache.lo md5.lo sha1.lo \
+ my_pread.lo mf_cache.lo md5.lo sha1.lo my_rnd.lo \
my_getopt.lo my_gethostbyname.lo my_port.lo \
my_rename.lo my_chsize.lo my_sync.lo my_getsystime.lo
sqlobjects = net.lo
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index ca329eadf0f..c01f34b422c 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -4408,7 +4408,6 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field)
field->max_length= 10; /* 2003-11-11 */
param->skip_result= skip_result_with_length;
break;
- break;
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
param->skip_result= skip_result_with_length;
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 1582f0898d8..ee08721b27c 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -145,6 +145,13 @@ IF(WITH_CSV_STORAGE_ENGINE)
ENDFOREACH(rpath)
ENDIF(WITH_CSV_STORAGE_ENGINE)
+IF(WITH_MARIA_STORAGE_ENGINE)
+ INCLUDE(${CMAKE_SOURCE_DIR}/storage/maria/CMakeLists.txt)
+ FOREACH(rpath ${MARIA_SOURCES})
+ SET(LIB_SOURCES ${LIB_SOURCES} ../storage/maria/${rpath})
+ ENDFOREACH(rpath)
+ENDIF(WITH_MARIA_STORAGE_ENGINE)
+
SET(SOURCE_SUBLIBS FALSE)
SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
diff --git a/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test b/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test
index 0baf49c9fac..5ed2f1ac2b8 100644
--- a/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test
+++ b/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test
@@ -8,9 +8,9 @@ source include/master-slave.inc;
let $SERVER_VERSION=`select version()`;
-create table t1 (a int);
+create table t1 (a int) ENGINE=MyISAM;
insert into t1 values (10);
-create table t2 (a int);
+create table t2 (a int) ENGINE=MyISAM;
create table t3 (a int) engine=merge union(t1);
create table t4 (a int);
# We force the slave to open t3 (because we want to try confusing him) with this :
diff --git a/mysql-test/extra/rpl_tests/rpl_insert_delayed.test b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test
index e492903afad..16e6bb3c960 100644
--- a/mysql-test/extra/rpl_tests/rpl_insert_delayed.test
+++ b/mysql-test/extra/rpl_tests/rpl_insert_delayed.test
@@ -17,7 +17,7 @@ select @@global.binlog_format;
# happened only in statement-based binlogging.
#
-CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
let $query = "INSERT DELAYED INTO t1 VALUES (null, 'Dr. No'), (null, 'From Russia With Love'), (null, 'Goldfinger'), (null, 'Thunderball'), (null, 'You Only Live Twice')";
--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=200 --query=$query --delimiter=";"
diff --git a/mysql-test/include/have_maria.inc b/mysql-test/include/have_maria.inc
new file mode 100644
index 00000000000..474e9db12b9
--- /dev/null
+++ b/mysql-test/include/have_maria.inc
@@ -0,0 +1,4 @@
+disable_query_log;
+--require r/true.require
+select (support = 'YES' or support = 'DEFAULT') as `TRUE` from information_schema.engines where engine = 'maria';
+enable_query_log;
diff --git a/mysql-test/include/maria_empty_logs.inc b/mysql-test/include/maria_empty_logs.inc
new file mode 100644
index 00000000000..00f92010bd0
--- /dev/null
+++ b/mysql-test/include/maria_empty_logs.inc
@@ -0,0 +1,84 @@
+# Maria help script.
+# Cleans up all logs to give recovery a fresh start.
+
+# API: set mel_keep_control_file=1 if want to keep control file;
+# uses vardir, port and socket.
+
+connection default;
+let $default_db=`select database()`;
+let $MYSQLD_DATADIR= `SELECT @@datadir`;
+# it will used at end of test for wait_for_status_var.inc primitive
+let $status_var= Threads_connected;
+let $status_var_value= query_get_value(SHOW STATUS LIKE 'Threads_connected', Value, 1);
+
+connection admin;
+-- echo * shut down mysqld, removed logs, restarted it
+append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+wait-maria_empty_logs.inc
+EOF
+
+--source include/mysqladmin_shutdown.inc
+
+if (!$mel_keep_control_file)
+{
+ --error 0,1
+ remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log_control;
+}
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000001;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000002;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000003;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000004;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000005;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000006;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000007;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000008;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000009;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000010;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000011;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000012;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000013;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000014;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000015;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000016;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000017;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000018;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000019;
+-- error 0,1
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000020;
+# hope there are not more than these logs...
+
+-- error 0,1
+remove_file $MYSQLD_DATADIR/maria_recovery.trace;
+
+append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+restart-maria_empty_logs.inc
+EOF
+
+--source include/wait_until_connected_again.inc
+
+connection default;
+# Make sure that all connections are restored
+--source include/wait_for_status_var.inc
+# Restore current database as the effect of "use" was lost after restart
+--disable_query_log
+eval use $default_db;
+--enable_query_log
diff --git a/mysql-test/include/maria_make_snapshot.inc b/mysql-test/include/maria_make_snapshot.inc
new file mode 100644
index 00000000000..2f480ac1a45
--- /dev/null
+++ b/mysql-test/include/maria_make_snapshot.inc
@@ -0,0 +1,49 @@
+# Maria helper script
+# Copies table' data and index file to other directory, or back, or compares.
+# The other directory looks like a database directory, so that we can
+# read copies from inside mysqld, that's also why we copy the frm.
+
+# "mms" is a namespace for Maria_Make_Snapshot
+
+# API:
+# 1) set one of
+# $mms_copy : to copy table from database to spare directory
+# $mms_reverse : to copy it back
+# $mms_compare_physically : to compare both byte-for-byte
+# 2) set $mms_tname to a string and set $mms_table_to_use to a number: tables
+# will be mysqltest.$mms_tname$mms_table_to_use.
+# 3) set $mms_purpose to say what this copy is for (influences the naming
+# of the spare directory).
+
+if ($mms_copy)
+{
+ --echo * copied $mms_tname$mms_table_to_use for $mms_purpose
+ copy_file $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAD $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAD;
+ copy_file $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAI $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAI;
+ copy_file $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.frm $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.frm;
+}
+
+if ($mms_reverse_copy)
+{
+ # do not call this without flushing target table first!
+ --echo * copied $mms_tname$mms_table_to_use back for $mms_purpose
+ -- error 0,1
+ remove_file $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAD;
+ copy_file $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAD $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAD;
+ -- error 0,1
+ remove_file $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAI;
+ copy_file $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAI $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAI;
+}
+
+if ($mms_compare_physically)
+{
+ # After the UNDO phase this is normally impossible
+ # (UNDO execution has created new log records => pages have new LSNs).
+ # So, do this only when testing REDO phase.
+ # If UNDO phase, we nevertheless compare checksums
+ # (see maria_verify_recovery.inc).
+ --echo * compared $mms_tname$mms_table_to_use to old version
+ diff_files $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAD $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAD;
+# index file not yet recovered
+# diff_files $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAI $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAI;
+}
diff --git a/mysql-test/include/maria_make_snapshot_for_comparison.inc b/mysql-test/include/maria_make_snapshot_for_comparison.inc
new file mode 100644
index 00000000000..cb756f60527
--- /dev/null
+++ b/mysql-test/include/maria_make_snapshot_for_comparison.inc
@@ -0,0 +1,31 @@
+# Maria helper script
+# Copies clean tables' data and index file to other directory
+# Tables are $mms_tname1...$mms_tname[$mms_tables]
+# They are later used as a reference to see if recovery works.
+
+# API:
+# set $mms_tname to a string, and $mms_tables to a number N, the script will
+# cover tables mysqltest.$mms_tname1,...$mms_tnameN
+
+connection admin;
+
+let $mms_table_to_use=$mms_tables;
+let $mms_purpose=comparison;
+let $mms_copy=1;
+
+--disable_query_log
+--disable_warnings
+eval drop database if exists mysqltest_for_$mms_purpose;
+--enable_warnings
+eval create database mysqltest_for_$mms_purpose;
+--enable_query_log
+
+while ($mms_table_to_use)
+{
+ # to serve as a reference, table must be in a clean state
+ eval flush table $mms_tname$mms_table_to_use;
+ -- source include/maria_make_snapshot.inc
+ dec $mms_table_to_use;
+}
+let $mms_copy=0;
+connection default;
diff --git a/mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc b/mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc
new file mode 100644
index 00000000000..62f5250cab4
--- /dev/null
+++ b/mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc
@@ -0,0 +1,38 @@
+# Maria helper script
+# Copies tables' data and index file to other directory, and control file.
+# Tables are $mms_tname1...$mms_tname[$mms_tables].
+# Later, mysqld is shutdown, and that snapshot is put back into the
+# datadir, control file too ("flashing recovery's brain"), and recovery is let
+# to run on it (see maria_verify_recovery.inc).
+
+# API:
+# set $mms_tname to a string, and $mms_tables to a number N, the script will
+# cover tables mysqltest.$mms_tname1,...$mms_tnameN
+
+
+connection admin;
+
+let $mms_table_to_use=$mms_tables;
+let $mms_purpose=feeding_recovery;
+let $mms_copy=1;
+
+--disable_query_log
+--disable_warnings
+eval drop database if exists mysqltest_for_$mms_purpose;
+--enable_warnings
+eval create database mysqltest_for_$mms_purpose;
+--enable_query_log
+
+while ($mms_table_to_use)
+{
+ -- source include/maria_make_snapshot.inc
+ dec $mms_table_to_use;
+}
+let $mms_copy=0;
+
+let $MYSQLD_DATADIR= `SELECT @@datadir`;
+-- error 0,1
+remove_file $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control;
+copy_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log_control $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control;
+
+connection default;
diff --git a/mysql-test/include/maria_verify_recovery.inc b/mysql-test/include/maria_verify_recovery.inc
new file mode 100644
index 00000000000..e8354c43837
--- /dev/null
+++ b/mysql-test/include/maria_verify_recovery.inc
@@ -0,0 +1,97 @@
+# Maria helper script.
+# Runs recovery, compare with expected table data.
+
+# API:
+# 1) set $mms_tname to a string, and $mms_tables to a number N, the script
+# will cover tables mysqltest.$mms_tname1,...$mms_tnameN
+# 2) set $mvr_debug_option to the crash way
+# 3) set $mvr_crash_statement to the statement which will trigger a crash
+# 4) set $mvr_restore_old_snapshot to 1 if you want recovery to run on
+# an old copy of tables and of the control file, 0 for normal recovery.
+# 5) set $mms_compare_physically to 1 if you want a physical byte-for-byte
+# comparison with expected table. Checksum comparison is always done.
+# "mvr" is a namespace for Maria_Verify_Recovery
+
+connection admin;
+
+# we may do a copy-back of tables before comparison, so save comparison
+# request made by caller:
+let $mms_compare_physically_save=$mms_compare_physically;
+let $mms_compare_physically=0;
+
+# warn mtr that mysqld is going to die and should not be restarted immediately
+#append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+#wait-maria_verify_recovery.inc
+#EOF
+# todo: remove this "system" and uncomment above when BUG#32296 is fixed
+system echo wait-maria_verify_recovery.inc >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+
+# flush page cache and log, only log, or nothing, and kill mysqld with
+# abort().
+# When we restore an old snapshot, we could just kill mysqld nicely,
+# but that would implicitely commit all work, which the tester may
+# not want (tester may want to observe rollback happening).
+
+eval SET SESSION debug=$mvr_debug_option;
+--echo * crashing mysqld intentionally
+--error 2013
+eval $mvr_crash_statement; # this will crash (DBUG magic)
+
+if ($mvr_restore_old_snapshot)
+{
+
+ # copy snapshot made by maria_make_snapshot_for_feeding_recovery back
+ # into datadir.
+
+ let $mms_table_to_use=$mms_tables;
+ let $mms_purpose=feeding_recovery;
+ let $mms_reverse_copy=1;
+ while ($mms_table_to_use)
+ {
+ -- source include/maria_make_snapshot.inc
+ dec $mms_table_to_use;
+ }
+ let $mms_reverse_copy=0;
+
+ # also copy back control file, to force recovery to start from an early
+ # point, ignoring further checkpoints.
+ -- error 0,1
+ remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log_control;
+ copy_file $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control $MYSQLD_DATADIR/$MARIA_LOG/maria_log_control;
+}
+
+--echo * recovery happens
+# let mtr restart mysqld (and thus execute the maria log)
+#append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+#restart-maria_verify_recovery.inc
+#EOF
+system echo restart-maria_verify_recovery.inc >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+
+--source include/wait_until_connected_again.inc
+
+# Compare that tables of $mms_tables are identical to old.
+# We always compare with CHECKSUM TABLE, and if requested (which makes sense
+# only for testing the REDO phase, as UNDO phase generates new records so new
+# LSNs on pages.) with a physical byte-for-byte comparison.
+let $mms_table_to_use=$mms_tables;
+let $mms_purpose=comparison;
+let $mms_compare_physically=$mms_compare_physically_save;
+while ($mms_table_to_use)
+{
+ eval check table $mms_tname$mms_table_to_use extended;
+ --echo * testing that checksum after recovery is as expected
+ let $new_checksum=`CHECKSUM TABLE $mms_tname$mms_table_to_use`;
+ let $old_checksum=`CHECKSUM TABLE mysqltest_for_$mms_purpose.$mms_tname$mms_table_to_use`;
+ # the $ text variables above are of the form "db.tablename\tchecksum",
+ # as db differs, we use substring().
+ --disable_query_log
+ eval select if(substring("$new_checksum",instr("$new_checksum",".t1")) = substring("$old_checksum",instr("$old_checksum",".t1")),"ok","failure") as "Checksum-check";
+ --enable_query_log
+ # this script may compare physically or do nothing
+ -- source include/maria_make_snapshot.inc
+ dec $mms_table_to_use;
+}
+
+connection default;
+# the effect of "use" is lost after a restart so we are back into db "test"
+use mysqltest;
diff --git a/mysql-test/include/mysqladmin_shutdown.inc b/mysql-test/include/mysqladmin_shutdown.inc
new file mode 100644
index 00000000000..16b33c2baf8
--- /dev/null
+++ b/mysql-test/include/mysqladmin_shutdown.inc
@@ -0,0 +1,7 @@
+# Initiates a clean shutdown of the server and waits for its completion
+
+--exec $MYSQLADMIN --no-defaults -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= shutdown 2>&1;
+
+# On Windows mysqladmin does not wait for shutdown to be finished,
+# so we have to monitor this with our connection:
+--source include/wait_until_disconnected.inc
diff --git a/mysql-test/include/ps_conv.inc b/mysql-test/include/ps_conv.inc
index 195d1061664..8cbe9450063 100644
--- a/mysql-test/include/ps_conv.inc
+++ b/mysql-test/include/ps_conv.inc
@@ -52,7 +52,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
-create table t5 as select
+eval create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
diff --git a/mysql-test/include/varchar.inc b/mysql-test/include/varchar.inc
index 15306ed8385..7accbd151a9 100644
--- a/mysql-test/include/varchar.inc
+++ b/mysql-test/include/varchar.inc
@@ -11,6 +11,11 @@ enable_query_log;
# Simple basic test that endspace is saved
#
+#
+# Remember to check that one doesn't get a warning or a note
+# from a char field when end spaces get removed. SQL standard!
+#
+
create table t1 (v varchar(10), c char(10), t text);
insert into t1 values('+ ', '+ ', '+ ');
set @a=repeat(' ',20);
diff --git a/mysql-test/include/wait_for_status_var.inc b/mysql-test/include/wait_for_status_var.inc
new file mode 100644
index 00000000000..4c168da7f1a
--- /dev/null
+++ b/mysql-test/include/wait_for_status_var.inc
@@ -0,0 +1,68 @@
+# ==== Purpose ====
+#
+# Waits until a variable from SHOW STATUS has returned a specified
+# value, or until a timeout is reached.
+#
+# ==== Usage ====
+#
+# let $status_var= Threads_connected;
+# let $status_var_value= 1;
+# --source include/wait_for_status_var.inc
+#
+# Parameters:
+#
+# $status_var, $status_var_value
+# This macro will wait until the variable of SHOW STATUS
+# named $status_var gets the value $status_var_value. See
+# the example above.
+#
+# $status_type= GLOBAL|SESSION
+# To specify the type (attribute) of status variable and
+# run either SHOW GLOBAL STATUS or SHOW SESSION STATUS.
+#
+# $status_var_comparsion
+# By default, this file waits until $status_var becomes equal to
+# $status_var_value. If you want to wait until $status_var
+# becomes *unequal* to $status_var_value, set this parameter to the
+# string '!=', like this:
+# let $status_var_comparsion= !=;
+#
+# $status_timeout
+# The default timeout is 1 minute. You can change the timeout by
+# setting $status_timeout. The unit is tenths of seconds.
+#
+
+if (`SELECT STRCMP('$status_type', '') * STRCMP(UPPER('$status_type'), 'SESSION') * STRCMP(UPPER('$status_type'), 'GLOBAL')`)
+{
+ --echo **** ERROR: Unknown type of variable status_type: allowed values are: SESSION or GLOBAL ****
+ exit;
+}
+
+let $_status_timeout_counter= $status_timeout;
+if (!$_status_timeout_counter)
+{
+ let $_status_timeout_counter= 600;
+}
+
+let $_status_var_comparsion= $status_var_comparsion;
+if (`SELECT '$_status_var_comparsion' = ''`)
+{
+ let $_status_var_comparsion= =;
+}
+
+let $_show_status_value= query_get_value("SHOW $status_type STATUS LIKE '$status_var'", Value, 1);
+while (`SELECT NOT('$_show_status_value' $_status_var_comparsion '$status_var_value')`)
+{
+ if (!$_status_timeout_counter)
+ {
+ --echo **** ERROR: failed while waiting for $status_type $status_var $_status_var_comparison $status_var_value ****
+ --echo Note: the following output may have changed since the failure was detected
+ --echo **** Showing STATUS, PROCESSLIST ****
+ eval SHOW $status_type STATUS LIKE '$status_var';
+ SHOW PROCESSLIST;
+ exit;
+ }
+ dec $_status_timeout_counter;
+ sleep 0.1;
+ let $_show_status_value= query_get_value("SHOW $status_type STATUS LIKE '$status_var'", Value, 1);
+}
diff --git a/mysql-test/include/wait_until_connected_again.inc b/mysql-test/include/wait_until_connected_again.inc
index c7bb774929a..aff92141a8b 100644
--- a/mysql-test/include/wait_until_connected_again.inc
+++ b/mysql-test/include/wait_until_connected_again.inc
@@ -1,9 +1,13 @@
#
# Include this script to wait until the connection to the
-# server has been restored or timeout occurs
+# server has been restored or timeout occurs.
+# You should have done --enable_reconnect first
+# When you change this file you may have to chance its cousin
+# wait_until_disconnected.inc
+
--disable_result_log
--disable_query_log
-let $counter= 500;
+let $counter= 5000;
let $mysql_errno= 9999;
while ($mysql_errno)
{
diff --git a/mysql-test/include/wait_until_disconnected.inc b/mysql-test/include/wait_until_disconnected.inc
index a4362e52d01..941a65a1efb 100644
--- a/mysql-test/include/wait_until_disconnected.inc
+++ b/mysql-test/include/wait_until_disconnected.inc
@@ -1,13 +1,16 @@
#
# Include this script to wait until the connection to the
-# server has been dropped
+# server has been dropped.
--disable_result_log
--disable_query_log
-let $counter= 500;
+let $counter= 600;
let $mysql_errno= 0;
while (!$mysql_errno)
{
- --error 0,1053,2002,2006,2013
+ # Strangely enough, the server might return "Too many connections"
+ # while being shutdown, thus 1040 is an "allowed" error.
+ # See BUG#36228.
+ --error 0,1040,1053,2002,2003,2006,2013
show status;
dec $counter;
@@ -15,7 +18,7 @@ while (!$mysql_errno)
{
--die Server failed to dissapear
}
- --sleep 0.1
+ --real_sleep 0.1
}
--enable_query_log
--enable_result_log
diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm
index 23a85ef7ecc..34d24270eb6 100644
--- a/mysql-test/lib/mtr_cases.pm
+++ b/mysql-test/lib/mtr_cases.pm
@@ -93,6 +93,7 @@ sub init_pattern {
sub collect_test_cases ($$) {
my $suites= shift; # Semicolon separated list of test suites
+ my %found_suites;
my $opt_cases= shift;
my $cases= []; # Array of hash(one hash for each testcase)
@@ -102,6 +103,7 @@ sub collect_test_cases ($$) {
foreach my $suite (split(",", $suites))
{
push(@$cases, collect_one_suite($suite, $opt_cases));
+ $found_suites{$suite}= 1;
}
if ( @$opt_cases )
@@ -113,6 +115,12 @@ sub collect_test_cases ($$) {
{
my $found= 0;
my ($sname, $tname, $extension)= split_testname($test_name_spec);
+ if (defined($sname) && !defined($found_suites{$sname}))
+ {
+ $found_suites{$sname}= 1;
+ push(@$cases, collect_one_suite($sname));
+ }
+
foreach my $test ( @$cases )
{
# test->{name} is always in suite.name format
@@ -572,6 +580,36 @@ sub optimize_cases {
if ( $default_engine =~ /^innodb/i );
}
}
+
+ # =======================================================
+ # Check that engine selected by
+ # --default-storage-engine=<engine> is supported
+ # =======================================================
+ my %builtin_engines = ('myisam' => 1, 'memory' => 1);
+
+ foreach my $opt ( @{$tinfo->{master_opt}} ) {
+ my $default_engine=
+ mtr_match_prefix($opt, "--default-storage-engine=");
+
+ if (defined $default_engine){
+
+
+ my $engine_value= $::mysqld_variables{$default_engine};
+
+ if ( ! exists $::mysqld_variables{$default_engine} and
+ ! exists $builtin_engines{$default_engine} )
+ {
+ $tinfo->{'skip'}= 1;
+ $tinfo->{'comment'}=
+ "'$default_engine' not supported";
+ }
+
+ $tinfo->{'ndb_test'}= 1
+ if ( $default_engine =~ /^ndb/i );
+ $tinfo->{'innodb_test'}= 1
+ if ( $default_engine =~ /^innodb/i );
+ }
+ }
}
}
@@ -644,6 +682,7 @@ sub process_opts_file {
}
}
+
##############################################################################
#
# Collect information about a single test case
@@ -836,14 +875,14 @@ sub collect_one_test_case {
if ( $tinfo->{'big_test'} and ! $::opt_big_test )
{
$tinfo->{'skip'}= 1;
- $tinfo->{'comment'}= "Test need 'big-test' option";
+ $tinfo->{'comment'}= "Test needs 'big-test' option";
return $tinfo
}
if ( $tinfo->{'need_debug'} && ! $::debug_compiled_binaries )
{
$tinfo->{'skip'}= 1;
- $tinfo->{'comment'}= "Test need debug binaries";
+ $tinfo->{'comment'}= "Test needs debug binaries";
return $tinfo
}
@@ -906,7 +945,7 @@ sub collect_one_test_case {
if (grep(/^--skip-log-bin/, @::opt_extra_mysqld_opt) )
{
$tinfo->{'skip'}= 1;
- $tinfo->{'comment'}= "Test need binlog";
+ $tinfo->{'comment'}= "Test needs binlog";
return $tinfo;
}
}
diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm
index ce3fba87385..f385379cfff 100644
--- a/mysql-test/lib/mtr_report.pm
+++ b/mysql-test/lib/mtr_report.pm
@@ -257,10 +257,9 @@ sub mtr_report_stats ($) {
{
mtr_warning("Got errors/warnings while running tests, please examine",
"'$warnlog' for details.");
- }
+ }
print "\n";
-
# Print a list of check_testcases that failed(if any)
if ( $::opt_check_testcases )
{
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 30eab135b24..dbbc68527a7 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -115,9 +115,12 @@ my $path_config_file; # The generated config file, var/my.cnf
# executables will be used by the test suite.
our $opt_vs_config = $ENV{'MTR_VS_CONFIG'};
-my $DEFAULT_SUITES= "main,binlog,federated,rpl,rpl_ndb,ndb";
-my $opt_suites;
+my $DEFAULT_SUITES= "main,binlog,federated,rpl,rpl_ndb,ndb,maria";
+our $opt_usage;
+our $opt_suites;
+our $opt_suites_default= "main,backup,backup_engines,binlog,rpl,rpl_ndb,ndb"; # Default suites to run
+our $opt_script_debug= 0; # Script debugging, enable with --script-debug
our $opt_verbose= 0; # Verbose output, enable with --verbose
our $exe_mysql;
our $exe_mysqladmin;
@@ -129,6 +132,7 @@ our $opt_big_test= 0;
our @opt_combinations;
our @opt_extra_mysqld_opt;
+our @opt_extra_mysqltest_opt;
my $opt_compress;
my $opt_ssl;
@@ -180,10 +184,10 @@ my $opt_mark_progress;
my $opt_sleep;
-my $opt_testcase_timeout= 15; # minutes
-my $opt_suite_timeout = 300; # minutes
-my $opt_shutdown_timeout= 10; # seconds
-my $opt_start_timeout = 180; # seconds
+my $opt_testcase_timeout= 15; # 15 minutes
+my $opt_suite_timeout = 360; # 6 hours
+my $opt_shutdown_timeout= 10; # 10 seconds
+my $opt_start_timeout = 180; # 180 seconds
sub testcase_timeout { return $opt_testcase_timeout * 60; };
sub suite_timeout { return $opt_suite_timeout * 60; };
@@ -206,6 +210,7 @@ my @default_valgrind_args= ("--show-reachable=yes");
my @valgrind_args;
my $opt_valgrind_path;
my $opt_callgrind;
+my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions.
our $opt_warnings= 1;
@@ -260,6 +265,11 @@ sub main {
"mysql-5.1-telco-6.2-merge" => "ndb_team",
"mysql-5.1-telco-6.3" => "ndb_team",
"mysql-6.0-ndb" => "ndb_team",
+ "mysql-6.0-falcon" => "falcon_team",
+ "mysql-6.0-falcon-team" => "falcon_team",
+ "mysql-6.0-falcon-wlad" => "falcon_team",
+ "mysql-6.0-falcon-chris" => "falcon_team",
+ "mysql-6.0-falcon-kevin" => "falcon_team",
);
foreach my $dir ( reverse splitdir($basedir) ) {
@@ -806,6 +816,9 @@ sub command_line_setup {
# Extra options used when starting mysqld
'mysqld=s' => \@opt_extra_mysqld_opt,
+ # Extra options used when starting mysqltest
+ 'mysqltest=s' => \@opt_extra_mysqltest_opt,
+
# Run test on running server
'extern=s' => \%opts_extern, # Append to hash
@@ -844,6 +857,7 @@ sub command_line_setup {
'valgrind-option=s' => \@valgrind_args,
'valgrind-path=s' => \$opt_valgrind_path,
'callgrind' => \$opt_callgrind,
+ 'debug-sync-timeout=i' => \$opt_debug_sync_timeout,
# Directories
'tmpdir=s' => \$opt_tmpdir,
@@ -1547,6 +1561,18 @@ sub client_arguments ($) {
}
+sub mysqlbinlog_arguments () {
+ my $exe= mtr_exe_exists("$path_client_bindir/mysqlbinlog");
+
+ my $args;
+ mtr_init_args(\$args);
+ mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
+ mtr_add_arg($args, "--local-load=%s", $opt_tmpdir);
+ client_debug_arg($args, "mysqlbinlog");
+ return mtr_args2str($exe, @$args);
+}
+
+
sub mysqlslap_arguments () {
my $exe= mtr_exe_maybe_exists("$path_client_bindir/mysqlslap");
if ( $exe eq "" ) {
@@ -1606,6 +1632,24 @@ sub mysql_client_test_arguments(){
return mtr_args2str($exe, @$args);
}
+sub tool_arguments ($$) {
+ my($sedir, $tool_name) = @_;
+ my $exe= my_find_bin($basedir,
+ [$sedir, "bin"],
+ $tool_name);
+
+ my $args;
+ mtr_init_args(\$args);
+ client_debug_arg($args, $tool_name);
+ return mtr_args2str($exe, @$args);
+}
+
+
+sub have_maria_support () {
+ my $maria_var= $mysqld_variables{'maria'};
+ return defined $maria_var and $maria_var eq 'TRUE';
+}
+
#
# Set environment to be used by childs of this process for
@@ -1791,7 +1835,7 @@ sub environment_setup {
$ENV{'MYSQL_SLAP'}= mysqlslap_arguments();
$ENV{'MYSQL_IMPORT'}= client_arguments("mysqlimport");
$ENV{'MYSQL_SHOW'}= client_arguments("mysqlshow");
- $ENV{'MYSQL_BINLOG'}= client_arguments("mysqlbinlog");
+ $ENV{'MYSQL_BINLOG'}= mysqlbinlog_arguments();
$ENV{'MYSQL'}= client_arguments("mysql");
$ENV{'MYSQL_UPGRADE'}= client_arguments("mysql_upgrade");
$ENV{'MYSQLADMIN'}= native_path($exe_mysqladmin);
@@ -1827,20 +1871,21 @@ sub environment_setup {
$ENV{'MYSQL_MY_PRINT_DEFAULTS'}= native_path($exe_my_print_defaults);
# ----------------------------------------------------
- # Setup env so childs can execute myisampack and myisamchk
+ # myisam tools
# ----------------------------------------------------
- $ENV{'MYISAMCHK'}= native_path(mtr_exe_exists(
- vs_config_dirs('storage/myisam', 'myisamchk'),
- vs_config_dirs('myisam', 'myisamchk'),
- "$path_client_bindir/myisamchk",
- "$basedir/storage/myisam/myisamchk",
- "$basedir/myisam/myisamchk"));
- $ENV{'MYISAMPACK'}= native_path(mtr_exe_exists(
- vs_config_dirs('storage/myisam', 'myisampack'),
- vs_config_dirs('myisam', 'myisampack'),
- "$path_client_bindir/myisampack",
- "$basedir/storage/myisam/myisampack",
- "$basedir/myisam/myisampack"));
+ $ENV{'MYISAMLOG'}= tool_arguments("storage/myisam", "myisamlog", );
+ $ENV{'MYISAMCHK'}= tool_arguments("storage/myisam", "myisamchk");
+ $ENV{'MYISAMPACK'}= tool_arguments("storage/myisam", "myisampack");
+ $ENV{'MYISAM_FTDUMP'}= tool_arguments("storage/myisam", "myisam_ftdump");
+
+ # ----------------------------------------------------
+ # maria tools
+ # ----------------------------------------------------
+ if (have_maria_support())
+ {
+ $ENV{'MARIA_CHK'}= tool_arguments("storage/maria", "maria_chk");
+ $ENV{'MARIA_PACK'}= tool_arguments("storage/maria", "maria_pack");
+ }
# ----------------------------------------------------
# perror
@@ -2572,6 +2617,7 @@ sub mysql_install_db {
mtr_add_arg($args, "--loose-skip-innodb");
mtr_add_arg($args, "--loose-skip-falcon");
mtr_add_arg($args, "--loose-skip-ndbcluster");
+ mtr_add_arg($args, "--loose-skip-maria");
mtr_add_arg($args, "--tmpdir=%s", "$opt_vardir/tmp/");
mtr_add_arg($args, "--core-file");
@@ -2592,6 +2638,12 @@ sub mysql_install_db {
my $exe_mysqld_bootstrap =
$ENV{'MYSQLD_BOOTSTRAP'} || find_mysqld($install_basedir);
+ # MASV add only to bootstrap.test
+ # Setup args for bootstrap.test
+ #
+ #mtr_init_args(\$cmd_args);
+ #mtr_add_arg($cmd_args, "--loose-skip-maria")
+
# ----------------------------------------------------------------------
# export MYSQLD_BOOTSTRAP_CMD variable containing <path>/mysqld <args>
# ----------------------------------------------------------------------
@@ -3952,6 +4004,11 @@ sub mysqld_arguments ($$$) {
mtr_add_arg($args, "%s", "--core-file");
}
+ # Enable the debug sync facility, set default wait timeout.
+ # Facility stays disabled if timeout value is zero.
+ mtr_add_arg($args, "--loose-debug-sync-timeout=%s",
+ $opt_debug_sync_timeout);
+
return $args;
}
@@ -4024,7 +4081,17 @@ sub mysqld_start ($$) {
# When both --valgrind and --debug is selected, send
# all output to the trace file, making it possible to
# see the exact location where valgrind complains
- $output= "$opt_vardir/log/".$mysqld->name().".trace";
+
+ # Write a message about this to the normal log file
+ my $trace_name= "$opt_vardir/log/".$mysqld->name().".trace";
+ mtr_tofile($output,
+ "NOTE: When running with --valgrind --debug the output from",
+ "mysqld(where the valgrind messages shows up) is stored ",
+ "together with the trace file to make it ",
+ "easier to find the exact position of valgrind errors.",
+ "See trace file $trace_name.\n");
+ $output= $trace_name;
+
}
if ( defined $exe )
@@ -4596,6 +4663,11 @@ sub start_mysqltest ($) {
}
}
+ foreach my $arg ( @opt_extra_mysqltest_opt )
+ {
+ mtr_add_arg($args, "%s", $arg);
+ }
+
# ----------------------------------------------------------------------
# export MYSQL_TEST variable containing <path>/mysqltest <args>
# ----------------------------------------------------------------------
@@ -4690,13 +4762,9 @@ sub gdb_arguments {
else
{
# write init file for mysqld
- mtr_tofile($gdb_init_file,
- "set args $str\n" .
- "break mysql_parse\n" .
- "commands 1\n" .
- "disable 1\n" .
- "end\n" .
- "run");
+ mtr_tofile($gdb_init_file, <<EOGDB );
+set args $str
+EOGDB
}
if ( $opt_manual_gdb )
@@ -4966,6 +5034,7 @@ Options for test case authoring
Options that pass on options
mysqld=ARGS Specify additional arguments to "mysqld"
+ mysqltest=ARGS Specify additional arguments to "mysqltest"
Options to run test on running server
@@ -5048,6 +5117,8 @@ Misc options
to turn off.
sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time
+ debug-sync-timeout=NUM Set default timeout for WAIT_FOR debug sync
+ actions. Disable facility with NUM=0.
HERE
exit(1);
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 5a115e9ea99..2a784d984ed 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -298,7 +298,7 @@ t1 0 a 1 a A 3 NULL NULL YES BTREE
t1 0 a 2 b A 300 NULL NULL YES BTREE
t1 1 b 1 b A 100 NULL NULL YES BTREE
drop table t1;
-CREATE TABLE t1 (i int(10), index(i) );
+CREATE TABLE t1 (i int(10), index(i) ) ENGINE=MyISAM;
ALTER TABLE t1 DISABLE KEYS;
INSERT DELAYED INTO t1 VALUES(1),(2),(3);
ALTER TABLE t1 ENABLE KEYS;
diff --git a/mysql-test/r/change_user.result b/mysql-test/r/change_user.result
index f8d5d900a80..679e656c381 100644
--- a/mysql-test/r/change_user.result
+++ b/mysql-test/r/change_user.result
@@ -24,6 +24,12 @@ change_user
SELECT @@session.sql_big_selects;
@@session.sql_big_selects
1
+SELECT @@global.max_join_size;
+@@global.max_join_size
+18446744073709551615
+SELECT @@session.max_join_size;
+@@session.max_join_size
+18446744073709551615
Bug#31418
SELECT IS_FREE_LOCK('bug31418');
IS_FREE_LOCK('bug31418')
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 057a8600ca2..2901020ab45 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -1734,7 +1734,7 @@ t1 CREATE TABLE `t1` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
drop table t1;
create temporary table t1 like information_schema.processlist;
show create table t1;
@@ -1748,7 +1748,7 @@ t1 CREATE TEMPORARY TABLE `t1` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
drop table t1;
create table t1 like information_schema.character_sets;
show create table t1;
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index 6f4ae965ca0..4cfd06149f1 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -240,7 +240,7 @@ select hex(s1) from t1;
hex(s1)
41
drop table t1;
-create table t1 (a text character set utf8, primary key(a(360)));
+create table t1 (a text character set utf8, primary key(a(371)));
ERROR 42000: Specified key was too long; max key length is 1000 bytes
CREATE TABLE t1 ( a varchar(10) ) CHARACTER SET utf8;
INSERT INTO t1 VALUES ( 'test' );
diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result
index bcda6ddb6ab..65b358615cf 100644
--- a/mysql-test/r/delayed.result
+++ b/mysql-test/r/delayed.result
@@ -251,8 +251,12 @@ HEX(a)
1
DROP TABLE t1;
CREATE TABLE t1 (a INT);
-INSERT DELAYED INTO t1 SET b= b();
+INSERT DELAYED INTO t1 SET a= b();
+ERROR 42000: FUNCTION test.b does not exist
+INSERT DELAYED INTO t1 SET b= 1;
ERROR 42S22: Unknown column 'b' in 'field list'
+INSERT DELAYED INTO t1 SET b= b();
+ERROR 42000: FUNCTION test.b does not exist
DROP TABLE t1;
End of 5.0 tests
DROP TABLE IF EXISTS t1,t2;
diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result
index 8633bd61681..6e2770ef940 100644
--- a/mysql-test/r/fulltext.result
+++ b/mysql-test/r/fulltext.result
@@ -522,6 +522,14 @@ WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref b b 5 const 4 Using where
DROP TABLE t1;
+create table t1(a text,b date,fulltext index(a))engine=myisam;
+insert into t1 set a='water',b='2008-08-04';
+select 1 from t1 where match(a) against ('water' in boolean mode) and b>='2008-08-01';
+1
+1
+drop table t1;
+show warnings;
+Level Code Message
CREATE TABLE t1(a CHAR(10));
INSERT INTO t1 VALUES('aaa15');
SELECT MATCH(a) AGAINST('aaa1* aaa14 aaa16' IN BOOLEAN MODE) FROM t1;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 2ce9587ef1a..1f46ade27e0 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1433,7 +1433,7 @@ insert t2 select * from t1;
insert t3 select * from t1;
checksum table t1, t2, t3, t4 quick;
Table Checksum
-test.t1 2948697075
+test.t1 3442722830
test.t2 NULL
test.t3 NULL
test.t4 NULL
@@ -1441,17 +1441,17 @@ Warnings:
Error 1146 Table 'test.t4' doesn't exist
checksum table t1, t2, t3, t4;
Table Checksum
-test.t1 2948697075
-test.t2 2948697075
-test.t3 2948697075
+test.t1 3442722830
+test.t2 3442722830
+test.t3 3442722830
test.t4 NULL
Warnings:
Error 1146 Table 'test.t4' doesn't exist
checksum table t1, t2, t3, t4 extended;
Table Checksum
-test.t1 2948697075
-test.t2 2948697075
-test.t3 2948697075
+test.t1 3442722830
+test.t2 3442722830
+test.t3 3442722830
test.t4 NULL
Warnings:
Error 1146 Table 'test.t4' doesn't exist
diff --git a/mysql-test/r/insert.result b/mysql-test/r/insert.result
index 919aff4bfb7..8036a346b3a 100644
--- a/mysql-test/r/insert.result
+++ b/mysql-test/r/insert.result
@@ -355,17 +355,17 @@ insert into t2 values (1,12), (2,24);
insert into v1 (f1) values (3) on duplicate key update f3= f3 + 10;
ERROR HY000: Can not modify more than one base table through a join view 'test.v1'
insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
+ERROR HY000: Can not modify more than one base table through a join view 'test.v1'
select * from t1;
f1 f2
1 11
2 22
-3 NULL
insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
+ERROR HY000: Can not modify more than one base table through a join view 'test.v1'
select * from t1;
f1 f2
1 11
2 22
-12 NULL
drop view v1;
drop table t1,t2;
create table t1 (id int primary key auto_increment, data int, unique(data));
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index cc05efded02..7d8f052ef84 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -1,3 +1,5 @@
+set global storage_engine=myisam;
+set session storage_engine=myisam;
drop table if exists t1,t2,t3,t4,t5,t6;
drop database if exists mysqltest;
create table t1 (a int not null primary key auto_increment, message char(20));
diff --git a/mysql-test/r/mix2_myisam.result b/mysql-test/r/mix2_myisam.result
index cabc4de8d21..e0a3d1af089 100644
--- a/mysql-test/r/mix2_myisam.result
+++ b/mysql-test/r/mix2_myisam.result
@@ -1232,34 +1232,34 @@ insert t5 select * from t1;
insert t6 select * from t1;
checksum table t1, t2, t3, t4, t5, t6, t7 quick;
Table Checksum
-test.t1 2948697075
+test.t1 3442722830
test.t2 NULL
test.t3 NULL
test.t4 NULL
-test.t5 2948697075
+test.t5 3442722830
test.t6 NULL
test.t7 NULL
Warnings:
Error 1146 Table 'test.t7' doesn't exist
checksum table t1, t2, t3, t4, t5, t6, t7;
Table Checksum
-test.t1 2948697075
-test.t2 2948697075
-test.t3 2948697075
-test.t4 2948697075
-test.t5 2948697075
-test.t6 2948697075
+test.t1 3442722830
+test.t2 3442722830
+test.t3 3442722830
+test.t4 3442722830
+test.t5 3442722830
+test.t6 3442722830
test.t7 NULL
Warnings:
Error 1146 Table 'test.t7' doesn't exist
checksum table t1, t2, t3, t4, t5, t6, t7 extended;
Table Checksum
-test.t1 2948697075
-test.t2 2948697075
-test.t3 2948697075
-test.t4 2948697075
-test.t5 2948697075
-test.t6 2948697075
+test.t1 3442722830
+test.t2 3442722830
+test.t3 3442722830
+test.t4 3442722830
+test.t5 3442722830
+test.t6 3442722830
test.t7 NULL
Warnings:
Error 1146 Table 'test.t7' doesn't exist
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index 6f26135ce45..33c7a203671 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
SET SQL_WARNINGS=1;
CREATE TABLE t1 (
STRING_DATA char(255) default NULL,
@@ -551,22 +551,22 @@ insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
insert t2 select * from t1;
checksum table t1, t2, t3 quick;
Table Checksum
-test.t1 2948697075
+test.t1 3442722830
test.t2 NULL
test.t3 NULL
Warnings:
Error 1146 Table 'test.t3' doesn't exist
checksum table t1, t2, t3;
Table Checksum
-test.t1 2948697075
-test.t2 2948697075
+test.t1 3442722830
+test.t2 3442722830
test.t3 NULL
Warnings:
Error 1146 Table 'test.t3' doesn't exist
checksum table t1, t2, t3 extended;
Table Checksum
-test.t1 2948697075
-test.t2 2948697075
+test.t1 3442722830
+test.t2 3442722830
test.t3 NULL
Warnings:
Error 1146 Table 'test.t3' doesn't exist
@@ -2226,4 +2226,29 @@ Key Start Len Index Type
1 2 30 multip. varchar
2 33 30 multip. char NULL
DROP TABLE t1;
+create table t1 (n int not null, c char(1)) transactional=1;
+Warnings:
+Error 1478 Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `n` int(11) NOT NULL,
+ `c` char(1) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 TRANSACTIONAL=1
+drop table t1;
+CREATE TABLE t1 (line LINESTRING NOT NULL) engine=myisam;
+INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t1;
+Table Checksum
+test.t1 326284887
+CREATE TABLE t2 (line LINESTRING NOT NULL) engine=myisam;
+INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t2;
+Table Checksum
+test.t2 326284887
+CREATE TABLE t3 select * from t1;
+checksum table t3;
+Table Checksum
+test.t3 326284887
+drop table t1,t2,t3;
End of 5.1 tests
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index ec397d8fb89..83d5ec284c1 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -728,7 +728,7 @@ DROP TABLE t1;
#
# Test for --insert-ignore
#
-CREATE TABLE t1 (a int);
+CREATE TABLE t1 (a int) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1),(2),(3);
INSERT INTO t1 VALUES (4),(5),(6);
@@ -3649,8 +3649,8 @@ CREATE TABLE t1(a int);
INSERT INTO t1 VALUES (1), (2);
mysqldump: Input filename too long: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
DROP TABLE t1;
-CREATE TABLE t2 (a int);
-CREATE TABLE t3 (a int);
+CREATE TABLE t2 (a int) ENGINE=MyISAM;
+CREATE TABLE t3 (a int) ENGINE=MyISAM;
CREATE TABLE t1 (a int) ENGINE=merge UNION=(t2, t3);
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
diff --git a/mysql-test/r/old-mode.result b/mysql-test/r/old-mode.result
new file mode 100644
index 00000000000..a9815d7dab2
--- /dev/null
+++ b/mysql-test/r/old-mode.result
@@ -0,0 +1,18 @@
+drop table if exists t1,t2;
+create table t1 (a int, b varchar(200), c text not null) checksum=1;
+create table t2 (a int, b varchar(200), c text not null) checksum=0;
+insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
+insert t2 select * from t1;
+checksum table t1, t2;
+Table Checksum
+test.t1 2948697075
+test.t2 2948697075
+checksum table t1, t2 quick;
+Table Checksum
+test.t1 NULL
+test.t2 NULL
+checksum table t1, t2 extended;
+Table Checksum
+test.t1 2948697075
+test.t2 2948697075
+drop table t1,t2;
diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result
index 0888b78618f..4e732db493e 100644
--- a/mysql-test/r/ps_2myisam.result
+++ b/mysql-test/r/ps_2myisam.result
@@ -1755,7 +1755,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
-create table t5 as select
+create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result
index e5a57131b01..bddb160189f 100644
--- a/mysql-test/r/ps_3innodb.result
+++ b/mysql-test/r/ps_3innodb.result
@@ -1738,7 +1738,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
-create table t5 as select
+create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result
index 2c83916e952..6072e6e771e 100644
--- a/mysql-test/r/ps_4heap.result
+++ b/mysql-test/r/ps_4heap.result
@@ -1739,7 +1739,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
-create table t5 as select
+create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result
index 0348d100393..fde309d82e4 100644
--- a/mysql-test/r/ps_5merge.result
+++ b/mysql-test/r/ps_5merge.result
@@ -1675,7 +1675,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
-create table t5 as select
+create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
@@ -4696,7 +4696,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
-create table t5 as select
+create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index 6cabc24d0eb..1c11932107e 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -42,9 +42,9 @@ drop table t1;
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
-create table t1 (a int not null);
+create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
-create table t2 (a int not null);
+create table t2 (a int not null) ENGINE=MyISAM;
insert into t2 values (4),(5),(6);
create table t3 (a int not null) engine=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
select * from t3;
@@ -460,7 +460,7 @@ Qcache_queries_in_cache 2
drop table t1;
flush query cache;
reset query cache;
-create table t1 (a int not null);
+create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
select * from t1;
a
diff --git a/mysql-test/r/row-checksum-old.result b/mysql-test/r/row-checksum-old.result
new file mode 100644
index 00000000000..3cf5a7104b9
--- /dev/null
+++ b/mysql-test/r/row-checksum-old.result
@@ -0,0 +1,85 @@
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 452555338
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 452555338
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=1;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 452555338
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 452555338
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=innodb checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 452555338
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 452555338
+drop table t1;
+create table t1 (a int null, v varchar(100)) engine=maria checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 452555338
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 452555338
+drop table t1;
+create table t1 (a int null, v varchar(100)) engine=maria checksum=1;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 452555338
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 452555338
+drop table t1;
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=1 row_format=fixed;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 4108368782
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 4108368782
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 4108368782
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 4108368782
+drop table t1;
diff --git a/mysql-test/r/row-checksum.result b/mysql-test/r/row-checksum.result
new file mode 100644
index 00000000000..31ae094859b
--- /dev/null
+++ b/mysql-test/r/row-checksum.result
@@ -0,0 +1,85 @@
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 229851577
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 229851577
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=1;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 229851577
+checksum table t1 quick;
+Table Checksum
+test.t1 229851577
+checksum table t1 extended;
+Table Checksum
+test.t1 229851577
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=innodb checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 229851577
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 229851577
+drop table t1;
+create table t1 (a int null, v varchar(100)) engine=maria checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 229851577
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 229851577
+drop table t1;
+create table t1 (a int null, v varchar(100)) engine=maria checksum=1;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 229851577
+checksum table t1 quick;
+Table Checksum
+test.t1 229851577
+checksum table t1 extended;
+Table Checksum
+test.t1 229851577
+drop table t1;
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=1 row_format=fixed;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 3885665021
+checksum table t1 quick;
+Table Checksum
+test.t1 3885665021
+checksum table t1 extended;
+Table Checksum
+test.t1 3885665021
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+Table Checksum
+test.t1 3885665021
+checksum table t1 quick;
+Table Checksum
+test.t1 NULL
+checksum table t1 extended;
+Table Checksum
+test.t1 3885665021
+drop table t1;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index aff26454b2d..dc9abdd98e4 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -626,8 +626,8 @@ a b
33 10
22 11
drop table t11, t12, t2;
-CREATE TABLE t1 (x int);
-create table t2 (a int);
+CREATE TABLE t1 (x int) ENGINE=MyISAM;
+create table t2 (a int) ENGINE=MyISAM;
create table t3 (b int);
insert into t2 values (1);
insert into t3 values (1),(2);
@@ -674,7 +674,7 @@ x
11
2
drop table t1, t2, t3;
-CREATE TABLE t1 (x int not null, y int, primary key (x));
+CREATE TABLE t1 (x int not null, y int, primary key (x)) ENGINE=MyISAM;
create table t2 (a int);
create table t3 (a int);
insert into t2 values (1);
@@ -4463,15 +4463,12 @@ SELECT t2.id, t2.c AS c FROM t1, t2
WHERE t1.id=t2.id AND 1 IN (SELECT id FROM t1) WITH CHECK OPTION;
INSERT INTO v2(a,b) VALUES (2,2);
ERROR HY000: CHECK OPTION failed 'test.v2'
-INSERT INTO v2(a,b) VALUES (1,2);
SELECT * FROM v1;
c
1
1
1
1
-2
-2
CREATE VIEW v3 AS
SELECT t2.c AS c FROM t2
WHERE 1 IN (SELECT id FROM t1) WITH CHECK OPTION;
diff --git a/mysql-test/r/subselect_debug.result b/mysql-test/r/subselect_debug.result
index 9ba552bbdf7..37a5c82a9f8 100644
--- a/mysql-test/r/subselect_debug.result
+++ b/mysql-test/r/subselect_debug.result
@@ -1,6 +1,7 @@
CREATE TABLE t1(id INT);
INSERT INTO t1 VALUES (1),(2),(3),(4);
INSERT INTO t1 SELECT a.id FROM t1 a,t1 b,t1 c,t1 d;
+SET @orig_debug=@@debug;
SET SESSION debug="d,subselect_exec_fail";
SELECT SUM(EXISTS(SELECT RAND() FROM t1)) FROM t1;
SUM(EXISTS(SELECT RAND() FROM t1))
@@ -8,5 +9,5 @@ SUM(EXISTS(SELECT RAND() FROM t1))
SELECT REVERSE(EXISTS(SELECT RAND() FROM t1));
REVERSE(EXISTS(SELECT RAND() FROM t1))
0
-SET SESSION debug=DEFAULT;
+SET SESSION debug=@orig_debug;
DROP TABLE t1;
diff --git a/mysql-test/r/variables-big.result b/mysql-test/r/variables-big.result
index ae1e20109b9..35882c7e284 100644
--- a/mysql-test/r/variables-big.result
+++ b/mysql-test/r/variables-big.result
@@ -1,20 +1,20 @@
set session transaction_prealloc_size=1024*1024*1024*1;
show processlist;
Id User Host db Command Time State Info
-1 root localhost test Query 0 NULL show processlist
+# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*2;
show processlist;
Id User Host db Command Time State Info
-1 root localhost test Query 0 NULL show processlist
+# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*3;
show processlist;
Id User Host db Command Time State Info
-1 root localhost test Query 0 NULL show processlist
+# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*4;
show processlist;
Id User Host db Command Time State Info
-1 root localhost test Query 0 NULL show processlist
+# root localhost test Query 0 NULL show processlist
set session transaction_prealloc_size=1024*1024*1024*5;
show processlist;
Id User Host db Command Time State Info
-1 root localhost test Query 0 NULL show processlist
+# root localhost test Query 0 NULL show processlist
diff --git a/mysql-test/suite/funcs_1/datadict/is_routines.inc b/mysql-test/suite/funcs_1/datadict/is_routines.inc
index 573967cbc1b..4902596df94 100644
--- a/mysql-test/suite/funcs_1/datadict/is_routines.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_routines.inc
@@ -75,6 +75,7 @@ eval SHOW TABLES FROM information_schema LIKE '$is_table';
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval DESCRIBE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
eval SHOW CREATE TABLE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval SHOW COLUMNS FROM information_schema.$is_table;
diff --git a/mysql-test/suite/funcs_1/datadict/is_triggers.inc b/mysql-test/suite/funcs_1/datadict/is_triggers.inc
index 70d5540e163..22fd851745f 100644
--- a/mysql-test/suite/funcs_1/datadict/is_triggers.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_triggers.inc
@@ -70,6 +70,7 @@ eval SHOW TABLES FROM information_schema LIKE '$is_table';
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval DESCRIBE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
eval SHOW CREATE TABLE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval SHOW COLUMNS FROM information_schema.$is_table;
diff --git a/mysql-test/suite/funcs_1/datadict/is_views.inc b/mysql-test/suite/funcs_1/datadict/is_views.inc
index 542dab05a8e..69f881b3e43 100644
--- a/mysql-test/suite/funcs_1/datadict/is_views.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_views.inc
@@ -57,6 +57,7 @@ eval SHOW TABLES FROM information_schema LIKE '$is_table';
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval DESCRIBE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
eval SHOW CREATE TABLE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval SHOW COLUMNS FROM information_schema.$is_table;
diff --git a/mysql-test/suite/funcs_1/datadict/processlist_priv.inc b/mysql-test/suite/funcs_1/datadict/processlist_priv.inc
index d8e1b398bfc..9c0ebda24b6 100644
--- a/mysql-test/suite/funcs_1/datadict/processlist_priv.inc
+++ b/mysql-test/suite/funcs_1/datadict/processlist_priv.inc
@@ -135,6 +135,7 @@ let $wait_condition=
SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE DB = 'information_schema' AND COMMAND = 'Sleep' AND USER = 'ddicttestuser1';
--source include/wait_condition.inc
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
eval SHOW CREATE TABLE $table;
--replace_column 1 ID 3 HOST_NAME 6 TIME
eval SHOW $table;
@@ -143,6 +144,7 @@ eval SELECT * FROM $table $select_where ORDER BY id;
--replace_column 1 ID 3 HOST_NAME 6 TIME
eval SELECT $columns FROM $table $select_where ORDER BY id;
--source suite/funcs_1/datadict/datadict_priv.inc
+--real_sleep 0.3
--echo ####################################################################################
@@ -153,6 +155,7 @@ connection con100;
# No need for poll routine here.
# The current state of the default session might depend on load of testing box
# but "ddicttestuser1" must not see anything of the root session.
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
eval SHOW CREATE TABLE $table;
--replace_column 1 ID 3 HOST_NAME 6 TIME
eval SHOW $table;
diff --git a/mysql-test/suite/funcs_1/datadict/processlist_val.inc b/mysql-test/suite/funcs_1/datadict/processlist_val.inc
index c34fb626bcd..ee5347fa529 100644
--- a/mysql-test/suite/funcs_1/datadict/processlist_val.inc
+++ b/mysql-test/suite/funcs_1/datadict/processlist_val.inc
@@ -72,6 +72,7 @@ echo
# Show the definition of the PROCESSLIST table
#--------------------------------------------------------------------------
;
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
SHOW CREATE TABLE INFORMATION_SCHEMA.PROCESSLIST;
echo
diff --git a/mysql-test/suite/funcs_1/datadict/tables2.inc b/mysql-test/suite/funcs_1/datadict/tables2.inc
index 6442aab493c..f9bb296eeaa 100644
--- a/mysql-test/suite/funcs_1/datadict/tables2.inc
+++ b/mysql-test/suite/funcs_1/datadict/tables2.inc
@@ -31,6 +31,7 @@ let $ndb_pattern = 'number_of_replicas';
--vertical_results
# We do not unify the engine name here, because the rowformat is
# specific to the engine.
+--replace_result Dynamic DYNAMIC_OR_PAGE Page DYNAMIC_OR_PAGE MyISAM MYISAM_OR_MARIA MARIA MYISAM_OR_MARIA
--replace_column 8 "#TBLR#" 9 "#ARL#" 10 "#DL#" 11 "#MDL#" 12 "#IL#" 13 "#DF#" 15 "#CRT#" 16 "#UT#" 17 "#CT#" 20 "#CO#" 21 "#TC#"
eval
SELECT *,
diff --git a/mysql-test/suite/funcs_1/r/is_columns.result b/mysql-test/suite/funcs_1/r/is_columns.result
index e0780a60e2e..7901902e729 100644
--- a/mysql-test/suite/funcs_1/r/is_columns.result
+++ b/mysql-test/suite/funcs_1/r/is_columns.result
@@ -69,7 +69,7 @@ COLUMNS CREATE TEMPORARY TABLE `COLUMNS` (
`EXTRA` varchar(27) NOT NULL DEFAULT '',
`PRIVILEGES` varchar(80) NOT NULL DEFAULT '',
`COLUMN_COMMENT` varchar(255) NOT NULL DEFAULT ''
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW COLUMNS FROM information_schema.COLUMNS;
Field Type Null Key Default Extra
TABLE_CATALOG varchar(512) YES NULL
diff --git a/mysql-test/suite/funcs_1/r/is_events.result b/mysql-test/suite/funcs_1/r/is_events.result
index 6dfe5899bf4..69ff40b304e 100644
--- a/mysql-test/suite/funcs_1/r/is_events.result
+++ b/mysql-test/suite/funcs_1/r/is_events.result
@@ -79,7 +79,7 @@ EVENTS CREATE TEMPORARY TABLE `EVENTS` (
`CHARACTER_SET_CLIENT` varchar(32) NOT NULL DEFAULT '',
`COLLATION_CONNECTION` varchar(32) NOT NULL DEFAULT '',
`DATABASE_COLLATION` varchar(32) NOT NULL DEFAULT ''
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW COLUMNS FROM information_schema.EVENTS;
Field Type Null Key Default Extra
EVENT_CATALOG varchar(64) YES NULL
diff --git a/mysql-test/suite/funcs_1/r/is_routines.result b/mysql-test/suite/funcs_1/r/is_routines.result
index e7a900f5c0b..bc0b1c655ca 100644
--- a/mysql-test/suite/funcs_1/r/is_routines.result
+++ b/mysql-test/suite/funcs_1/r/is_routines.result
@@ -77,7 +77,7 @@ ROUTINES CREATE TEMPORARY TABLE `ROUTINES` (
`CHARACTER_SET_CLIENT` varchar(32) NOT NULL DEFAULT '',
`COLLATION_CONNECTION` varchar(32) NOT NULL DEFAULT '',
`DATABASE_COLLATION` varchar(32) NOT NULL DEFAULT ''
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW COLUMNS FROM information_schema.ROUTINES;
Field Type Null Key Default Extra
SPECIFIC_NAME varchar(64) NO
diff --git a/mysql-test/suite/funcs_1/r/is_tables_is.result b/mysql-test/suite/funcs_1/r/is_tables_is.result
index 83eaef22e0c..59e5c6ecf57 100644
--- a/mysql-test/suite/funcs_1/r/is_tables_is.result
+++ b/mysql-test/suite/funcs_1/r/is_tables_is.result
@@ -86,9 +86,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME COLUMNS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -155,9 +155,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME EVENTS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -270,9 +270,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME PARTITIONS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -293,9 +293,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME PLUGINS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -316,9 +316,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME PROCESSLIST
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -362,9 +362,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME ROUTINES
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -569,9 +569,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME TRIGGERS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -615,9 +615,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME VIEWS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -724,9 +724,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME COLUMNS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -793,9 +793,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME EVENTS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -908,9 +908,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME PARTITIONS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -931,9 +931,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME PLUGINS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -954,9 +954,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME PROCESSLIST
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -1000,9 +1000,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME ROUTINES
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -1207,9 +1207,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME TRIGGERS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -1253,9 +1253,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA information_schema
TABLE_NAME VIEWS
TABLE_TYPE SYSTEM VIEW
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
diff --git a/mysql-test/suite/funcs_1/r/is_tables_myisam.result b/mysql-test/suite/funcs_1/r/is_tables_myisam.result
index 0f476309303..59673fcbf45 100644
--- a/mysql-test/suite/funcs_1/r/is_tables_myisam.result
+++ b/mysql-test/suite/funcs_1/r/is_tables_myisam.result
@@ -19,12 +19,12 @@ FROM information_schema.tables
WHERE table_schema LIKE 'test%' AND table_type = 'BASE TABLE'
ORDER BY table_schema,table_name;
TABLE_CATALOG NULL
-TABLE_SCHEMA test1
+TABLE_SCHEMA test
TABLE_NAME t1
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -42,12 +42,58 @@ TABLE_COMMENT #TC#
user_comment
Separator -----------------------------------------------------
TABLE_CATALOG NULL
-TABLE_SCHEMA test1
+TABLE_SCHEMA test
+TABLE_NAME t10
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t11
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
TABLE_NAME t2
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -65,12 +111,242 @@ TABLE_COMMENT #TC#
user_comment
Separator -----------------------------------------------------
TABLE_CATALOG NULL
-TABLE_SCHEMA test2
-TABLE_NAME t1
+TABLE_SCHEMA test
+TABLE_NAME t3
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t4
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t7
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t8
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t9
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb1
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb2
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb3
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb4
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test1
+TABLE_NAME tb2
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test4
+TABLE_NAME t6
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -111,12 +387,12 @@ FROM information_schema.tables
WHERE table_schema LIKE 'test%' AND table_type = 'BASE TABLE'
ORDER BY table_schema,table_name;
TABLE_CATALOG NULL
-TABLE_SCHEMA test1
+TABLE_SCHEMA test
TABLE_NAME t1
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -134,12 +410,265 @@ TABLE_COMMENT #TC#
user_comment
Separator -----------------------------------------------------
TABLE_CATALOG NULL
-TABLE_SCHEMA test1
+TABLE_SCHEMA test
+TABLE_NAME t10
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t11
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
TABLE_NAME t2
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t3
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t4
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t7
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t8
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME t9
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT Fixed
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb1
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb2
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb3
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
+VERSION 10
+ROW_FORMAT DYNAMIC_OR_PAGE
+TABLE_ROWS #TBLR#
+AVG_ROW_LENGTH #ARL#
+DATA_LENGTH #DL#
+MAX_DATA_LENGTH #MDL#
+INDEX_LENGTH #IL#
+DATA_FREE #DF#
+AUTO_INCREMENT NULL
+CREATE_TIME #CRT#
+UPDATE_TIME #UT#
+CHECK_TIME #CT#
+TABLE_COLLATION latin1_swedish_ci
+CHECKSUM NULL
+CREATE_OPTIONS #CO#
+TABLE_COMMENT #TC#
+user_comment
+Separator -----------------------------------------------------
+TABLE_CATALOG NULL
+TABLE_SCHEMA test
+TABLE_NAME tb4
+TABLE_TYPE BASE TABLE
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
diff --git a/mysql-test/suite/funcs_1/r/is_tables_mysql.result b/mysql-test/suite/funcs_1/r/is_tables_mysql.result
index 4b33009904f..b41318d9bae 100644
--- a/mysql-test/suite/funcs_1/r/is_tables_mysql.result
+++ b/mysql-test/suite/funcs_1/r/is_tables_mysql.result
@@ -16,7 +16,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME columns_priv
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -39,7 +39,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME db
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -62,9 +62,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME event
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -85,7 +85,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME func
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -110,7 +110,7 @@ TABLE_NAME general_log
TABLE_TYPE BASE TABLE
ENGINE CSV
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -131,7 +131,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME help_category
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -154,7 +154,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME help_keyword
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -177,7 +177,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME help_relation
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -200,9 +200,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME help_topic
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -223,7 +223,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME host
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -246,9 +246,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME ndb_binlog_index
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -269,7 +269,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME plugin
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -292,9 +292,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME proc
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -315,7 +315,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME procs_priv
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -338,7 +338,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME servers
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -363,7 +363,7 @@ TABLE_NAME slow_log
TABLE_TYPE BASE TABLE
ENGINE CSV
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
@@ -384,7 +384,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME tables_priv
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -407,7 +407,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME time_zone
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -430,7 +430,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME time_zone_leap_second
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -453,7 +453,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME time_zone_name
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -476,7 +476,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME time_zone_transition
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -499,7 +499,7 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME time_zone_transition_type
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
ROW_FORMAT Fixed
TABLE_ROWS #TBLR#
@@ -522,9 +522,9 @@ TABLE_CATALOG NULL
TABLE_SCHEMA mysql
TABLE_NAME user
TABLE_TYPE BASE TABLE
-ENGINE MyISAM
+ENGINE MYISAM_OR_MARIA
VERSION 10
-ROW_FORMAT Dynamic
+ROW_FORMAT DYNAMIC_OR_PAGE
TABLE_ROWS #TBLR#
AVG_ROW_LENGTH #ARL#
DATA_LENGTH #DL#
diff --git a/mysql-test/suite/funcs_1/r/is_triggers.result b/mysql-test/suite/funcs_1/r/is_triggers.result
index edf4a9e5032..5940e900a37 100644
--- a/mysql-test/suite/funcs_1/r/is_triggers.result
+++ b/mysql-test/suite/funcs_1/r/is_triggers.result
@@ -75,7 +75,7 @@ TRIGGERS CREATE TEMPORARY TABLE `TRIGGERS` (
`CHARACTER_SET_CLIENT` varchar(32) NOT NULL DEFAULT '',
`COLLATION_CONNECTION` varchar(32) NOT NULL DEFAULT '',
`DATABASE_COLLATION` varchar(32) NOT NULL DEFAULT ''
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW COLUMNS FROM information_schema.TRIGGERS;
Field Type Null Key Default Extra
TRIGGER_CATALOG varchar(512) YES NULL
diff --git a/mysql-test/suite/funcs_1/r/is_views.result b/mysql-test/suite/funcs_1/r/is_views.result
index f960c26b21d..0cce7a83d62 100644
--- a/mysql-test/suite/funcs_1/r/is_views.result
+++ b/mysql-test/suite/funcs_1/r/is_views.result
@@ -51,7 +51,7 @@ VIEWS CREATE TEMPORARY TABLE `VIEWS` (
`SECURITY_TYPE` varchar(7) NOT NULL DEFAULT '',
`CHARACTER_SET_CLIENT` varchar(32) NOT NULL DEFAULT '',
`COLLATION_CONNECTION` varchar(32) NOT NULL DEFAULT ''
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW COLUMNS FROM information_schema.VIEWS;
Field Type Null Key Default Extra
TABLE_CATALOG varchar(512) YES NULL
diff --git a/mysql-test/suite/funcs_1/r/processlist_priv_no_prot.result b/mysql-test/suite/funcs_1/r/processlist_priv_no_prot.result
index d862b7424e0..b1e1cbbc4a9 100644
--- a/mysql-test/suite/funcs_1/r/processlist_priv_no_prot.result
+++ b/mysql-test/suite/funcs_1/r/processlist_priv_no_prot.result
@@ -30,7 +30,7 @@ PROCESSLIST CREATE TEMPORARY TABLE `PROCESSLIST` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW processlist;
Id User Host db Command Time State Info
ID root HOST_NAME information_schema Query TIME NULL SHOW processlist
@@ -100,7 +100,7 @@ PROCESSLIST CREATE TEMPORARY TABLE `PROCESSLIST` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW processlist;
Id User Host db Command Time State Info
ID ddicttestuser1 HOST_NAME information_schema Query TIME NULL SHOW processlist
diff --git a/mysql-test/suite/funcs_1/r/processlist_priv_ps.result b/mysql-test/suite/funcs_1/r/processlist_priv_ps.result
index 56230a0f806..e9aef731ade 100644
--- a/mysql-test/suite/funcs_1/r/processlist_priv_ps.result
+++ b/mysql-test/suite/funcs_1/r/processlist_priv_ps.result
@@ -30,7 +30,7 @@ PROCESSLIST CREATE TEMPORARY TABLE `PROCESSLIST` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW processlist;
Id User Host db Command Time State Info
ID root HOST_NAME information_schema Query TIME NULL SHOW processlist
@@ -100,7 +100,7 @@ PROCESSLIST CREATE TEMPORARY TABLE `PROCESSLIST` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
+) DEFAULT CHARSET=utf8
SHOW processlist;
Id User Host db Command Time State Info
ID ddicttestuser1 HOST_NAME information_schema Query TIME NULL SHOW processlist
diff --git a/mysql-test/suite/funcs_1/r/processlist_val_no_prot.result b/mysql-test/suite/funcs_1/r/processlist_val_no_prot.result
index 482e143fd23..6edcd98784d 100644
--- a/mysql-test/suite/funcs_1/r/processlist_val_no_prot.result
+++ b/mysql-test/suite/funcs_1/r/processlist_val_no_prot.result
@@ -20,240 +20,139 @@ PROCESSLIST CREATE TEMPORARY TABLE `PROCESSLIST` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
-# Ensure that the information about the own connection is correct.
-#--------------------------------------------------------------------------
-
+) DEFAULT CHARSET=utf8
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST;
+COUNT(*)
+1
+USE test;
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> root <HOST_NAME> test Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> root localhost test Query 0 executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> root <HOST_NAME> test Query <TIME> NULL SHOW FULL PROCESSLIST
-SET @default_id = CONNECTION_ID();
-SELECT COUNT(*) = 1 AS "Expect exact one connection with this id"
-FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @default_id;
-Expect exact one connection with this id
-1
-SELECT COUNT(*) = 1 AS "Expect 1"
-FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @default_id
-AND USER = 'root' AND DB = 'test' AND Command IN('Query','Execute')
-AND State = 'executing';
-Expect 1
-1
+<ID> root localhost test Query 0 NULL SHOW FULL PROCESSLIST
USE information_schema;
-SELECT COUNT(*) = 1 AS "Is the DB correct?"
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id AND DB = 'information_schema';
-Is the DB correct?
-1
-SELECT @my_info := INFO FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id;
-@my_info := INFO
-SELECT @my_info := INFO FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id
-SELECT @my_info = 'SELECT @my_info := INFO FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id'
- AS 'Is the content of PROCESSLIST.INFO correct?';
-Is the content of PROCESSLIST.INFO correct?
-1
-SELECT COUNT(*) = 1 AS "Has TIME a reasonable value?"
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id AND 0 <= TIME < 10;
-Has TIME a reasonable value?
-1
-# Ensure that the information about an inactive connection is correct.
-#--------------------------------------------------------------------------
-
-# ----- establish connection con1 (user = test_user) -----
-
-# ----- switch to connection default (user = root) -----
-
-# Poll till the connection con1 is in state COMMAND = 'Sleep'.
-
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> root <HOST_NAME> information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> root localhost information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-SELECT ID,TIME INTO @test_user_con1_id,@time FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE COMMAND = 'Sleep' AND USER = 'test_user';
-SELECT @test_user_con1_id = @default_id + 1
-AS "Did we got the next higher PROCESSLIST ID?";
-Did we got the next higher PROCESSLIST ID?
-1
-SELECT 0 <= @time < 10 AS "Has TIME a reasonable value?";
-Has TIME a reasonable value?
+<ID> root localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
+SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST;
+INFO
+SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST
+SELECT ID INTO @my_proclist_id FROM INFORMATION_SCHEMA.PROCESSLIST;
+
+----- establish connection ddicttestuser1 (user = ddicttestuser1) -----
+
+----- switch to connection default (user = root) -----
+SELECT @time > 0;
+@time > 0
1
-SELECT COUNT(*) = 2 AS "Is HOST LIKE 'localhost%'?"
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE HOST LIKE 'localhost%';
-Is HOST LIKE 'localhost%'?
+# Sleep some time
+SELECT @time < @time2;
+@time < @time2
1
-SELECT COUNT(*) = 1 AS "Expect 1"
-FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @test_user_con1_id
-AND USER = 'test_user' AND DB = 'information_schema'
- AND Command = 'Sleep' AND State = '' AND INFO IS NULL;
-Expect 1
+SELECT ID = @my_proclist_id + 1 FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE USER = 'ddicttestuser1';
+ID = @my_proclist_id + 1
1
-# Ensure that the user test_user sees only connections with his username
-# because he has not the PROCESS privilege.
-#----------------------------------------------------------------------------
-
-# ----- switch to connection con1 (user = test_user) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> test_user <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-# Ensure that the user test_user sees all connections with his username.
-#----------------------------------------------------------------------------
-
------ establish connection con2 (user = test_user) ------
-
-# ----- switch to connection default (user = root) -----
-
-# Poll till all connections of 'test_user' are in a state with COMMAND = 'Sleep'
-
-# ----- switch to connection con2 (user = test_user) -----
+<ID> ddicttestuser1 localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
+----- establish connection con2 (user = ddicttestuser1) ------
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
+<ID> ddicttestuser1 localhost information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Sleep <TIME> NULL
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> test_user <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-# ----- switch to connection default (user = root) -----
-
-SELECT ID INTO @test_user_con2_id FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID <> @test_user_con1_id
-AND USER = 'test_user' AND DB = 'information_schema';
-# Ensure we get correct information about a connection during work
-#----------------------------------------------------------------------------
+<ID> ddicttestuser1 localhost information_schema Sleep <TIME> NULL
+<ID> ddicttestuser1 localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-# ----- switch to connection con2 (user = test_user) -----
+----- switch to connection default (user = root) -----
+----- close connection con2 -----
-# Send a long enough running statement to the server, but do not
-# wait till the result comes back.
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
-SELECT sleep(10), 17;
-# ----- switch to connection default (user = root) -----
-# Poll till connection con2 is in state 'User sleep'.
+# Send a long enough running statement to the server, but do not
+# wait till the result comes back. We will pull this later.
+SELECT sleep(2.5),'Command time';
-SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
-ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Query <TIME> User sleep SELECT sleep(10), 17
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> root <HOST_NAME> information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
-SHOW FULL PROCESSLIST;
-Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> test_user <HOST_NAME> information_schema Query <TIME> User sleep SELECT sleep(10), 17
-SELECT STATE, TIME, INFO INTO @state, @time, @info
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @test_user_con2_id;
-SELECT 0 <= @time < 10 AS "Has TIME a reasonable value?";
-Has TIME a reasonable value?
+----- switch to connection default (user = root) -----
+# Sleep some time
+SELECT @time > 0;
+@time > 0
1
-SELECT @state = 'User sleep' AS "Has STATE the expected value?";
-Has STATE the expected value?
+# Sleep some time
+SELECT @time < @time2;
+@time < @time2
1
-SELECT @info = 'SELECT sleep(10), 17' AS "Has INFO the expected value?";
-Has INFO the expected value?
-1
-# ----- switch to connection con2 (user = testuser) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
# Pull("reap") the result set from the statement executed with "send".
+sleep(2.5) Command time
+0 Command time
-sleep(10) 17
-0 17
-# ----- switch to connection default (user = root) -----
-# Poll till all connections of 'test_user' are in a state with COMMAND = 'Sleep'
+# Send a long (21 KB code and runtime = 2 seconds) statement to the server,
+# but do not wait till the result comes back. We will pull this later.
+SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END' AS "my_monster_statement";
-# Ensure that we see that a connection "hangs" when colliding with a
-# WRITE TABLE LOCK
-#----------------------------------------------------------------------------
+----- switch to connection default (user = root) -----
+# Sleep some time
+SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
+ID USER HOST DB COMMAND TIME STATE INFO
+<ID> ddicttestuser1 localhost information_schema <COMMAND> <TIME> <STATE> SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END' AS "my_monster_statement"
+<ID> root localhost information_schema <COMMAND> <TIME> <STATE> SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+SHOW FULL PROCESSLIST;
+Id User Host db Command Time State Info
+<ID> root localhost information_schema <COMMAND> <TIME> <STATE> SHOW FULL PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema <COMMAND> <TIME> <STATE> SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END' AS "my_monster_statement"
+SHOW PROCESSLIST;
+Id User Host db Command Time State Info
+<ID> root localhost information_schema <COMMAND> <TIME> <STATE> SHOW PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema <COMMAND> <TIME> <STATE> SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representativ
+
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
+# Pull("reap") the result set from the monster statement executed with "send".
+sleep(2) my_monster_statement
+0 BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END
+----- switch to connection default (user = root) -----
LOCK TABLE test.t1 WRITE;
-# ----- switch to connection con2 (user = test_user) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
# Send a statement to the server, but do not wait till the result
# comes back. We will pull this later.
-
SELECT COUNT(*) FROM test.t1;
-# ----- switch to connection default (user = root) -----
-
-# Poll till INFO is no more NULL and State = 'Locked'.
+----- switch to connection default (user = root) -----
+# Sleep some time
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Query <TIME> Locked SELECT COUNT(*) FROM test.t1
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> root <HOST_NAME> information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Query <TIME> Locked SELECT COUNT(*) FROM test.t1
+<ID> root localhost information_schema Query <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+SHOW FULL PROCESSLIST;
+Id User Host db Command Time State Info
+<ID> root localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Query <TIME> Locked SELECT COUNT(*) FROM test.t1
UNLOCK TABLES;
-# ----- switch to connection con2 (user = test_user) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
# Pull("reap") the result set from the statement executed with "send".
-
COUNT(*)
0
-# Ensure that SHOW/SELECT processlist can handle extreme long commands
-#----------------------------------------------------------------------------
-
-# ----- switch to connection default (user = root) -----
-
-LOCK TABLE test.t1 WRITE;
-# ----- switch to connection con2 (user = test_user) -----
-
-# Send a long (~20 KB code) statement to the server, but do not wait
-# till the result comes back. We will pull this later.
-SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END' AS "Long string" FROM test.t1;
-# ----- switch to connection default (user = root) -----
+----- switch to connection default (user = root) -----
-# Poll till INFO is no more NULL and State = 'Locked'.
-
-# Expect result:
-# Statement Content of INFO
-# SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST Complete statement
-# SHOW FULL PROCESSLIST Complete statement
-# SHOW PROCESSLIST statement truncated after 100 char
-
-SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
-ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END' AS "Long string" FROM test.t1
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> NULL
-<ID> root <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
-SHOW FULL PROCESSLIST;
-Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SHOW FULL PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> NULL
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END' AS "Long string" FROM test.t1
-SHOW PROCESSLIST;
-Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SHOW PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> NULL
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representativ
-UNLOCK TABLES;
-# ----- switch to connection con2 (user = test_user) -----
-
-# Pull("reap") the result set from the monster statement executed with "send".
-
-count(*) Long string
-0 BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END
-# ----- switch to connection default (user = root) -----
-
------ disconnect con1 and con2 -----
-
-DROP USER test_user@'localhost';
+----- close connection ddicttestuser1 -----
+DROP USER ddicttestuser1@'localhost';
DROP TABLE test.t1;
diff --git a/mysql-test/suite/funcs_1/r/processlist_val_ps.result b/mysql-test/suite/funcs_1/r/processlist_val_ps.result
index 72ca56d0ffa..b9b1887d146 100644
--- a/mysql-test/suite/funcs_1/r/processlist_val_ps.result
+++ b/mysql-test/suite/funcs_1/r/processlist_val_ps.result
@@ -20,240 +20,139 @@ PROCESSLIST CREATE TEMPORARY TABLE `PROCESSLIST` (
`TIME` bigint(7) NOT NULL DEFAULT '0',
`STATE` varchar(64) DEFAULT NULL,
`INFO` longtext
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
-# Ensure that the information about the own connection is correct.
-#--------------------------------------------------------------------------
-
+) DEFAULT CHARSET=utf8
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST;
+COUNT(*)
+1
+USE test;
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> root <HOST_NAME> test Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> root localhost test Execute 0 executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> root <HOST_NAME> test Query <TIME> NULL SHOW FULL PROCESSLIST
-SET @default_id = CONNECTION_ID();
-SELECT COUNT(*) = 1 AS "Expect exact one connection with this id"
-FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @default_id;
-Expect exact one connection with this id
-1
-SELECT COUNT(*) = 1 AS "Expect 1"
-FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @default_id
-AND USER = 'root' AND DB = 'test' AND Command IN('Query','Execute')
-AND State = 'executing';
-Expect 1
-1
+<ID> root localhost test Query 0 NULL SHOW FULL PROCESSLIST
USE information_schema;
-SELECT COUNT(*) = 1 AS "Is the DB correct?"
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id AND DB = 'information_schema';
-Is the DB correct?
-1
-SELECT @my_info := INFO FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id;
-@my_info := INFO
-SELECT @my_info := INFO FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id
-SELECT @my_info = 'SELECT @my_info := INFO FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id'
- AS 'Is the content of PROCESSLIST.INFO correct?';
-Is the content of PROCESSLIST.INFO correct?
-1
-SELECT COUNT(*) = 1 AS "Has TIME a reasonable value?"
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @default_id AND 0 <= TIME < 10;
-Has TIME a reasonable value?
-1
-# Ensure that the information about an inactive connection is correct.
-#--------------------------------------------------------------------------
-
-# ----- establish connection con1 (user = test_user) -----
-
-# ----- switch to connection default (user = root) -----
-
-# Poll till the connection con1 is in state COMMAND = 'Sleep'.
-
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> root <HOST_NAME> information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> root localhost information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-SELECT ID,TIME INTO @test_user_con1_id,@time FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE COMMAND = 'Sleep' AND USER = 'test_user';
-SELECT @test_user_con1_id = @default_id + 1
-AS "Did we got the next higher PROCESSLIST ID?";
-Did we got the next higher PROCESSLIST ID?
-1
-SELECT 0 <= @time < 10 AS "Has TIME a reasonable value?";
-Has TIME a reasonable value?
+<ID> root localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
+SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST;
+INFO
+SELECT INFO FROM INFORMATION_SCHEMA.PROCESSLIST
+SELECT ID INTO @my_proclist_id FROM INFORMATION_SCHEMA.PROCESSLIST;
+
+----- establish connection ddicttestuser1 (user = ddicttestuser1) -----
+
+----- switch to connection default (user = root) -----
+SELECT @time > 0;
+@time > 0
1
-SELECT COUNT(*) = 2 AS "Is HOST LIKE 'localhost%'?"
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE HOST LIKE 'localhost%';
-Is HOST LIKE 'localhost%'?
+# Sleep some time
+SELECT @time < @time2;
+@time < @time2
1
-SELECT COUNT(*) = 1 AS "Expect 1"
-FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @test_user_con1_id
-AND USER = 'test_user' AND DB = 'information_schema'
- AND Command = 'Sleep' AND State = '' AND INFO IS NULL;
-Expect 1
+SELECT ID = @my_proclist_id + 1 FROM INFORMATION_SCHEMA.PROCESSLIST
+WHERE USER = 'ddicttestuser1';
+ID = @my_proclist_id + 1
1
-# Ensure that the user test_user sees only connections with his username
-# because he has not the PROCESS privilege.
-#----------------------------------------------------------------------------
-
-# ----- switch to connection con1 (user = test_user) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> test_user <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-# Ensure that the user test_user sees all connections with his username.
-#----------------------------------------------------------------------------
-
------ establish connection con2 (user = test_user) ------
-
-# ----- switch to connection default (user = root) -----
-
-# Poll till all connections of 'test_user' are in a state with COMMAND = 'Sleep'
-
-# ----- switch to connection con2 (user = test_user) -----
+<ID> ddicttestuser1 localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
+----- establish connection con2 (user = ddicttestuser1) ------
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
+<ID> ddicttestuser1 localhost information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Sleep <TIME> NULL
SHOW FULL PROCESSLIST;
Id User Host db Command Time State Info
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> test_user <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-# ----- switch to connection default (user = root) -----
-
-SELECT ID INTO @test_user_con2_id FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID <> @test_user_con1_id
-AND USER = 'test_user' AND DB = 'information_schema';
-# Ensure we get correct information about a connection during work
-#----------------------------------------------------------------------------
+<ID> ddicttestuser1 localhost information_schema Sleep <TIME> NULL
+<ID> ddicttestuser1 localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-# ----- switch to connection con2 (user = test_user) -----
+----- switch to connection default (user = root) -----
+----- close connection con2 -----
-# Send a long enough running statement to the server, but do not
-# wait till the result comes back.
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
-SELECT sleep(10), 17;
-# ----- switch to connection default (user = root) -----
-# Poll till connection con2 is in state 'User sleep'.
+# Send a long enough running statement to the server, but do not
+# wait till the result comes back. We will pull this later.
+SELECT sleep(2.5),'Command time';
-SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
-ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Query <TIME> User sleep SELECT sleep(10), 17
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> root <HOST_NAME> information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
-SHOW FULL PROCESSLIST;
-Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> test_user <HOST_NAME> information_schema Query <TIME> User sleep SELECT sleep(10), 17
-SELECT STATE, TIME, INFO INTO @state, @time, @info
-FROM INFORMATION_SCHEMA.PROCESSLIST
-WHERE ID = @test_user_con2_id;
-SELECT 0 <= @time < 10 AS "Has TIME a reasonable value?";
-Has TIME a reasonable value?
+----- switch to connection default (user = root) -----
+# Sleep some time
+SELECT @time > 0;
+@time > 0
1
-SELECT @state = 'User sleep' AS "Has STATE the expected value?";
-Has STATE the expected value?
+# Sleep some time
+SELECT @time < @time2;
+@time < @time2
1
-SELECT @info = 'SELECT sleep(10), 17' AS "Has INFO the expected value?";
-Has INFO the expected value?
-1
-# ----- switch to connection con2 (user = testuser) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
# Pull("reap") the result set from the statement executed with "send".
+sleep(2.5) Command time
+0 Command time
-sleep(10) 17
-0 17
-# ----- switch to connection default (user = root) -----
-# Poll till all connections of 'test_user' are in a state with COMMAND = 'Sleep'
+# Send a long (21 KB code and runtime = 2 seconds) statement to the server,
+# but do not wait till the result comes back. We will pull this later.
+SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END' AS "my_monster_statement";
-# Ensure that we see that a connection "hangs" when colliding with a
-# WRITE TABLE LOCK
-#----------------------------------------------------------------------------
+----- switch to connection default (user = root) -----
+# Sleep some time
+SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
+ID USER HOST DB COMMAND TIME STATE INFO
+<ID> ddicttestuser1 localhost information_schema <COMMAND> <TIME> <STATE> SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END' AS "my_monster_statement"
+<ID> root localhost information_schema <COMMAND> <TIME> <STATE> SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+SHOW FULL PROCESSLIST;
+Id User Host db Command Time State Info
+<ID> root localhost information_schema <COMMAND> <TIME> <STATE> SHOW FULL PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema <COMMAND> <TIME> <STATE> SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END' AS "my_monster_statement"
+SHOW PROCESSLIST;
+Id User Host db Command Time State Info
+<ID> root localhost information_schema <COMMAND> <TIME> <STATE> SHOW PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema <COMMAND> <TIME> <STATE> SELECT sleep(2),'BEGIN this is the representative of a very long statement.this is the representativ
+
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
+# Pull("reap") the result set from the monster statement executed with "send".
+sleep(2) my_monster_statement
+0 BEGIN this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.this is the representative of a very long statement.END
+----- switch to connection default (user = root) -----
LOCK TABLE test.t1 WRITE;
-# ----- switch to connection con2 (user = test_user) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
# Send a statement to the server, but do not wait till the result
# comes back. We will pull this later.
-
SELECT COUNT(*) FROM test.t1;
-# ----- switch to connection default (user = root) -----
-
-# Poll till INFO is no more NULL and State = 'Locked'.
+----- switch to connection default (user = root) -----
+# Sleep some time
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema Query <TIME> Locked SELECT COUNT(*) FROM test.t1
-<ID> test_user <HOST_NAME> information_schema Sleep <TIME> NULL
-<ID> root <HOST_NAME> information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Query <TIME> Locked SELECT COUNT(*) FROM test.t1
+<ID> root localhost information_schema Execute <TIME> executing SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
+SHOW FULL PROCESSLIST;
+Id User Host db Command Time State Info
+<ID> root localhost information_schema Query <TIME> NULL SHOW FULL PROCESSLIST
+<ID> ddicttestuser1 localhost information_schema Query <TIME> Locked SELECT COUNT(*) FROM test.t1
UNLOCK TABLES;
-# ----- switch to connection con2 (user = test_user) -----
+----- switch to connection ddicttestuser1 (user = ddicttestuser1) -----
# Pull("reap") the result set from the statement executed with "send".
-
COUNT(*)
0
-# Ensure that SHOW/SELECT processlist can handle extreme long commands
-#----------------------------------------------------------------------------
-
-# ----- switch to connection default (user = root) -----
-
-LOCK TABLE test.t1 WRITE;
-# ----- switch to connection con2 (user = test_user) -----
-
-# Send a long (~20 KB code) statement to the server, but do not wait
-# till the result comes back. We will pull this later.
-SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END' AS "Long string" FROM test.t1;
-# ----- switch to connection default (user = root) -----
+----- switch to connection default (user = root) -----
-# Poll till INFO is no more NULL and State = 'Locked'.
-
-# Expect result:
-# Statement Content of INFO
-# SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST Complete statement
-# SHOW FULL PROCESSLIST Complete statement
-# SHOW PROCESSLIST statement truncated after 100 char
-
-SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
-ID USER HOST DB COMMAND TIME STATE INFO
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END' AS "Long string" FROM test.t1
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> NULL
-<ID> root <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
-SHOW FULL PROCESSLIST;
-Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SHOW FULL PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> NULL
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END' AS "Long string" FROM test.t1
-SHOW PROCESSLIST;
-Id User Host db Command Time State Info
-<ID> root <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SHOW PROCESSLIST
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> NULL
-<ID> test_user <HOST_NAME> information_schema <COMMAND> <TIME> <STATE> SELECT count(*),'BEGIN-This is the representative of a very long statement.This is the representativ
-UNLOCK TABLES;
-# ----- switch to connection con2 (user = test_user) -----
-
-# Pull("reap") the result set from the monster statement executed with "send".
-
-count(*) Long string
-0 BEGIN-This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.This is the representative of a very long statement.-END
-# ----- switch to connection default (user = root) -----
-
------ disconnect con1 and con2 -----
-
-DROP USER test_user@'localhost';
+----- close connection ddicttestuser1 -----
+DROP USER ddicttestuser1@'localhost';
DROP TABLE test.t1;
diff --git a/mysql-test/suite/funcs_1/t/is_columns.test b/mysql-test/suite/funcs_1/t/is_columns.test
index 20b832ca5c3..b960c608e7d 100644
--- a/mysql-test/suite/funcs_1/t/is_columns.test
+++ b/mysql-test/suite/funcs_1/t/is_columns.test
@@ -78,6 +78,7 @@ eval SHOW TABLES FROM information_schema LIKE '$is_table';
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval DESCRIBE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
eval SHOW CREATE TABLE information_schema.$is_table;
--source suite/funcs_1/datadict/datadict_bug_12777.inc
eval SHOW COLUMNS FROM information_schema.$is_table;
diff --git a/mysql-test/suite/funcs_1/t/is_events.test b/mysql-test/suite/funcs_1/t/is_events.test
index 583e946e7f0..22565840728 100644
--- a/mysql-test/suite/funcs_1/t/is_events.test
+++ b/mysql-test/suite/funcs_1/t/is_events.test
@@ -89,6 +89,7 @@ eval SHOW TABLES FROM information_schema LIKE '$is_table';
# is associated.
#
eval DESCRIBE information_schema.$is_table;
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
eval SHOW CREATE TABLE information_schema.$is_table;
eval SHOW COLUMNS FROM information_schema.$is_table;
diff --git a/mysql-test/suite/maria/r/maria-autozerofill.result b/mysql-test/suite/maria/r/maria-autozerofill.result
new file mode 100644
index 00000000000..0b069cd7a52
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-autozerofill.result
@@ -0,0 +1,20 @@
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+create table t1(a int) engine=maria;
+insert into t1 values(1);
+flush table t1;
+create_rename_lsn has non-magic value
+* shut down mysqld, removed logs, restarted it
+select * from t1;
+a
+1
+Warnings:
+Error 1194 t1' is marked as crashed and should be repaired
+flush table t1;
+Status: changed,sorted index pages,zerofilled,movable
+create_rename_lsn has magic value
+insert into t1 values(2);
+flush table t1;
+create_rename_lsn has non-magic value
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria-big.result b/mysql-test/suite/maria/r/maria-big.result
new file mode 100644
index 00000000000..64b3296b6b2
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-big.result
@@ -0,0 +1,222 @@
+set global max_allowed_packet=400000000;
+set storage_engine=maria;
+affected rows: 0
+drop table if exists t1, t2;
+affected rows: 0
+create table t1(a char(3));
+affected rows: 0
+insert into t1 values("abc");
+affected rows: 1
+insert into t1 select "def" from t1;
+affected rows: 1
+info: Records: 1 Duplicates: 0 Warnings: 0
+insert into t1 select "ghi" from t1;
+affected rows: 2
+info: Records: 2 Duplicates: 0 Warnings: 0
+insert into t1 select "jkl" from t1;
+affected rows: 4
+info: Records: 4 Duplicates: 0 Warnings: 0
+insert into t1 select "mno" from t1;
+affected rows: 8
+info: Records: 8 Duplicates: 0 Warnings: 0
+insert into t1 select "pqr" from t1;
+affected rows: 16
+info: Records: 16 Duplicates: 0 Warnings: 0
+insert into t1 select "stu" from t1;
+affected rows: 32
+info: Records: 32 Duplicates: 0 Warnings: 0
+insert into t1 select "vwx" from t1;
+affected rows: 64
+info: Records: 64 Duplicates: 0 Warnings: 0
+insert into t1 select "yza" from t1;
+affected rows: 128
+info: Records: 128 Duplicates: 0 Warnings: 0
+insert into t1 select "ceg" from t1;
+affected rows: 256
+info: Records: 256 Duplicates: 0 Warnings: 0
+insert into t1 select "ikm" from t1;
+affected rows: 512
+info: Records: 512 Duplicates: 0 Warnings: 0
+insert into t1 select "oqs" from t1;
+affected rows: 1024
+info: Records: 1024 Duplicates: 0 Warnings: 0
+select count(*) from t1;
+count(*)
+2048
+affected rows: 1
+insert into t1 select "uwy" from t1;
+affected rows: 2048
+info: Records: 2048 Duplicates: 0 Warnings: 0
+create table t2 select * from t1;
+affected rows: 4096
+info: Records: 4096 Duplicates: 0 Warnings: 0
+select count(*) from t1;
+count(*)
+4096
+affected rows: 1
+select count(*) from t2;
+count(*)
+4096
+affected rows: 1
+drop table t1, t2;
+affected rows: 0
+create table t1 (a int, b longtext);
+affected rows: 0
+insert into t1 values (1,"123456789012345678901234567890"),(2,"09876543210987654321");
+affected rows: 2
+info: Records: 2 Duplicates: 0 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=CONCAT(b,b);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+select a,length(b) from t1;
+a length(b)
+1 251658240
+2 167772160
+affected rows: 2
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+affected rows: 1
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+update t1 set b=mid(b,1,length(b)/2);
+affected rows: 2
+info: Rows matched: 2 Changed: 2 Warnings: 0
+select a,length(b) from t1;
+a length(b)
+1 60
+2 40
+affected rows: 2
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+affected rows: 1
+drop table t1;
+affected rows: 0
diff --git a/mysql-test/suite/maria/r/maria-big2.result b/mysql-test/suite/maria/r/maria-big2.result
new file mode 100644
index 00000000000..847f6682f4a
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-big2.result
@@ -0,0 +1,6 @@
+create table t2(id int,a varchar(255),b varchar(255),key(a))engine=maria row_format=dynamic transactional=0;
+Table Op Msg_type Msg_text
+test.t2 check status OK
+Table Op Msg_type Msg_text
+test.t2 check status OK
+drop table t2;
diff --git a/mysql-test/suite/maria/r/maria-connect.result b/mysql-test/suite/maria/r/maria-connect.result
new file mode 100644
index 00000000000..8fe483c8467
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-connect.result
@@ -0,0 +1,23 @@
+set global storage_engine=maria;
+set session storage_engine=maria;
+drop table if exists t1;
+SET SQL_WARNINGS=1;
+RESET MASTER;
+set binlog_format=statement;
+CREATE TABLE t1 (a int primary key);
+insert t1 values (1),(2),(3);
+insert t1 values (4),(2),(5);
+ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
+select * from t1;
+a
+1
+2
+3
+4
+SHOW BINLOG EVENTS FROM 106;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 106 Query 1 204 use `test`; CREATE TABLE t1 (a int primary key)
+master-bin.000001 204 Query 1 295 use `test`; insert t1 values (1),(2),(3)
+master-bin.000001 295 Query 1 386 use `test`; insert t1 values (4),(2),(5)
+drop table t1;
+set binlog_format=default;
diff --git a/mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result b/mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result
new file mode 100644
index 00000000000..189872e8e13
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-gis-rtree-dynamic.result
@@ -0,0 +1,1500 @@
+set storage_engine=maria;
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL,
+SPATIAL KEY(g)
+) row_format=dynamic;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `fid` int(11) NOT NULL AUTO_INCREMENT,
+ `g` geometry NOT NULL,
+ PRIMARY KEY (`fid`),
+ SPATIAL KEY `g` (`g`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 ROW_FORMAT=DYNAMIC
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(148 148, 152 152)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(147 147, 153 153)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(146 146, 154 154)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(145 145, 155 155)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(144 144, 156 156)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(143 143, 157 157)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(142 142, 158 158)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(141 141, 159 159)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(140 140, 160 160)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(139 139, 161 161)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(138 138, 162 162)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(137 137, 163 163)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(136 136, 164 164)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(135 135, 165 165)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(134 134, 166 166)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(133 133, 167 167)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(132 132, 168 168)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(131 131, 169 169)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(130 130, 170 170)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(129 129, 171 171)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(128 128, 172 172)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(127 127, 173 173)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(126 126, 174 174)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(125 125, 175 175)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(124 124, 176 176)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(123 123, 177 177)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(122 122, 178 178)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(121 121, 179 179)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(120 120, 180 180)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(119 119, 181 181)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(118 118, 182 182)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(117 117, 183 183)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(116 116, 184 184)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(115 115, 185 185)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(114 114, 186 186)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(113 113, 187 187)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(112 112, 188 188)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(111 111, 189 189)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(110 110, 190 190)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(109 109, 191 191)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(108 108, 192 192)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(107 107, 193 193)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(106 106, 194 194)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(105 105, 195 195)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(104 104, 196 196)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(103 103, 197 197)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(102 102, 198 198)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(101 101, 199 199)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(100 100, 200 200)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(99 99, 201 201)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(98 98, 202 202)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(97 97, 203 203)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(96 96, 204 204)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(95 95, 205 205)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(94 94, 206 206)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(93 93, 207 207)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(92 92, 208 208)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(91 91, 209 209)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(90 90, 210 210)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(89 89, 211 211)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(88 88, 212 212)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(87 87, 213 213)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(86 86, 214 214)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(85 85, 215 215)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(84 84, 216 216)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(83 83, 217 217)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(82 82, 218 218)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(81 81, 219 219)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(80 80, 220 220)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(79 79, 221 221)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(78 78, 222 222)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(77 77, 223 223)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(76 76, 224 224)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(75 75, 225 225)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(74 74, 226 226)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(73 73, 227 227)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(72 72, 228 228)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(71 71, 229 229)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(70 70, 230 230)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(69 69, 231 231)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(68 68, 232 232)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(67 67, 233 233)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(66 66, 234 234)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(65 65, 235 235)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(64 64, 236 236)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(63 63, 237 237)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(62 62, 238 238)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(61 61, 239 239)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(60 60, 240 240)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(59 59, 241 241)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(58 58, 242 242)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(57 57, 243 243)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(56 56, 244 244)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(55 55, 245 245)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(54 54, 246 246)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(53 53, 247 247)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(52 52, 248 248)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(51 51, 249 249)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(50 50, 250 250)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(49 49, 251 251)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(48 48, 252 252)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(47 47, 253 253)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(46 46, 254 254)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(45 45, 255 255)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(44 44, 256 256)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(43 43, 257 257)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(42 42, 258 258)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(41 41, 259 259)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(40 40, 260 260)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(39 39, 261 261)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(38 38, 262 262)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(37 37, 263 263)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(36 36, 264 264)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(35 35, 265 265)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(34 34, 266 266)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(33 33, 267 267)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(32 32, 268 268)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(31 31, 269 269)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(30 30, 270 270)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(29 29, 271 271)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(28 28, 272 272)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(27 27, 273 273)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(26 26, 274 274)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(25 25, 275 275)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(24 24, 276 276)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(23 23, 277 277)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(22 22, 278 278)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(21 21, 279 279)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(20 20, 280 280)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(19 19, 281 281)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(18 18, 282 282)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(17 17, 283 283)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(16 16, 284 284)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(15 15, 285 285)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(14 14, 286 286)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(13 13, 287 287)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(12 12, 288 288)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(11 11, 289 289)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(10 10, 290 290)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(9 9, 291 291)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(8 8, 292 292)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(7 7, 293 293)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(6 6, 294 294)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(5 5, 295 295)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(4 4, 296 296)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(3 3, 297 297)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(2 2, 298 298)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 1, 299 299)'));
+SELECT count(*) FROM t1;
+count(*)
+150
+EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range g g 34 NULL 11 Using where
+SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+fid AsText(g)
+1 LINESTRING(150 150,150 150)
+2 LINESTRING(149 149,151 151)
+3 LINESTRING(148 148,152 152)
+4 LINESTRING(147 147,153 153)
+5 LINESTRING(146 146,154 154)
+6 LINESTRING(145 145,155 155)
+7 LINESTRING(144 144,156 156)
+8 LINESTRING(143 143,157 157)
+9 LINESTRING(142 142,158 158)
+10 LINESTRING(141 141,159 159)
+11 LINESTRING(140 140,160 160)
+DROP TABLE t1;
+CREATE TABLE t2 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL
+) row_format=dynamic;
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))));
+ALTER TABLE t2 ADD SPATIAL KEY(g);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `fid` int(11) NOT NULL AUTO_INCREMENT,
+ `g` geometry NOT NULL,
+ PRIMARY KEY (`fid`),
+ SPATIAL KEY `g` (`g`)
+) ENGINE=MARIA AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 ROW_FORMAT=DYNAMIC
+SELECT count(*) FROM t2;
+count(*)
+100
+EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range g g 34 NULL 4 Using where
+SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+fid AsText(g)
+45 LINESTRING(51 51,60 60)
+46 LINESTRING(51 41,60 50)
+55 LINESTRING(41 51,50 60)
+56 LINESTRING(41 41,50 50)
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+99
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+98
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+97
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+96
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+95
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+94
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+93
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+92
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+91
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+90
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+89
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+88
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+87
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+86
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+85
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+84
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+83
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+82
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+81
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+80
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+79
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+78
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+77
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+76
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+75
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+74
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+73
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+72
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+71
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+70
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+69
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+68
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+67
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+66
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+65
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+64
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+63
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+62
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+61
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+60
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+59
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+58
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+57
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+56
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+55
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+54
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+53
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+52
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+51
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+50
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+49
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+48
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+47
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+46
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+45
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+44
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+43
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+42
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+41
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+40
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+39
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+38
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+37
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+36
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+35
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+34
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+33
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+32
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+31
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+30
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+29
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+28
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+27
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+26
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+25
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+24
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+23
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+22
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+21
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+20
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+19
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+18
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+17
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+16
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+15
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+14
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+13
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+12
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+11
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+10
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+9
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+8
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+7
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+6
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+5
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+4
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+3
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+2
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+1
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+0
+DROP TABLE t2;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a)) row_format=dynamic;
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+drop table t1;
+CREATE TABLE t1 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL,
+SPATIAL KEY(g)
+) row_format=dynamic;
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
+drop table t1;
+CREATE TABLE t1 (
+line LINESTRING NOT NULL,
+kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+name VARCHAR(32),
+SPATIAL KEY (line)
+) row_format=dynamic;
+ALTER TABLE t1 DISABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES
+("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+ALTER TABLE t1 ENABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES ("austria", "pp", GeomFromText('LINESTRING(14.9906 48.9887,14.9946 48.9904,14.9947 48.9916)'));
+drop table t1;
+CREATE TABLE t1 (st varchar(100));
+INSERT INTO t1 VALUES ("Fake string");
+CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)) row_format=dynamic;
+INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+drop table t1, t2;
+CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) row_format=dynamic DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'geometry' can't have a default value
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
+-66.8158332999, -18.7186111000 -66.8102777000, -18.7211111000 -66.9269443999,
+-18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-65.7402776999 -96.6686111000, -65.7372222000
+-96.5516666000, -65.8502777000 -96.5461111000, -65.8527777000 -96.6627777000,
+-65.7402776999 -96.6686111000))'));
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+CREATE TABLE t1 (
+c1 geometry NOT NULL default '',
+SPATIAL KEY i1 (c1)
+) row_format=dynamic DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'c1' can't have a default value
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 geometry NOT NULL default '',
+SPATIAL KEY i1 (c1)
+) row_format=dynamic DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'c1' can't have a default value
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-65.7402776999 -96.6686111000,
+ -65.7372222000 -96.5516666000,
+ -65.8502777000 -96.5461111000,
+ -65.8527777000 -96.6627777000,
+ -65.7402776999 -96.6686111000))'));
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) row_format=dynamic;
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
+SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
+1
+1
+1
+1
+DROP TABLE t1;
+CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
+c2 varchar(15) collate utf8_bin default NULL,
+c1 varchar(15) collate utf8_bin default NULL,
+c3 varchar(10) collate utf8_bin default NULL,
+spatial_point point NOT NULL,
+PRIMARY KEY(id),
+SPATIAL KEY (spatial_point)
+)row_format=dynamic DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('y', 's', 'j', GeomFromText('POINT(167 74)')),
+('r', 'n', 'd', GeomFromText('POINT(215 118)')),
+('g', 'n', 'e', GeomFromText('POINT(203 98)')),
+('h', 'd', 'd', GeomFromText('POINT(54 193)')),
+('r', 'x', 'y', GeomFromText('POINT(47 69)')),
+('t', 'q', 'r', GeomFromText('POINT(109 42)')),
+('a', 'z', 'd', GeomFromText('POINT(0 154)')),
+('x', 'v', 'o', GeomFromText('POINT(174 131)')),
+('b', 'r', 'a', GeomFromText('POINT(114 253)')),
+('x', 'z', 'i', GeomFromText('POINT(163 21)')),
+('w', 'p', 'i', GeomFromText('POINT(42 102)')),
+('g', 'j', 'j', GeomFromText('POINT(170 133)')),
+('m', 'g', 'n', GeomFromText('POINT(28 22)')),
+('b', 'z', 'h', GeomFromText('POINT(174 28)')),
+('q', 'k', 'f', GeomFromText('POINT(233 73)')),
+('w', 'w', 'a', GeomFromText('POINT(124 200)')),
+('t', 'j', 'w', GeomFromText('POINT(252 101)')),
+('d', 'r', 'd', GeomFromText('POINT(98 18)')),
+('w', 'o', 'y', GeomFromText('POINT(165 31)')),
+('y', 'h', 't', GeomFromText('POINT(14 220)')),
+('d', 'p', 'u', GeomFromText('POINT(223 196)')),
+('g', 'y', 'g', GeomFromText('POINT(207 96)')),
+('x', 'm', 'n', GeomFromText('POINT(214 3)')),
+('g', 'v', 'e', GeomFromText('POINT(140 205)')),
+('g', 'm', 'm', GeomFromText('POINT(10 236)')),
+('i', 'r', 'j', GeomFromText('POINT(137 228)')),
+('w', 's', 'p', GeomFromText('POINT(115 6)')),
+('o', 'n', 'k', GeomFromText('POINT(158 129)')),
+('j', 'h', 'l', GeomFromText('POINT(129 72)')),
+('f', 'x', 'l', GeomFromText('POINT(139 207)')),
+('u', 'd', 'n', GeomFromText('POINT(125 109)')),
+('b', 'a', 'z', GeomFromText('POINT(30 32)')),
+('m', 'h', 'o', GeomFromText('POINT(251 251)')),
+('f', 'r', 'd', GeomFromText('POINT(243 211)')),
+('b', 'd', 'r', GeomFromText('POINT(232 80)')),
+('g', 'k', 'v', GeomFromText('POINT(15 100)')),
+('i', 'f', 'c', GeomFromText('POINT(109 66)')),
+('r', 't', 'j', GeomFromText('POINT(178 6)')),
+('y', 'n', 'f', GeomFromText('POINT(233 211)')),
+('f', 'y', 'm', GeomFromText('POINT(99 16)')),
+('z', 'q', 'l', GeomFromText('POINT(39 49)')),
+('j', 'c', 'r', GeomFromText('POINT(75 187)')),
+('c', 'y', 'y', GeomFromText('POINT(246 253)')),
+('w', 'u', 'd', GeomFromText('POINT(56 190)')),
+('n', 'q', 'm', GeomFromText('POINT(73 149)')),
+('d', 'y', 'a', GeomFromText('POINT(134 6)')),
+('z', 's', 'w', GeomFromText('POINT(216 225)')),
+('d', 'u', 'k', GeomFromText('POINT(132 70)')),
+('f', 'v', 't', GeomFromText('POINT(187 141)')),
+('r', 'r', 'a', GeomFromText('POINT(152 39)')),
+('y', 'p', 'o', GeomFromText('POINT(45 27)')),
+('p', 'n', 'm', GeomFromText('POINT(228 148)')),
+('e', 'g', 'e', GeomFromText('POINT(88 81)')),
+('m', 'a', 'h', GeomFromText('POINT(35 29)')),
+('m', 'h', 'f', GeomFromText('POINT(30 71)')),
+('h', 'k', 'i', GeomFromText('POINT(244 78)')),
+('z', 'v', 'd', GeomFromText('POINT(241 38)')),
+('q', 'l', 'j', GeomFromText('POINT(13 71)')),
+('s', 'p', 'g', GeomFromText('POINT(108 38)')),
+('q', 's', 'j', GeomFromText('POINT(92 101)')),
+('l', 'h', 'g', GeomFromText('POINT(120 78)')),
+('w', 't', 'b', GeomFromText('POINT(193 109)')),
+('b', 's', 's', GeomFromText('POINT(223 211)')),
+('w', 'w', 'y', GeomFromText('POINT(122 42)')),
+('q', 'c', 'c', GeomFromText('POINT(104 102)')),
+('w', 'g', 'n', GeomFromText('POINT(213 120)')),
+('p', 'q', 'a', GeomFromText('POINT(247 148)')),
+('c', 'z', 'e', GeomFromText('POINT(18 106)')),
+('z', 'u', 'n', GeomFromText('POINT(70 133)')),
+('j', 'n', 'x', GeomFromText('POINT(232 13)')),
+('e', 'h', 'f', GeomFromText('POINT(22 135)')),
+('w', 'l', 'f', GeomFromText('POINT(9 180)')),
+('a', 'v', 'q', GeomFromText('POINT(163 228)')),
+('i', 'z', 'o', GeomFromText('POINT(180 100)')),
+('e', 'c', 'l', GeomFromText('POINT(182 231)')),
+('c', 'k', 'o', GeomFromText('POINT(19 60)')),
+('q', 'f', 'p', GeomFromText('POINT(79 95)')),
+('m', 'd', 'r', GeomFromText('POINT(3 127)')),
+('m', 'e', 't', GeomFromText('POINT(136 154)')),
+('w', 'w', 'w', GeomFromText('POINT(102 15)')),
+('l', 'n', 'q', GeomFromText('POINT(71 196)')),
+('p', 'k', 'c', GeomFromText('POINT(47 139)')),
+('j', 'o', 'r', GeomFromText('POINT(177 128)')),
+('j', 'q', 'a', GeomFromText('POINT(170 6)')),
+('b', 'a', 'o', GeomFromText('POINT(63 211)')),
+('g', 's', 'o', GeomFromText('POINT(144 251)')),
+('w', 'u', 'w', GeomFromText('POINT(221 214)')),
+('g', 'a', 'm', GeomFromText('POINT(14 102)')),
+('u', 'q', 'z', GeomFromText('POINT(86 200)')),
+('k', 'a', 'm', GeomFromText('POINT(144 222)')),
+('j', 'u', 'r', GeomFromText('POINT(216 142)')),
+('q', 'k', 'v', GeomFromText('POINT(121 236)')),
+('p', 'o', 'r', GeomFromText('POINT(108 102)')),
+('b', 'd', 'x', GeomFromText('POINT(127 198)')),
+('k', 's', 'a', GeomFromText('POINT(2 150)')),
+('f', 'm', 'f', GeomFromText('POINT(160 191)')),
+('q', 'y', 'x', GeomFromText('POINT(98 111)')),
+('o', 'f', 'm', GeomFromText('POINT(232 218)')),
+('c', 'w', 'j', GeomFromText('POINT(156 165)')),
+('s', 'q', 'v', GeomFromText('POINT(98 161)'));
+SET @@RAND_SEED1=692635050, @@RAND_SEED2=297339954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=159925977, @@RAND_SEED2=942570618;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=328169745, @@RAND_SEED2=410451954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+CHECK TABLE t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(19 81)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(20 177)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(221 193)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(195 205)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(15 213)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(214 63)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(243 171)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(198 82)') where c1 like 'y%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('f', 'y', 'p', GeomFromText('POINT(109 235)')),
+('b', 'e', 'v', GeomFromText('POINT(20 48)')),
+('i', 'u', 'f', GeomFromText('POINT(15 55)')),
+('o', 'r', 'z', GeomFromText('POINT(105 64)')),
+('a', 'p', 'a', GeomFromText('POINT(142 236)')),
+('g', 'i', 'k', GeomFromText('POINT(10 49)')),
+('x', 'z', 'x', GeomFromText('POINT(192 200)')),
+('c', 'v', 'r', GeomFromText('POINT(94 168)')),
+('y', 'z', 'e', GeomFromText('POINT(141 51)')),
+('h', 'm', 'd', GeomFromText('POINT(35 251)')),
+('v', 'm', 'q', GeomFromText('POINT(44 90)')),
+('j', 'l', 'z', GeomFromText('POINT(67 237)')),
+('i', 'v', 'a', GeomFromText('POINT(75 14)')),
+('b', 'q', 't', GeomFromText('POINT(153 33)')),
+('e', 'm', 'a', GeomFromText('POINT(247 49)')),
+('l', 'y', 'g', GeomFromText('POINT(56 203)')),
+('v', 'o', 'r', GeomFromText('POINT(90 54)')),
+('r', 'n', 'd', GeomFromText('POINT(135 83)')),
+('j', 't', 'u', GeomFromText('POINT(174 239)')),
+('u', 'n', 'g', GeomFromText('POINT(104 191)')),
+('p', 'q', 'y', GeomFromText('POINT(63 171)')),
+('o', 'q', 'p', GeomFromText('POINT(192 103)')),
+('f', 'x', 'e', GeomFromText('POINT(244 30)')),
+('n', 'x', 'c', GeomFromText('POINT(92 103)')),
+('r', 'q', 'z', GeomFromText('POINT(166 20)')),
+('s', 'a', 'j', GeomFromText('POINT(137 205)')),
+('z', 't', 't', GeomFromText('POINT(99 134)')),
+('o', 'm', 'j', GeomFromText('POINT(217 3)')),
+('n', 'h', 'j', GeomFromText('POINT(211 17)')),
+('v', 'v', 'a', GeomFromText('POINT(41 137)')),
+('q', 'o', 'j', GeomFromText('POINT(5 92)')),
+('z', 'y', 'e', GeomFromText('POINT(175 212)')),
+('j', 'z', 'h', GeomFromText('POINT(224 194)')),
+('a', 'g', 'm', GeomFromText('POINT(31 119)')),
+('p', 'c', 'f', GeomFromText('POINT(17 221)')),
+('t', 'h', 'k', GeomFromText('POINT(26 203)')),
+('u', 'w', 'p', GeomFromText('POINT(47 185)')),
+('z', 'a', 'c', GeomFromText('POINT(61 133)')),
+('u', 'k', 'a', GeomFromText('POINT(210 115)')),
+('k', 'f', 'h', GeomFromText('POINT(125 113)')),
+('t', 'v', 'y', GeomFromText('POINT(12 239)')),
+('u', 'v', 'd', GeomFromText('POINT(90 24)')),
+('m', 'y', 'w', GeomFromText('POINT(25 243)')),
+('d', 'n', 'g', GeomFromText('POINT(122 92)')),
+('z', 'm', 'f', GeomFromText('POINT(235 110)')),
+('q', 'd', 'f', GeomFromText('POINT(233 217)')),
+('a', 'v', 'u', GeomFromText('POINT(69 59)')),
+('x', 'k', 'p', GeomFromText('POINT(240 14)')),
+('i', 'v', 'r', GeomFromText('POINT(154 42)')),
+('w', 'h', 'l', GeomFromText('POINT(178 156)')),
+('d', 'h', 'n', GeomFromText('POINT(65 157)')),
+('c', 'k', 'z', GeomFromText('POINT(62 33)')),
+('e', 'l', 'w', GeomFromText('POINT(162 1)')),
+('r', 'f', 'i', GeomFromText('POINT(127 71)')),
+('q', 'm', 'c', GeomFromText('POINT(63 118)')),
+('c', 'h', 'u', GeomFromText('POINT(205 203)')),
+('d', 't', 'p', GeomFromText('POINT(234 87)')),
+('s', 'g', 'h', GeomFromText('POINT(149 34)')),
+('o', 'b', 'q', GeomFromText('POINT(159 179)')),
+('k', 'u', 'f', GeomFromText('POINT(202 254)')),
+('u', 'f', 'g', GeomFromText('POINT(70 15)')),
+('x', 's', 'b', GeomFromText('POINT(25 181)')),
+('s', 'c', 'g', GeomFromText('POINT(252 17)')),
+('a', 'c', 'f', GeomFromText('POINT(89 67)')),
+('r', 'e', 'q', GeomFromText('POINT(55 54)')),
+('f', 'i', 'k', GeomFromText('POINT(178 230)')),
+('p', 'e', 'l', GeomFromText('POINT(198 28)')),
+('w', 'o', 'd', GeomFromText('POINT(204 189)')),
+('c', 'a', 'g', GeomFromText('POINT(230 178)')),
+('r', 'o', 'e', GeomFromText('POINT(61 116)')),
+('w', 'a', 'a', GeomFromText('POINT(178 237)')),
+('v', 'd', 'e', GeomFromText('POINT(70 85)')),
+('k', 'c', 'e', GeomFromText('POINT(147 118)')),
+('d', 'q', 't', GeomFromText('POINT(218 77)')),
+('k', 'g', 'f', GeomFromText('POINT(192 113)')),
+('w', 'n', 'e', GeomFromText('POINT(92 124)')),
+('r', 'm', 'q', GeomFromText('POINT(130 65)')),
+('o', 'r', 'r', GeomFromText('POINT(174 233)')),
+('k', 'n', 't', GeomFromText('POINT(175 147)')),
+('q', 'm', 'r', GeomFromText('POINT(18 208)')),
+('l', 'd', 'i', GeomFromText('POINT(13 104)')),
+('w', 'o', 'y', GeomFromText('POINT(207 39)')),
+('p', 'u', 'o', GeomFromText('POINT(114 31)')),
+('y', 'a', 'p', GeomFromText('POINT(106 59)')),
+('a', 'x', 'z', GeomFromText('POINT(17 57)')),
+('v', 'h', 'x', GeomFromText('POINT(170 13)')),
+('t', 's', 'u', GeomFromText('POINT(84 18)')),
+('z', 'z', 'f', GeomFromText('POINT(250 197)')),
+('l', 'z', 't', GeomFromText('POINT(59 80)')),
+('j', 'g', 's', GeomFromText('POINT(54 26)')),
+('g', 'v', 'm', GeomFromText('POINT(89 98)')),
+('q', 'v', 'b', GeomFromText('POINT(39 240)')),
+('x', 'k', 'v', GeomFromText('POINT(246 207)')),
+('k', 'u', 'i', GeomFromText('POINT(105 111)')),
+('w', 'z', 's', GeomFromText('POINT(235 8)')),
+('d', 'd', 'd', GeomFromText('POINT(105 4)')),
+('c', 'z', 'q', GeomFromText('POINT(13 140)')),
+('m', 'k', 'i', GeomFromText('POINT(208 120)')),
+('g', 'a', 'g', GeomFromText('POINT(9 182)')),
+('z', 'j', 'r', GeomFromText('POINT(149 153)')),
+('h', 'f', 'g', GeomFromText('POINT(81 236)')),
+('m', 'e', 'q', GeomFromText('POINT(209 215)')),
+('c', 'h', 'y', GeomFromText('POINT(235 70)')),
+('i', 'e', 'g', GeomFromText('POINT(138 26)')),
+('m', 't', 'u', GeomFromText('POINT(119 237)')),
+('o', 'w', 's', GeomFromText('POINT(193 166)')),
+('f', 'm', 'q', GeomFromText('POINT(85 96)')),
+('x', 'l', 'x', GeomFromText('POINT(58 115)')),
+('x', 'q', 'u', GeomFromText('POINT(108 210)')),
+('b', 'h', 'i', GeomFromText('POINT(250 139)')),
+('y', 'd', 'x', GeomFromText('POINT(199 135)')),
+('w', 'h', 'p', GeomFromText('POINT(247 233)')),
+('p', 'z', 't', GeomFromText('POINT(148 249)')),
+('q', 'a', 'u', GeomFromText('POINT(174 78)')),
+('v', 't', 'm', GeomFromText('POINT(70 228)')),
+('t', 'n', 'f', GeomFromText('POINT(123 2)')),
+('x', 't', 'b', GeomFromText('POINT(35 50)')),
+('r', 'j', 'f', GeomFromText('POINT(200 51)')),
+('s', 'q', 'o', GeomFromText('POINT(23 184)')),
+('u', 'v', 'z', GeomFromText('POINT(7 113)')),
+('v', 'u', 'l', GeomFromText('POINT(145 190)')),
+('o', 'k', 'i', GeomFromText('POINT(161 122)')),
+('l', 'y', 'e', GeomFromText('POINT(17 232)')),
+('t', 'b', 'e', GeomFromText('POINT(120 50)')),
+('e', 's', 'u', GeomFromText('POINT(254 1)')),
+('d', 'd', 'u', GeomFromText('POINT(167 140)')),
+('o', 'b', 'x', GeomFromText('POINT(186 237)')),
+('m', 's', 's', GeomFromText('POINT(172 149)')),
+('t', 'y', 'a', GeomFromText('POINT(149 85)')),
+('x', 't', 'r', GeomFromText('POINT(10 165)')),
+('g', 'c', 'e', GeomFromText('POINT(95 165)')),
+('e', 'e', 'z', GeomFromText('POINT(98 65)')),
+('f', 'v', 'i', GeomFromText('POINT(149 144)')),
+('o', 'p', 'm', GeomFromText('POINT(233 67)')),
+('t', 'u', 'b', GeomFromText('POINT(109 215)')),
+('o', 'o', 'b', GeomFromText('POINT(130 48)')),
+('e', 'm', 'h', GeomFromText('POINT(88 189)')),
+('e', 'v', 'y', GeomFromText('POINT(55 29)')),
+('e', 't', 'm', GeomFromText('POINT(129 55)')),
+('p', 'p', 'i', GeomFromText('POINT(126 222)')),
+('c', 'i', 'c', GeomFromText('POINT(19 158)')),
+('c', 'b', 's', GeomFromText('POINT(13 19)')),
+('u', 'y', 'a', GeomFromText('POINT(114 5)')),
+('a', 'o', 'f', GeomFromText('POINT(227 232)')),
+('t', 'c', 'z', GeomFromText('POINT(63 62)')),
+('d', 'o', 'k', GeomFromText('POINT(48 228)')),
+('x', 'c', 'e', GeomFromText('POINT(204 2)')),
+('e', 'e', 'g', GeomFromText('POINT(125 43)')),
+('o', 'r', 'f', GeomFromText('POINT(171 140)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(163 157)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(53 151)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(96 183)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(57 91)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 110)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('b', 'c', 'e', GeomFromText('POINT(41 137)')),
+('p', 'y', 'k', GeomFromText('POINT(50 22)')),
+('s', 'c', 'h', GeomFromText('POINT(208 173)')),
+('x', 'u', 'l', GeomFromText('POINT(199 175)')),
+('s', 'r', 'h', GeomFromText('POINT(85 192)')),
+('j', 'k', 'u', GeomFromText('POINT(18 25)')),
+('p', 'w', 'h', GeomFromText('POINT(152 197)')),
+('e', 'd', 'c', GeomFromText('POINT(229 3)')),
+('o', 'x', 'k', GeomFromText('POINT(187 155)')),
+('o', 'b', 'k', GeomFromText('POINT(208 150)')),
+('d', 'a', 'j', GeomFromText('POINT(70 87)')),
+('f', 'e', 'k', GeomFromText('POINT(156 96)')),
+('u', 'y', 'p', GeomFromText('POINT(239 193)')),
+('n', 'v', 'p', GeomFromText('POINT(223 98)')),
+('z', 'j', 'r', GeomFromText('POINT(87 89)')),
+('h', 'x', 'x', GeomFromText('POINT(92 0)')),
+('r', 'v', 'r', GeomFromText('POINT(159 139)')),
+('v', 'g', 'g', GeomFromText('POINT(16 229)')),
+('z', 'k', 'u', GeomFromText('POINT(99 52)')),
+('p', 'p', 'o', GeomFromText('POINT(105 125)')),
+('w', 'h', 'y', GeomFromText('POINT(105 154)')),
+('v', 'y', 'z', GeomFromText('POINT(134 238)')),
+('x', 'o', 'o', GeomFromText('POINT(178 88)')),
+('z', 'w', 'd', GeomFromText('POINT(123 60)')),
+('q', 'f', 'u', GeomFromText('POINT(64 90)')),
+('s', 'n', 't', GeomFromText('POINT(50 138)')),
+('v', 'p', 't', GeomFromText('POINT(114 91)')),
+('a', 'o', 'n', GeomFromText('POINT(78 43)')),
+('k', 'u', 'd', GeomFromText('POINT(185 161)')),
+('w', 'd', 'n', GeomFromText('POINT(25 92)')),
+('k', 'w', 'a', GeomFromText('POINT(59 238)')),
+('t', 'c', 'f', GeomFromText('POINT(65 87)')),
+('g', 's', 'p', GeomFromText('POINT(238 126)')),
+('d', 'n', 'y', GeomFromText('POINT(107 173)')),
+('l', 'a', 'w', GeomFromText('POINT(125 152)')),
+('m', 'd', 'j', GeomFromText('POINT(146 53)')),
+('q', 'm', 'c', GeomFromText('POINT(217 187)')),
+('i', 'r', 'r', GeomFromText('POINT(6 113)')),
+('e', 'j', 'b', GeomFromText('POINT(37 83)')),
+('w', 'w', 'h', GeomFromText('POINT(83 199)')),
+('k', 'b', 's', GeomFromText('POINT(170 64)')),
+('s', 'b', 'c', GeomFromText('POINT(163 130)')),
+('c', 'h', 'a', GeomFromText('POINT(141 3)')),
+('k', 'j', 'u', GeomFromText('POINT(143 76)')),
+('r', 'h', 'o', GeomFromText('POINT(243 92)')),
+('i', 'd', 'b', GeomFromText('POINT(205 13)')),
+('r', 'y', 'q', GeomFromText('POINT(138 8)')),
+('m', 'o', 'i', GeomFromText('POINT(36 45)')),
+('v', 'g', 'm', GeomFromText('POINT(0 40)')),
+('f', 'e', 'i', GeomFromText('POINT(76 6)')),
+('c', 'q', 'q', GeomFromText('POINT(115 248)')),
+('x', 'c', 'i', GeomFromText('POINT(29 74)')),
+('l', 's', 't', GeomFromText('POINT(83 18)')),
+('t', 't', 'a', GeomFromText('POINT(26 168)')),
+('u', 'n', 'x', GeomFromText('POINT(200 110)')),
+('j', 'b', 'd', GeomFromText('POINT(216 136)')),
+('s', 'p', 'w', GeomFromText('POINT(38 156)')),
+('f', 'b', 'v', GeomFromText('POINT(29 186)')),
+('v', 'e', 'r', GeomFromText('POINT(149 40)')),
+('v', 't', 'm', GeomFromText('POINT(184 24)')),
+('y', 'g', 'a', GeomFromText('POINT(219 105)')),
+('s', 'f', 'i', GeomFromText('POINT(114 130)')),
+('e', 'q', 'h', GeomFromText('POINT(203 135)')),
+('h', 'g', 'b', GeomFromText('POINT(9 208)')),
+('o', 'l', 'r', GeomFromText('POINT(245 79)')),
+('s', 's', 'v', GeomFromText('POINT(238 198)')),
+('w', 'w', 'z', GeomFromText('POINT(209 232)')),
+('v', 'd', 'n', GeomFromText('POINT(30 193)')),
+('q', 'w', 'k', GeomFromText('POINT(133 18)')),
+('o', 'h', 'o', GeomFromText('POINT(42 140)')),
+('f', 'f', 'h', GeomFromText('POINT(145 1)')),
+('u', 's', 'r', GeomFromText('POINT(70 62)')),
+('x', 'n', 'q', GeomFromText('POINT(33 86)')),
+('u', 'p', 'v', GeomFromText('POINT(232 220)')),
+('z', 'e', 'a', GeomFromText('POINT(130 69)')),
+('r', 'u', 'z', GeomFromText('POINT(243 241)')),
+('b', 'n', 't', GeomFromText('POINT(120 12)')),
+('u', 'f', 's', GeomFromText('POINT(190 212)')),
+('a', 'd', 'q', GeomFromText('POINT(235 191)')),
+('f', 'q', 'm', GeomFromText('POINT(176 2)')),
+('n', 'c', 's', GeomFromText('POINT(218 163)')),
+('e', 'm', 'h', GeomFromText('POINT(163 108)')),
+('c', 'f', 'l', GeomFromText('POINT(220 115)')),
+('c', 'v', 'q', GeomFromText('POINT(66 45)')),
+('w', 'v', 'x', GeomFromText('POINT(251 220)')),
+('f', 'w', 'z', GeomFromText('POINT(146 149)')),
+('h', 'n', 'h', GeomFromText('POINT(148 128)')),
+('y', 'k', 'v', GeomFromText('POINT(28 110)')),
+('c', 'x', 'q', GeomFromText('POINT(13 13)')),
+('e', 'd', 's', GeomFromText('POINT(91 190)')),
+('c', 'w', 'c', GeomFromText('POINT(10 231)')),
+('u', 'j', 'n', GeomFromText('POINT(250 21)')),
+('w', 'n', 'x', GeomFromText('POINT(141 69)')),
+('f', 'p', 'y', GeomFromText('POINT(228 246)')),
+('d', 'q', 'f', GeomFromText('POINT(194 22)')),
+('d', 'z', 'l', GeomFromText('POINT(233 181)')),
+('c', 'a', 'q', GeomFromText('POINT(183 96)')),
+('m', 'i', 'd', GeomFromText('POINT(117 226)')),
+('z', 'y', 'y', GeomFromText('POINT(62 81)')),
+('g', 'v', 'm', GeomFromText('POINT(66 158)'));
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1072017234, @@RAND_SEED2=484203885;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=358851897, @@RAND_SEED2=358495224;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=509031459, @@RAND_SEED2=675962925;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(61 203)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 194)') where c1 like 'f%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(228 18)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 18)') where c1 like 'l%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(176 94)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(44 47)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 191)') where c1 like 'b%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(179 218)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(239 40)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(248 41)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(167 82)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(13 104)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(139 84)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(145 108)') where c1 like 'p%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(147 57)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(217 144)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(160 224)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(38 28)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(104 114)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 19)') where c1 like 'c%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('f', 'x', 'p', GeomFromText('POINT(92 181)')),
+('s', 'i', 'c', GeomFromText('POINT(49 60)')),
+('c', 'c', 'i', GeomFromText('POINT(7 57)')),
+('n', 'g', 'k', GeomFromText('POINT(252 105)')),
+('g', 'b', 'm', GeomFromText('POINT(180 11)')),
+('u', 'l', 'r', GeomFromText('POINT(32 90)')),
+('c', 'x', 'e', GeomFromText('POINT(143 24)')),
+('x', 'u', 'a', GeomFromText('POINT(123 92)')),
+('s', 'b', 'h', GeomFromText('POINT(190 108)')),
+('c', 'x', 'b', GeomFromText('POINT(104 100)')),
+('i', 'd', 't', GeomFromText('POINT(214 104)')),
+('r', 'w', 'g', GeomFromText('POINT(29 67)')),
+('b', 'f', 'g', GeomFromText('POINT(149 46)')),
+('r', 'r', 'd', GeomFromText('POINT(242 196)')),
+('j', 'l', 'a', GeomFromText('POINT(90 196)')),
+('e', 't', 'b', GeomFromText('POINT(190 64)')),
+('l', 'x', 'w', GeomFromText('POINT(250 73)')),
+('q', 'y', 'r', GeomFromText('POINT(120 182)')),
+('s', 'j', 'a', GeomFromText('POINT(180 175)')),
+('n', 'i', 'y', GeomFromText('POINT(124 136)')),
+('s', 'x', 's', GeomFromText('POINT(176 209)')),
+('u', 'f', 's', GeomFromText('POINT(215 173)')),
+('m', 'j', 'x', GeomFromText('POINT(44 140)')),
+('v', 'g', 'x', GeomFromText('POINT(177 233)')),
+('u', 't', 'b', GeomFromText('POINT(136 197)')),
+('f', 'g', 'b', GeomFromText('POINT(10 8)')),
+('v', 'c', 'j', GeomFromText('POINT(13 81)')),
+('d', 's', 'q', GeomFromText('POINT(200 100)')),
+('a', 'p', 'j', GeomFromText('POINT(33 40)')),
+('i', 'c', 'g', GeomFromText('POINT(168 204)')),
+('k', 'h', 'i', GeomFromText('POINT(93 243)')),
+('s', 'b', 's', GeomFromText('POINT(157 13)')),
+('v', 'l', 'l', GeomFromText('POINT(103 6)')),
+('r', 'b', 'k', GeomFromText('POINT(244 137)')),
+('l', 'd', 'r', GeomFromText('POINT(162 254)')),
+('q', 'b', 'z', GeomFromText('POINT(136 246)')),
+('x', 'x', 'p', GeomFromText('POINT(120 37)')),
+('m', 'e', 'z', GeomFromText('POINT(203 167)')),
+('q', 'n', 'p', GeomFromText('POINT(94 119)')),
+('b', 'g', 'u', GeomFromText('POINT(93 248)')),
+('r', 'v', 'v', GeomFromText('POINT(53 88)')),
+('y', 'a', 'i', GeomFromText('POINT(98 219)')),
+('a', 's', 'g', GeomFromText('POINT(173 138)')),
+('c', 'a', 't', GeomFromText('POINT(235 135)')),
+('q', 'm', 'd', GeomFromText('POINT(224 208)')),
+('e', 'p', 'k', GeomFromText('POINT(161 238)')),
+('n', 'g', 'q', GeomFromText('POINT(35 204)')),
+('t', 't', 'x', GeomFromText('POINT(230 178)')),
+('w', 'f', 'a', GeomFromText('POINT(150 221)')),
+('z', 'm', 'z', GeomFromText('POINT(119 42)')),
+('l', 'j', 's', GeomFromText('POINT(97 96)')),
+('f', 'z', 'x', GeomFromText('POINT(208 65)')),
+('i', 'v', 'c', GeomFromText('POINT(145 79)')),
+('l', 'f', 'k', GeomFromText('POINT(83 234)')),
+('u', 'a', 's', GeomFromText('POINT(250 49)')),
+('o', 'k', 'p', GeomFromText('POINT(46 50)')),
+('d', 'e', 'z', GeomFromText('POINT(30 198)')),
+('r', 'r', 'l', GeomFromText('POINT(78 189)')),
+('y', 'l', 'f', GeomFromText('POINT(188 132)')),
+('d', 'q', 'm', GeomFromText('POINT(247 107)')),
+('p', 'j', 'n', GeomFromText('POINT(148 227)')),
+('b', 'o', 'i', GeomFromText('POINT(172 25)')),
+('e', 'v', 'd', GeomFromText('POINT(94 248)')),
+('q', 'd', 'f', GeomFromText('POINT(15 29)')),
+('w', 'b', 'b', GeomFromText('POINT(74 111)')),
+('g', 'q', 'f', GeomFromText('POINT(107 215)')),
+('o', 'h', 'r', GeomFromText('POINT(25 168)')),
+('u', 't', 'w', GeomFromText('POINT(251 188)')),
+('h', 's', 'w', GeomFromText('POINT(254 247)')),
+('f', 'f', 'b', GeomFromText('POINT(166 103)'));
+SET @@RAND_SEED1=866613816, @@RAND_SEED2=92289615;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('l', 'c', 'l', GeomFromText('POINT(202 98)')),
+('k', 'c', 'b', GeomFromText('POINT(46 206)')),
+('r', 'y', 'm', GeomFromText('POINT(74 140)')),
+('y', 'z', 'd', GeomFromText('POINT(200 160)')),
+('s', 'y', 's', GeomFromText('POINT(156 205)')),
+('u', 'v', 'p', GeomFromText('POINT(86 82)')),
+('j', 's', 's', GeomFromText('POINT(91 233)')),
+('x', 'j', 'f', GeomFromText('POINT(3 14)')),
+('l', 'z', 'v', GeomFromText('POINT(123 156)')),
+('h', 'i', 'o', GeomFromText('POINT(145 229)')),
+('o', 'r', 'd', GeomFromText('POINT(15 22)')),
+('f', 'x', 't', GeomFromText('POINT(21 60)')),
+('t', 'g', 'h', GeomFromText('POINT(50 153)')),
+('g', 'u', 'b', GeomFromText('POINT(82 85)')),
+('v', 'a', 'p', GeomFromText('POINT(231 178)')),
+('n', 'v', 'o', GeomFromText('POINT(183 25)')),
+('j', 'n', 'm', GeomFromText('POINT(50 144)')),
+('e', 'f', 'i', GeomFromText('POINT(46 16)')),
+('d', 'w', 'a', GeomFromText('POINT(66 6)')),
+('f', 'x', 'a', GeomFromText('POINT(107 197)')),
+('m', 'o', 'a', GeomFromText('POINT(142 80)')),
+('q', 'l', 'g', GeomFromText('POINT(251 23)')),
+('c', 's', 's', GeomFromText('POINT(158 43)')),
+('y', 'd', 'o', GeomFromText('POINT(196 228)')),
+('d', 'p', 'l', GeomFromText('POINT(107 5)')),
+('h', 'a', 'b', GeomFromText('POINT(183 166)')),
+('m', 'w', 'p', GeomFromText('POINT(19 59)')),
+('b', 'y', 'o', GeomFromText('POINT(178 30)')),
+('x', 'w', 'i', GeomFromText('POINT(168 94)')),
+('t', 'k', 'z', GeomFromText('POINT(171 5)')),
+('r', 'm', 'a', GeomFromText('POINT(222 19)')),
+('u', 'v', 'e', GeomFromText('POINT(224 80)')),
+('q', 'r', 'k', GeomFromText('POINT(212 218)')),
+('d', 'p', 'j', GeomFromText('POINT(169 7)')),
+('d', 'r', 'v', GeomFromText('POINT(193 23)')),
+('n', 'y', 'y', GeomFromText('POINT(130 178)')),
+('m', 'z', 'r', GeomFromText('POINT(81 200)')),
+('j', 'e', 'w', GeomFromText('POINT(145 239)')),
+('v', 'h', 'x', GeomFromText('POINT(24 105)')),
+('z', 'm', 'a', GeomFromText('POINT(175 129)')),
+('b', 'c', 'v', GeomFromText('POINT(213 10)')),
+('t', 't', 'u', GeomFromText('POINT(2 129)')),
+('r', 's', 'v', GeomFromText('POINT(209 192)')),
+('x', 'p', 'g', GeomFromText('POINT(43 63)')),
+('t', 'e', 'u', GeomFromText('POINT(139 210)')),
+('l', 'e', 't', GeomFromText('POINT(245 148)')),
+('a', 'i', 'k', GeomFromText('POINT(167 195)')),
+('m', 'o', 'h', GeomFromText('POINT(206 120)')),
+('g', 'z', 's', GeomFromText('POINT(169 240)')),
+('z', 'u', 's', GeomFromText('POINT(202 120)')),
+('i', 'b', 'a', GeomFromText('POINT(216 18)')),
+('w', 'y', 'g', GeomFromText('POINT(119 236)')),
+('h', 'y', 'p', GeomFromText('POINT(161 24)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(33 100)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(41 46)') where c1 like 'f%';
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+create table t1 (a geometry not null, spatial index(a)) row_format=dynamic;
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072)));
+insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0)));
+insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241)));
+insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231)));
+insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260)));
+insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125)));
+insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29)));
+insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86)));
+insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130)));
+insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34)));
+insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183)));
+insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178)));
+drop table t1;
+CREATE TABLE t1(foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) row_format=dynamic;
+INSERT INTO t1(foo) VALUES (NULL);
+ERROR 23000: Column 'foo' cannot be null
+INSERT INTO t1() VALUES ();
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+INSERT INTO t1(foo) VALUES ('');
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+DROP TABLE t1;
+CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)) row_format=dynamic;
+INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)'));
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b GEOMETRY NOT NULL, SPATIAL KEY b(b)) row_format=dynamic;
+INSERT INTO t1 VALUES (1, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+INSERT INTO t1 VALUES (2, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+SELECT COUNT(*) FROM t1 WHERE
+MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+COUNT(*)
+2
+SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE
+MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+COUNT(*)
+2
+DROP TABLE t1;
+End of 5.0 tests.
diff --git a/mysql-test/suite/maria/r/maria-gis-rtree-trans.result b/mysql-test/suite/maria/r/maria-gis-rtree-trans.result
new file mode 100644
index 00000000000..9e43daa9623
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-gis-rtree-trans.result
@@ -0,0 +1,1491 @@
+set storage_engine=maria;
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL,
+SPATIAL KEY(g)
+) transactional=1 row_format=page;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `fid` int(11) NOT NULL AUTO_INCREMENT,
+ `g` geometry NOT NULL,
+ PRIMARY KEY (`fid`),
+ SPATIAL KEY `g` (`g`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 ROW_FORMAT=PAGE TRANSACTIONAL=1
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(148 148, 152 152)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(147 147, 153 153)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(146 146, 154 154)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(145 145, 155 155)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(144 144, 156 156)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(143 143, 157 157)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(142 142, 158 158)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(141 141, 159 159)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(140 140, 160 160)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(139 139, 161 161)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(138 138, 162 162)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(137 137, 163 163)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(136 136, 164 164)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(135 135, 165 165)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(134 134, 166 166)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(133 133, 167 167)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(132 132, 168 168)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(131 131, 169 169)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(130 130, 170 170)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(129 129, 171 171)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(128 128, 172 172)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(127 127, 173 173)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(126 126, 174 174)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(125 125, 175 175)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(124 124, 176 176)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(123 123, 177 177)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(122 122, 178 178)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(121 121, 179 179)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(120 120, 180 180)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(119 119, 181 181)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(118 118, 182 182)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(117 117, 183 183)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(116 116, 184 184)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(115 115, 185 185)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(114 114, 186 186)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(113 113, 187 187)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(112 112, 188 188)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(111 111, 189 189)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(110 110, 190 190)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(109 109, 191 191)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(108 108, 192 192)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(107 107, 193 193)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(106 106, 194 194)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(105 105, 195 195)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(104 104, 196 196)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(103 103, 197 197)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(102 102, 198 198)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(101 101, 199 199)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(100 100, 200 200)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(99 99, 201 201)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(98 98, 202 202)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(97 97, 203 203)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(96 96, 204 204)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(95 95, 205 205)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(94 94, 206 206)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(93 93, 207 207)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(92 92, 208 208)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(91 91, 209 209)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(90 90, 210 210)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(89 89, 211 211)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(88 88, 212 212)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(87 87, 213 213)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(86 86, 214 214)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(85 85, 215 215)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(84 84, 216 216)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(83 83, 217 217)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(82 82, 218 218)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(81 81, 219 219)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(80 80, 220 220)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(79 79, 221 221)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(78 78, 222 222)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(77 77, 223 223)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(76 76, 224 224)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(75 75, 225 225)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(74 74, 226 226)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(73 73, 227 227)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(72 72, 228 228)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(71 71, 229 229)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(70 70, 230 230)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(69 69, 231 231)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(68 68, 232 232)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(67 67, 233 233)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(66 66, 234 234)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(65 65, 235 235)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(64 64, 236 236)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(63 63, 237 237)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(62 62, 238 238)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(61 61, 239 239)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(60 60, 240 240)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(59 59, 241 241)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(58 58, 242 242)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(57 57, 243 243)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(56 56, 244 244)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(55 55, 245 245)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(54 54, 246 246)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(53 53, 247 247)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(52 52, 248 248)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(51 51, 249 249)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(50 50, 250 250)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(49 49, 251 251)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(48 48, 252 252)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(47 47, 253 253)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(46 46, 254 254)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(45 45, 255 255)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(44 44, 256 256)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(43 43, 257 257)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(42 42, 258 258)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(41 41, 259 259)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(40 40, 260 260)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(39 39, 261 261)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(38 38, 262 262)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(37 37, 263 263)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(36 36, 264 264)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(35 35, 265 265)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(34 34, 266 266)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(33 33, 267 267)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(32 32, 268 268)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(31 31, 269 269)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(30 30, 270 270)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(29 29, 271 271)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(28 28, 272 272)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(27 27, 273 273)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(26 26, 274 274)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(25 25, 275 275)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(24 24, 276 276)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(23 23, 277 277)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(22 22, 278 278)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(21 21, 279 279)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(20 20, 280 280)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(19 19, 281 281)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(18 18, 282 282)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(17 17, 283 283)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(16 16, 284 284)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(15 15, 285 285)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(14 14, 286 286)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(13 13, 287 287)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(12 12, 288 288)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(11 11, 289 289)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(10 10, 290 290)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(9 9, 291 291)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(8 8, 292 292)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(7 7, 293 293)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(6 6, 294 294)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(5 5, 295 295)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(4 4, 296 296)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(3 3, 297 297)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(2 2, 298 298)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 1, 299 299)'));
+SELECT count(*) FROM t1;
+count(*)
+150
+EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range g g 34 NULL 11 Using where
+SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+fid AsText(g)
+1 LINESTRING(150 150,150 150)
+2 LINESTRING(149 149,151 151)
+3 LINESTRING(148 148,152 152)
+4 LINESTRING(147 147,153 153)
+5 LINESTRING(146 146,154 154)
+6 LINESTRING(145 145,155 155)
+7 LINESTRING(144 144,156 156)
+8 LINESTRING(143 143,157 157)
+9 LINESTRING(142 142,158 158)
+10 LINESTRING(141 141,159 159)
+11 LINESTRING(140 140,160 160)
+DROP TABLE t1;
+CREATE TABLE t2 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL
+) transactional=1 row_format=page;
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))));
+ALTER TABLE t2 ADD SPATIAL KEY(g);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `fid` int(11) NOT NULL AUTO_INCREMENT,
+ `g` geometry NOT NULL,
+ PRIMARY KEY (`fid`),
+ SPATIAL KEY `g` (`g`)
+) ENGINE=MARIA AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 ROW_FORMAT=PAGE TRANSACTIONAL=1
+SELECT count(*) FROM t2;
+count(*)
+100
+EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range g g 34 NULL 4 Using where
+SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+fid AsText(g)
+45 LINESTRING(51 51,60 60)
+46 LINESTRING(51 41,60 50)
+55 LINESTRING(41 51,50 60)
+56 LINESTRING(41 41,50 50)
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+99
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+98
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+97
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+96
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+95
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+94
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+93
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+92
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+91
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+90
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+89
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+88
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+87
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+86
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+85
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+84
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+83
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+82
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+81
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+80
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+79
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+78
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+77
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+76
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+75
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+74
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+73
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+72
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+71
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+70
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+69
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+68
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+67
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+66
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+65
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+64
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+63
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+62
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+61
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+60
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+59
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+58
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+57
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+56
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+55
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+54
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+53
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+52
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+51
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+50
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+49
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+48
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+47
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+46
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+45
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+44
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+43
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+42
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+41
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+40
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+39
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+38
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+37
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+36
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+35
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+34
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+33
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+32
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+31
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+30
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+29
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+28
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+27
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+26
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+25
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+24
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+23
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+22
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+21
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+20
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+19
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+18
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+17
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+16
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+15
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+14
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+13
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+12
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+11
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+10
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+9
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+8
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+7
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+6
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+5
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+4
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+3
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+2
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+1
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+0
+DROP TABLE t2;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a)) transactional=1 row_format=page;
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+drop table t1;
+CREATE TABLE t1 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL,
+SPATIAL KEY(g)
+) transactional=1 row_format=page;
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
+drop table t1;
+CREATE TABLE t1 (
+line LINESTRING NOT NULL,
+kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+name VARCHAR(32),
+SPATIAL KEY (line)
+) transactional=1 row_format=page;
+ALTER TABLE t1 DISABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES
+("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+ALTER TABLE t1 ENABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES ("austria", "pp", GeomFromText('LINESTRING(14.9906 48.9887,14.9946 48.9904,14.9947 48.9916)'));
+drop table t1;
+CREATE TABLE t1 (st varchar(100));
+INSERT INTO t1 VALUES ("Fake string");
+CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)) transactional=1 row_format=page;
+INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+drop table t1, t2;
+CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) transactional=1 row_format=page DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'geometry' can't have a default value
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
+-66.8158332999, -18.7186111000 -66.8102777000, -18.7211111000 -66.9269443999,
+-18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-65.7402776999 -96.6686111000, -65.7372222000
+-96.5516666000, -65.8502777000 -96.5461111000, -65.8527777000 -96.6627777000,
+-65.7402776999 -96.6686111000))'));
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+CREATE TABLE t1 (
+c1 geometry NOT NULL default '',
+SPATIAL KEY i1 (c1)
+) transactional=1 row_format=page DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'c1' can't have a default value
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 geometry NOT NULL default '',
+SPATIAL KEY i1 (c1)
+) transactional=1 row_format=page DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'c1' can't have a default value
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-65.7402776999 -96.6686111000,
+ -65.7372222000 -96.5516666000,
+ -65.8502777000 -96.5461111000,
+ -65.8527777000 -96.6627777000,
+ -65.7402776999 -96.6686111000))'));
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=1 row_format=page;
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
+SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
+1
+1
+1
+1
+DROP TABLE t1;
+CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
+c2 varchar(15) collate utf8_bin default NULL,
+c1 varchar(15) collate utf8_bin default NULL,
+c3 varchar(10) collate utf8_bin default NULL,
+spatial_point point NOT NULL,
+PRIMARY KEY(id),
+SPATIAL KEY (spatial_point)
+)transactional=1 row_format=page DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('y', 's', 'j', GeomFromText('POINT(167 74)')),
+('r', 'n', 'd', GeomFromText('POINT(215 118)')),
+('g', 'n', 'e', GeomFromText('POINT(203 98)')),
+('h', 'd', 'd', GeomFromText('POINT(54 193)')),
+('r', 'x', 'y', GeomFromText('POINT(47 69)')),
+('t', 'q', 'r', GeomFromText('POINT(109 42)')),
+('a', 'z', 'd', GeomFromText('POINT(0 154)')),
+('x', 'v', 'o', GeomFromText('POINT(174 131)')),
+('b', 'r', 'a', GeomFromText('POINT(114 253)')),
+('x', 'z', 'i', GeomFromText('POINT(163 21)')),
+('w', 'p', 'i', GeomFromText('POINT(42 102)')),
+('g', 'j', 'j', GeomFromText('POINT(170 133)')),
+('m', 'g', 'n', GeomFromText('POINT(28 22)')),
+('b', 'z', 'h', GeomFromText('POINT(174 28)')),
+('q', 'k', 'f', GeomFromText('POINT(233 73)')),
+('w', 'w', 'a', GeomFromText('POINT(124 200)')),
+('t', 'j', 'w', GeomFromText('POINT(252 101)')),
+('d', 'r', 'd', GeomFromText('POINT(98 18)')),
+('w', 'o', 'y', GeomFromText('POINT(165 31)')),
+('y', 'h', 't', GeomFromText('POINT(14 220)')),
+('d', 'p', 'u', GeomFromText('POINT(223 196)')),
+('g', 'y', 'g', GeomFromText('POINT(207 96)')),
+('x', 'm', 'n', GeomFromText('POINT(214 3)')),
+('g', 'v', 'e', GeomFromText('POINT(140 205)')),
+('g', 'm', 'm', GeomFromText('POINT(10 236)')),
+('i', 'r', 'j', GeomFromText('POINT(137 228)')),
+('w', 's', 'p', GeomFromText('POINT(115 6)')),
+('o', 'n', 'k', GeomFromText('POINT(158 129)')),
+('j', 'h', 'l', GeomFromText('POINT(129 72)')),
+('f', 'x', 'l', GeomFromText('POINT(139 207)')),
+('u', 'd', 'n', GeomFromText('POINT(125 109)')),
+('b', 'a', 'z', GeomFromText('POINT(30 32)')),
+('m', 'h', 'o', GeomFromText('POINT(251 251)')),
+('f', 'r', 'd', GeomFromText('POINT(243 211)')),
+('b', 'd', 'r', GeomFromText('POINT(232 80)')),
+('g', 'k', 'v', GeomFromText('POINT(15 100)')),
+('i', 'f', 'c', GeomFromText('POINT(109 66)')),
+('r', 't', 'j', GeomFromText('POINT(178 6)')),
+('y', 'n', 'f', GeomFromText('POINT(233 211)')),
+('f', 'y', 'm', GeomFromText('POINT(99 16)')),
+('z', 'q', 'l', GeomFromText('POINT(39 49)')),
+('j', 'c', 'r', GeomFromText('POINT(75 187)')),
+('c', 'y', 'y', GeomFromText('POINT(246 253)')),
+('w', 'u', 'd', GeomFromText('POINT(56 190)')),
+('n', 'q', 'm', GeomFromText('POINT(73 149)')),
+('d', 'y', 'a', GeomFromText('POINT(134 6)')),
+('z', 's', 'w', GeomFromText('POINT(216 225)')),
+('d', 'u', 'k', GeomFromText('POINT(132 70)')),
+('f', 'v', 't', GeomFromText('POINT(187 141)')),
+('r', 'r', 'a', GeomFromText('POINT(152 39)')),
+('y', 'p', 'o', GeomFromText('POINT(45 27)')),
+('p', 'n', 'm', GeomFromText('POINT(228 148)')),
+('e', 'g', 'e', GeomFromText('POINT(88 81)')),
+('m', 'a', 'h', GeomFromText('POINT(35 29)')),
+('m', 'h', 'f', GeomFromText('POINT(30 71)')),
+('h', 'k', 'i', GeomFromText('POINT(244 78)')),
+('z', 'v', 'd', GeomFromText('POINT(241 38)')),
+('q', 'l', 'j', GeomFromText('POINT(13 71)')),
+('s', 'p', 'g', GeomFromText('POINT(108 38)')),
+('q', 's', 'j', GeomFromText('POINT(92 101)')),
+('l', 'h', 'g', GeomFromText('POINT(120 78)')),
+('w', 't', 'b', GeomFromText('POINT(193 109)')),
+('b', 's', 's', GeomFromText('POINT(223 211)')),
+('w', 'w', 'y', GeomFromText('POINT(122 42)')),
+('q', 'c', 'c', GeomFromText('POINT(104 102)')),
+('w', 'g', 'n', GeomFromText('POINT(213 120)')),
+('p', 'q', 'a', GeomFromText('POINT(247 148)')),
+('c', 'z', 'e', GeomFromText('POINT(18 106)')),
+('z', 'u', 'n', GeomFromText('POINT(70 133)')),
+('j', 'n', 'x', GeomFromText('POINT(232 13)')),
+('e', 'h', 'f', GeomFromText('POINT(22 135)')),
+('w', 'l', 'f', GeomFromText('POINT(9 180)')),
+('a', 'v', 'q', GeomFromText('POINT(163 228)')),
+('i', 'z', 'o', GeomFromText('POINT(180 100)')),
+('e', 'c', 'l', GeomFromText('POINT(182 231)')),
+('c', 'k', 'o', GeomFromText('POINT(19 60)')),
+('q', 'f', 'p', GeomFromText('POINT(79 95)')),
+('m', 'd', 'r', GeomFromText('POINT(3 127)')),
+('m', 'e', 't', GeomFromText('POINT(136 154)')),
+('w', 'w', 'w', GeomFromText('POINT(102 15)')),
+('l', 'n', 'q', GeomFromText('POINT(71 196)')),
+('p', 'k', 'c', GeomFromText('POINT(47 139)')),
+('j', 'o', 'r', GeomFromText('POINT(177 128)')),
+('j', 'q', 'a', GeomFromText('POINT(170 6)')),
+('b', 'a', 'o', GeomFromText('POINT(63 211)')),
+('g', 's', 'o', GeomFromText('POINT(144 251)')),
+('w', 'u', 'w', GeomFromText('POINT(221 214)')),
+('g', 'a', 'm', GeomFromText('POINT(14 102)')),
+('u', 'q', 'z', GeomFromText('POINT(86 200)')),
+('k', 'a', 'm', GeomFromText('POINT(144 222)')),
+('j', 'u', 'r', GeomFromText('POINT(216 142)')),
+('q', 'k', 'v', GeomFromText('POINT(121 236)')),
+('p', 'o', 'r', GeomFromText('POINT(108 102)')),
+('b', 'd', 'x', GeomFromText('POINT(127 198)')),
+('k', 's', 'a', GeomFromText('POINT(2 150)')),
+('f', 'm', 'f', GeomFromText('POINT(160 191)')),
+('q', 'y', 'x', GeomFromText('POINT(98 111)')),
+('o', 'f', 'm', GeomFromText('POINT(232 218)')),
+('c', 'w', 'j', GeomFromText('POINT(156 165)')),
+('s', 'q', 'v', GeomFromText('POINT(98 161)'));
+SET @@RAND_SEED1=692635050, @@RAND_SEED2=297339954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=159925977, @@RAND_SEED2=942570618;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=328169745, @@RAND_SEED2=410451954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(19 81)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(20 177)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(221 193)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(195 205)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(15 213)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(214 63)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(243 171)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(198 82)') where c1 like 'y%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('f', 'y', 'p', GeomFromText('POINT(109 235)')),
+('b', 'e', 'v', GeomFromText('POINT(20 48)')),
+('i', 'u', 'f', GeomFromText('POINT(15 55)')),
+('o', 'r', 'z', GeomFromText('POINT(105 64)')),
+('a', 'p', 'a', GeomFromText('POINT(142 236)')),
+('g', 'i', 'k', GeomFromText('POINT(10 49)')),
+('x', 'z', 'x', GeomFromText('POINT(192 200)')),
+('c', 'v', 'r', GeomFromText('POINT(94 168)')),
+('y', 'z', 'e', GeomFromText('POINT(141 51)')),
+('h', 'm', 'd', GeomFromText('POINT(35 251)')),
+('v', 'm', 'q', GeomFromText('POINT(44 90)')),
+('j', 'l', 'z', GeomFromText('POINT(67 237)')),
+('i', 'v', 'a', GeomFromText('POINT(75 14)')),
+('b', 'q', 't', GeomFromText('POINT(153 33)')),
+('e', 'm', 'a', GeomFromText('POINT(247 49)')),
+('l', 'y', 'g', GeomFromText('POINT(56 203)')),
+('v', 'o', 'r', GeomFromText('POINT(90 54)')),
+('r', 'n', 'd', GeomFromText('POINT(135 83)')),
+('j', 't', 'u', GeomFromText('POINT(174 239)')),
+('u', 'n', 'g', GeomFromText('POINT(104 191)')),
+('p', 'q', 'y', GeomFromText('POINT(63 171)')),
+('o', 'q', 'p', GeomFromText('POINT(192 103)')),
+('f', 'x', 'e', GeomFromText('POINT(244 30)')),
+('n', 'x', 'c', GeomFromText('POINT(92 103)')),
+('r', 'q', 'z', GeomFromText('POINT(166 20)')),
+('s', 'a', 'j', GeomFromText('POINT(137 205)')),
+('z', 't', 't', GeomFromText('POINT(99 134)')),
+('o', 'm', 'j', GeomFromText('POINT(217 3)')),
+('n', 'h', 'j', GeomFromText('POINT(211 17)')),
+('v', 'v', 'a', GeomFromText('POINT(41 137)')),
+('q', 'o', 'j', GeomFromText('POINT(5 92)')),
+('z', 'y', 'e', GeomFromText('POINT(175 212)')),
+('j', 'z', 'h', GeomFromText('POINT(224 194)')),
+('a', 'g', 'm', GeomFromText('POINT(31 119)')),
+('p', 'c', 'f', GeomFromText('POINT(17 221)')),
+('t', 'h', 'k', GeomFromText('POINT(26 203)')),
+('u', 'w', 'p', GeomFromText('POINT(47 185)')),
+('z', 'a', 'c', GeomFromText('POINT(61 133)')),
+('u', 'k', 'a', GeomFromText('POINT(210 115)')),
+('k', 'f', 'h', GeomFromText('POINT(125 113)')),
+('t', 'v', 'y', GeomFromText('POINT(12 239)')),
+('u', 'v', 'd', GeomFromText('POINT(90 24)')),
+('m', 'y', 'w', GeomFromText('POINT(25 243)')),
+('d', 'n', 'g', GeomFromText('POINT(122 92)')),
+('z', 'm', 'f', GeomFromText('POINT(235 110)')),
+('q', 'd', 'f', GeomFromText('POINT(233 217)')),
+('a', 'v', 'u', GeomFromText('POINT(69 59)')),
+('x', 'k', 'p', GeomFromText('POINT(240 14)')),
+('i', 'v', 'r', GeomFromText('POINT(154 42)')),
+('w', 'h', 'l', GeomFromText('POINT(178 156)')),
+('d', 'h', 'n', GeomFromText('POINT(65 157)')),
+('c', 'k', 'z', GeomFromText('POINT(62 33)')),
+('e', 'l', 'w', GeomFromText('POINT(162 1)')),
+('r', 'f', 'i', GeomFromText('POINT(127 71)')),
+('q', 'm', 'c', GeomFromText('POINT(63 118)')),
+('c', 'h', 'u', GeomFromText('POINT(205 203)')),
+('d', 't', 'p', GeomFromText('POINT(234 87)')),
+('s', 'g', 'h', GeomFromText('POINT(149 34)')),
+('o', 'b', 'q', GeomFromText('POINT(159 179)')),
+('k', 'u', 'f', GeomFromText('POINT(202 254)')),
+('u', 'f', 'g', GeomFromText('POINT(70 15)')),
+('x', 's', 'b', GeomFromText('POINT(25 181)')),
+('s', 'c', 'g', GeomFromText('POINT(252 17)')),
+('a', 'c', 'f', GeomFromText('POINT(89 67)')),
+('r', 'e', 'q', GeomFromText('POINT(55 54)')),
+('f', 'i', 'k', GeomFromText('POINT(178 230)')),
+('p', 'e', 'l', GeomFromText('POINT(198 28)')),
+('w', 'o', 'd', GeomFromText('POINT(204 189)')),
+('c', 'a', 'g', GeomFromText('POINT(230 178)')),
+('r', 'o', 'e', GeomFromText('POINT(61 116)')),
+('w', 'a', 'a', GeomFromText('POINT(178 237)')),
+('v', 'd', 'e', GeomFromText('POINT(70 85)')),
+('k', 'c', 'e', GeomFromText('POINT(147 118)')),
+('d', 'q', 't', GeomFromText('POINT(218 77)')),
+('k', 'g', 'f', GeomFromText('POINT(192 113)')),
+('w', 'n', 'e', GeomFromText('POINT(92 124)')),
+('r', 'm', 'q', GeomFromText('POINT(130 65)')),
+('o', 'r', 'r', GeomFromText('POINT(174 233)')),
+('k', 'n', 't', GeomFromText('POINT(175 147)')),
+('q', 'm', 'r', GeomFromText('POINT(18 208)')),
+('l', 'd', 'i', GeomFromText('POINT(13 104)')),
+('w', 'o', 'y', GeomFromText('POINT(207 39)')),
+('p', 'u', 'o', GeomFromText('POINT(114 31)')),
+('y', 'a', 'p', GeomFromText('POINT(106 59)')),
+('a', 'x', 'z', GeomFromText('POINT(17 57)')),
+('v', 'h', 'x', GeomFromText('POINT(170 13)')),
+('t', 's', 'u', GeomFromText('POINT(84 18)')),
+('z', 'z', 'f', GeomFromText('POINT(250 197)')),
+('l', 'z', 't', GeomFromText('POINT(59 80)')),
+('j', 'g', 's', GeomFromText('POINT(54 26)')),
+('g', 'v', 'm', GeomFromText('POINT(89 98)')),
+('q', 'v', 'b', GeomFromText('POINT(39 240)')),
+('x', 'k', 'v', GeomFromText('POINT(246 207)')),
+('k', 'u', 'i', GeomFromText('POINT(105 111)')),
+('w', 'z', 's', GeomFromText('POINT(235 8)')),
+('d', 'd', 'd', GeomFromText('POINT(105 4)')),
+('c', 'z', 'q', GeomFromText('POINT(13 140)')),
+('m', 'k', 'i', GeomFromText('POINT(208 120)')),
+('g', 'a', 'g', GeomFromText('POINT(9 182)')),
+('z', 'j', 'r', GeomFromText('POINT(149 153)')),
+('h', 'f', 'g', GeomFromText('POINT(81 236)')),
+('m', 'e', 'q', GeomFromText('POINT(209 215)')),
+('c', 'h', 'y', GeomFromText('POINT(235 70)')),
+('i', 'e', 'g', GeomFromText('POINT(138 26)')),
+('m', 't', 'u', GeomFromText('POINT(119 237)')),
+('o', 'w', 's', GeomFromText('POINT(193 166)')),
+('f', 'm', 'q', GeomFromText('POINT(85 96)')),
+('x', 'l', 'x', GeomFromText('POINT(58 115)')),
+('x', 'q', 'u', GeomFromText('POINT(108 210)')),
+('b', 'h', 'i', GeomFromText('POINT(250 139)')),
+('y', 'd', 'x', GeomFromText('POINT(199 135)')),
+('w', 'h', 'p', GeomFromText('POINT(247 233)')),
+('p', 'z', 't', GeomFromText('POINT(148 249)')),
+('q', 'a', 'u', GeomFromText('POINT(174 78)')),
+('v', 't', 'm', GeomFromText('POINT(70 228)')),
+('t', 'n', 'f', GeomFromText('POINT(123 2)')),
+('x', 't', 'b', GeomFromText('POINT(35 50)')),
+('r', 'j', 'f', GeomFromText('POINT(200 51)')),
+('s', 'q', 'o', GeomFromText('POINT(23 184)')),
+('u', 'v', 'z', GeomFromText('POINT(7 113)')),
+('v', 'u', 'l', GeomFromText('POINT(145 190)')),
+('o', 'k', 'i', GeomFromText('POINT(161 122)')),
+('l', 'y', 'e', GeomFromText('POINT(17 232)')),
+('t', 'b', 'e', GeomFromText('POINT(120 50)')),
+('e', 's', 'u', GeomFromText('POINT(254 1)')),
+('d', 'd', 'u', GeomFromText('POINT(167 140)')),
+('o', 'b', 'x', GeomFromText('POINT(186 237)')),
+('m', 's', 's', GeomFromText('POINT(172 149)')),
+('t', 'y', 'a', GeomFromText('POINT(149 85)')),
+('x', 't', 'r', GeomFromText('POINT(10 165)')),
+('g', 'c', 'e', GeomFromText('POINT(95 165)')),
+('e', 'e', 'z', GeomFromText('POINT(98 65)')),
+('f', 'v', 'i', GeomFromText('POINT(149 144)')),
+('o', 'p', 'm', GeomFromText('POINT(233 67)')),
+('t', 'u', 'b', GeomFromText('POINT(109 215)')),
+('o', 'o', 'b', GeomFromText('POINT(130 48)')),
+('e', 'm', 'h', GeomFromText('POINT(88 189)')),
+('e', 'v', 'y', GeomFromText('POINT(55 29)')),
+('e', 't', 'm', GeomFromText('POINT(129 55)')),
+('p', 'p', 'i', GeomFromText('POINT(126 222)')),
+('c', 'i', 'c', GeomFromText('POINT(19 158)')),
+('c', 'b', 's', GeomFromText('POINT(13 19)')),
+('u', 'y', 'a', GeomFromText('POINT(114 5)')),
+('a', 'o', 'f', GeomFromText('POINT(227 232)')),
+('t', 'c', 'z', GeomFromText('POINT(63 62)')),
+('d', 'o', 'k', GeomFromText('POINT(48 228)')),
+('x', 'c', 'e', GeomFromText('POINT(204 2)')),
+('e', 'e', 'g', GeomFromText('POINT(125 43)')),
+('o', 'r', 'f', GeomFromText('POINT(171 140)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(163 157)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(53 151)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(96 183)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(57 91)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 110)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('b', 'c', 'e', GeomFromText('POINT(41 137)')),
+('p', 'y', 'k', GeomFromText('POINT(50 22)')),
+('s', 'c', 'h', GeomFromText('POINT(208 173)')),
+('x', 'u', 'l', GeomFromText('POINT(199 175)')),
+('s', 'r', 'h', GeomFromText('POINT(85 192)')),
+('j', 'k', 'u', GeomFromText('POINT(18 25)')),
+('p', 'w', 'h', GeomFromText('POINT(152 197)')),
+('e', 'd', 'c', GeomFromText('POINT(229 3)')),
+('o', 'x', 'k', GeomFromText('POINT(187 155)')),
+('o', 'b', 'k', GeomFromText('POINT(208 150)')),
+('d', 'a', 'j', GeomFromText('POINT(70 87)')),
+('f', 'e', 'k', GeomFromText('POINT(156 96)')),
+('u', 'y', 'p', GeomFromText('POINT(239 193)')),
+('n', 'v', 'p', GeomFromText('POINT(223 98)')),
+('z', 'j', 'r', GeomFromText('POINT(87 89)')),
+('h', 'x', 'x', GeomFromText('POINT(92 0)')),
+('r', 'v', 'r', GeomFromText('POINT(159 139)')),
+('v', 'g', 'g', GeomFromText('POINT(16 229)')),
+('z', 'k', 'u', GeomFromText('POINT(99 52)')),
+('p', 'p', 'o', GeomFromText('POINT(105 125)')),
+('w', 'h', 'y', GeomFromText('POINT(105 154)')),
+('v', 'y', 'z', GeomFromText('POINT(134 238)')),
+('x', 'o', 'o', GeomFromText('POINT(178 88)')),
+('z', 'w', 'd', GeomFromText('POINT(123 60)')),
+('q', 'f', 'u', GeomFromText('POINT(64 90)')),
+('s', 'n', 't', GeomFromText('POINT(50 138)')),
+('v', 'p', 't', GeomFromText('POINT(114 91)')),
+('a', 'o', 'n', GeomFromText('POINT(78 43)')),
+('k', 'u', 'd', GeomFromText('POINT(185 161)')),
+('w', 'd', 'n', GeomFromText('POINT(25 92)')),
+('k', 'w', 'a', GeomFromText('POINT(59 238)')),
+('t', 'c', 'f', GeomFromText('POINT(65 87)')),
+('g', 's', 'p', GeomFromText('POINT(238 126)')),
+('d', 'n', 'y', GeomFromText('POINT(107 173)')),
+('l', 'a', 'w', GeomFromText('POINT(125 152)')),
+('m', 'd', 'j', GeomFromText('POINT(146 53)')),
+('q', 'm', 'c', GeomFromText('POINT(217 187)')),
+('i', 'r', 'r', GeomFromText('POINT(6 113)')),
+('e', 'j', 'b', GeomFromText('POINT(37 83)')),
+('w', 'w', 'h', GeomFromText('POINT(83 199)')),
+('k', 'b', 's', GeomFromText('POINT(170 64)')),
+('s', 'b', 'c', GeomFromText('POINT(163 130)')),
+('c', 'h', 'a', GeomFromText('POINT(141 3)')),
+('k', 'j', 'u', GeomFromText('POINT(143 76)')),
+('r', 'h', 'o', GeomFromText('POINT(243 92)')),
+('i', 'd', 'b', GeomFromText('POINT(205 13)')),
+('r', 'y', 'q', GeomFromText('POINT(138 8)')),
+('m', 'o', 'i', GeomFromText('POINT(36 45)')),
+('v', 'g', 'm', GeomFromText('POINT(0 40)')),
+('f', 'e', 'i', GeomFromText('POINT(76 6)')),
+('c', 'q', 'q', GeomFromText('POINT(115 248)')),
+('x', 'c', 'i', GeomFromText('POINT(29 74)')),
+('l', 's', 't', GeomFromText('POINT(83 18)')),
+('t', 't', 'a', GeomFromText('POINT(26 168)')),
+('u', 'n', 'x', GeomFromText('POINT(200 110)')),
+('j', 'b', 'd', GeomFromText('POINT(216 136)')),
+('s', 'p', 'w', GeomFromText('POINT(38 156)')),
+('f', 'b', 'v', GeomFromText('POINT(29 186)')),
+('v', 'e', 'r', GeomFromText('POINT(149 40)')),
+('v', 't', 'm', GeomFromText('POINT(184 24)')),
+('y', 'g', 'a', GeomFromText('POINT(219 105)')),
+('s', 'f', 'i', GeomFromText('POINT(114 130)')),
+('e', 'q', 'h', GeomFromText('POINT(203 135)')),
+('h', 'g', 'b', GeomFromText('POINT(9 208)')),
+('o', 'l', 'r', GeomFromText('POINT(245 79)')),
+('s', 's', 'v', GeomFromText('POINT(238 198)')),
+('w', 'w', 'z', GeomFromText('POINT(209 232)')),
+('v', 'd', 'n', GeomFromText('POINT(30 193)')),
+('q', 'w', 'k', GeomFromText('POINT(133 18)')),
+('o', 'h', 'o', GeomFromText('POINT(42 140)')),
+('f', 'f', 'h', GeomFromText('POINT(145 1)')),
+('u', 's', 'r', GeomFromText('POINT(70 62)')),
+('x', 'n', 'q', GeomFromText('POINT(33 86)')),
+('u', 'p', 'v', GeomFromText('POINT(232 220)')),
+('z', 'e', 'a', GeomFromText('POINT(130 69)')),
+('r', 'u', 'z', GeomFromText('POINT(243 241)')),
+('b', 'n', 't', GeomFromText('POINT(120 12)')),
+('u', 'f', 's', GeomFromText('POINT(190 212)')),
+('a', 'd', 'q', GeomFromText('POINT(235 191)')),
+('f', 'q', 'm', GeomFromText('POINT(176 2)')),
+('n', 'c', 's', GeomFromText('POINT(218 163)')),
+('e', 'm', 'h', GeomFromText('POINT(163 108)')),
+('c', 'f', 'l', GeomFromText('POINT(220 115)')),
+('c', 'v', 'q', GeomFromText('POINT(66 45)')),
+('w', 'v', 'x', GeomFromText('POINT(251 220)')),
+('f', 'w', 'z', GeomFromText('POINT(146 149)')),
+('h', 'n', 'h', GeomFromText('POINT(148 128)')),
+('y', 'k', 'v', GeomFromText('POINT(28 110)')),
+('c', 'x', 'q', GeomFromText('POINT(13 13)')),
+('e', 'd', 's', GeomFromText('POINT(91 190)')),
+('c', 'w', 'c', GeomFromText('POINT(10 231)')),
+('u', 'j', 'n', GeomFromText('POINT(250 21)')),
+('w', 'n', 'x', GeomFromText('POINT(141 69)')),
+('f', 'p', 'y', GeomFromText('POINT(228 246)')),
+('d', 'q', 'f', GeomFromText('POINT(194 22)')),
+('d', 'z', 'l', GeomFromText('POINT(233 181)')),
+('c', 'a', 'q', GeomFromText('POINT(183 96)')),
+('m', 'i', 'd', GeomFromText('POINT(117 226)')),
+('z', 'y', 'y', GeomFromText('POINT(62 81)')),
+('g', 'v', 'm', GeomFromText('POINT(66 158)'));
+SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1072017234, @@RAND_SEED2=484203885;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=358851897, @@RAND_SEED2=358495224;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=509031459, @@RAND_SEED2=675962925;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(61 203)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 194)') where c1 like 'f%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(228 18)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 18)') where c1 like 'l%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(176 94)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(44 47)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 191)') where c1 like 'b%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(179 218)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(239 40)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(248 41)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(167 82)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(13 104)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(139 84)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(145 108)') where c1 like 'p%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(147 57)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(217 144)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(160 224)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(38 28)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(104 114)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 19)') where c1 like 'c%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('f', 'x', 'p', GeomFromText('POINT(92 181)')),
+('s', 'i', 'c', GeomFromText('POINT(49 60)')),
+('c', 'c', 'i', GeomFromText('POINT(7 57)')),
+('n', 'g', 'k', GeomFromText('POINT(252 105)')),
+('g', 'b', 'm', GeomFromText('POINT(180 11)')),
+('u', 'l', 'r', GeomFromText('POINT(32 90)')),
+('c', 'x', 'e', GeomFromText('POINT(143 24)')),
+('x', 'u', 'a', GeomFromText('POINT(123 92)')),
+('s', 'b', 'h', GeomFromText('POINT(190 108)')),
+('c', 'x', 'b', GeomFromText('POINT(104 100)')),
+('i', 'd', 't', GeomFromText('POINT(214 104)')),
+('r', 'w', 'g', GeomFromText('POINT(29 67)')),
+('b', 'f', 'g', GeomFromText('POINT(149 46)')),
+('r', 'r', 'd', GeomFromText('POINT(242 196)')),
+('j', 'l', 'a', GeomFromText('POINT(90 196)')),
+('e', 't', 'b', GeomFromText('POINT(190 64)')),
+('l', 'x', 'w', GeomFromText('POINT(250 73)')),
+('q', 'y', 'r', GeomFromText('POINT(120 182)')),
+('s', 'j', 'a', GeomFromText('POINT(180 175)')),
+('n', 'i', 'y', GeomFromText('POINT(124 136)')),
+('s', 'x', 's', GeomFromText('POINT(176 209)')),
+('u', 'f', 's', GeomFromText('POINT(215 173)')),
+('m', 'j', 'x', GeomFromText('POINT(44 140)')),
+('v', 'g', 'x', GeomFromText('POINT(177 233)')),
+('u', 't', 'b', GeomFromText('POINT(136 197)')),
+('f', 'g', 'b', GeomFromText('POINT(10 8)')),
+('v', 'c', 'j', GeomFromText('POINT(13 81)')),
+('d', 's', 'q', GeomFromText('POINT(200 100)')),
+('a', 'p', 'j', GeomFromText('POINT(33 40)')),
+('i', 'c', 'g', GeomFromText('POINT(168 204)')),
+('k', 'h', 'i', GeomFromText('POINT(93 243)')),
+('s', 'b', 's', GeomFromText('POINT(157 13)')),
+('v', 'l', 'l', GeomFromText('POINT(103 6)')),
+('r', 'b', 'k', GeomFromText('POINT(244 137)')),
+('l', 'd', 'r', GeomFromText('POINT(162 254)')),
+('q', 'b', 'z', GeomFromText('POINT(136 246)')),
+('x', 'x', 'p', GeomFromText('POINT(120 37)')),
+('m', 'e', 'z', GeomFromText('POINT(203 167)')),
+('q', 'n', 'p', GeomFromText('POINT(94 119)')),
+('b', 'g', 'u', GeomFromText('POINT(93 248)')),
+('r', 'v', 'v', GeomFromText('POINT(53 88)')),
+('y', 'a', 'i', GeomFromText('POINT(98 219)')),
+('a', 's', 'g', GeomFromText('POINT(173 138)')),
+('c', 'a', 't', GeomFromText('POINT(235 135)')),
+('q', 'm', 'd', GeomFromText('POINT(224 208)')),
+('e', 'p', 'k', GeomFromText('POINT(161 238)')),
+('n', 'g', 'q', GeomFromText('POINT(35 204)')),
+('t', 't', 'x', GeomFromText('POINT(230 178)')),
+('w', 'f', 'a', GeomFromText('POINT(150 221)')),
+('z', 'm', 'z', GeomFromText('POINT(119 42)')),
+('l', 'j', 's', GeomFromText('POINT(97 96)')),
+('f', 'z', 'x', GeomFromText('POINT(208 65)')),
+('i', 'v', 'c', GeomFromText('POINT(145 79)')),
+('l', 'f', 'k', GeomFromText('POINT(83 234)')),
+('u', 'a', 's', GeomFromText('POINT(250 49)')),
+('o', 'k', 'p', GeomFromText('POINT(46 50)')),
+('d', 'e', 'z', GeomFromText('POINT(30 198)')),
+('r', 'r', 'l', GeomFromText('POINT(78 189)')),
+('y', 'l', 'f', GeomFromText('POINT(188 132)')),
+('d', 'q', 'm', GeomFromText('POINT(247 107)')),
+('p', 'j', 'n', GeomFromText('POINT(148 227)')),
+('b', 'o', 'i', GeomFromText('POINT(172 25)')),
+('e', 'v', 'd', GeomFromText('POINT(94 248)')),
+('q', 'd', 'f', GeomFromText('POINT(15 29)')),
+('w', 'b', 'b', GeomFromText('POINT(74 111)')),
+('g', 'q', 'f', GeomFromText('POINT(107 215)')),
+('o', 'h', 'r', GeomFromText('POINT(25 168)')),
+('u', 't', 'w', GeomFromText('POINT(251 188)')),
+('h', 's', 'w', GeomFromText('POINT(254 247)')),
+('f', 'f', 'b', GeomFromText('POINT(166 103)'));
+SET @@RAND_SEED1=866613816, @@RAND_SEED2=92289615;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('l', 'c', 'l', GeomFromText('POINT(202 98)')),
+('k', 'c', 'b', GeomFromText('POINT(46 206)')),
+('r', 'y', 'm', GeomFromText('POINT(74 140)')),
+('y', 'z', 'd', GeomFromText('POINT(200 160)')),
+('s', 'y', 's', GeomFromText('POINT(156 205)')),
+('u', 'v', 'p', GeomFromText('POINT(86 82)')),
+('j', 's', 's', GeomFromText('POINT(91 233)')),
+('x', 'j', 'f', GeomFromText('POINT(3 14)')),
+('l', 'z', 'v', GeomFromText('POINT(123 156)')),
+('h', 'i', 'o', GeomFromText('POINT(145 229)')),
+('o', 'r', 'd', GeomFromText('POINT(15 22)')),
+('f', 'x', 't', GeomFromText('POINT(21 60)')),
+('t', 'g', 'h', GeomFromText('POINT(50 153)')),
+('g', 'u', 'b', GeomFromText('POINT(82 85)')),
+('v', 'a', 'p', GeomFromText('POINT(231 178)')),
+('n', 'v', 'o', GeomFromText('POINT(183 25)')),
+('j', 'n', 'm', GeomFromText('POINT(50 144)')),
+('e', 'f', 'i', GeomFromText('POINT(46 16)')),
+('d', 'w', 'a', GeomFromText('POINT(66 6)')),
+('f', 'x', 'a', GeomFromText('POINT(107 197)')),
+('m', 'o', 'a', GeomFromText('POINT(142 80)')),
+('q', 'l', 'g', GeomFromText('POINT(251 23)')),
+('c', 's', 's', GeomFromText('POINT(158 43)')),
+('y', 'd', 'o', GeomFromText('POINT(196 228)')),
+('d', 'p', 'l', GeomFromText('POINT(107 5)')),
+('h', 'a', 'b', GeomFromText('POINT(183 166)')),
+('m', 'w', 'p', GeomFromText('POINT(19 59)')),
+('b', 'y', 'o', GeomFromText('POINT(178 30)')),
+('x', 'w', 'i', GeomFromText('POINT(168 94)')),
+('t', 'k', 'z', GeomFromText('POINT(171 5)')),
+('r', 'm', 'a', GeomFromText('POINT(222 19)')),
+('u', 'v', 'e', GeomFromText('POINT(224 80)')),
+('q', 'r', 'k', GeomFromText('POINT(212 218)')),
+('d', 'p', 'j', GeomFromText('POINT(169 7)')),
+('d', 'r', 'v', GeomFromText('POINT(193 23)')),
+('n', 'y', 'y', GeomFromText('POINT(130 178)')),
+('m', 'z', 'r', GeomFromText('POINT(81 200)')),
+('j', 'e', 'w', GeomFromText('POINT(145 239)')),
+('v', 'h', 'x', GeomFromText('POINT(24 105)')),
+('z', 'm', 'a', GeomFromText('POINT(175 129)')),
+('b', 'c', 'v', GeomFromText('POINT(213 10)')),
+('t', 't', 'u', GeomFromText('POINT(2 129)')),
+('r', 's', 'v', GeomFromText('POINT(209 192)')),
+('x', 'p', 'g', GeomFromText('POINT(43 63)')),
+('t', 'e', 'u', GeomFromText('POINT(139 210)')),
+('l', 'e', 't', GeomFromText('POINT(245 148)')),
+('a', 'i', 'k', GeomFromText('POINT(167 195)')),
+('m', 'o', 'h', GeomFromText('POINT(206 120)')),
+('g', 'z', 's', GeomFromText('POINT(169 240)')),
+('z', 'u', 's', GeomFromText('POINT(202 120)')),
+('i', 'b', 'a', GeomFromText('POINT(216 18)')),
+('w', 'y', 'g', GeomFromText('POINT(119 236)')),
+('h', 'y', 'p', GeomFromText('POINT(161 24)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(33 100)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(41 46)') where c1 like 'f%';
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+create table t1 (a geometry not null, spatial index(a)) transactional=1 row_format=page;
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072)));
+insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0)));
+insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241)));
+insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231)));
+insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260)));
+insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125)));
+insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29)));
+insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86)));
+insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130)));
+insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34)));
+insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183)));
+insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178)));
+drop table t1;
+CREATE TABLE t1(foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=1 row_format=page;
+INSERT INTO t1(foo) VALUES (NULL);
+ERROR 23000: Column 'foo' cannot be null
+INSERT INTO t1() VALUES ();
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+INSERT INTO t1(foo) VALUES ('');
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+DROP TABLE t1;
+CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)) transactional=1 row_format=page;
+INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)'));
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b GEOMETRY NOT NULL, SPATIAL KEY b(b)) transactional=1 row_format=page;
+INSERT INTO t1 VALUES (1, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+INSERT INTO t1 VALUES (2, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+SELECT COUNT(*) FROM t1 WHERE
+MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+COUNT(*)
+2
+SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE
+MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+COUNT(*)
+2
+DROP TABLE t1;
+End of 5.0 tests.
diff --git a/mysql-test/suite/maria/r/maria-gis-rtree.result b/mysql-test/suite/maria/r/maria-gis-rtree.result
new file mode 100644
index 00000000000..0c929fe1313
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-gis-rtree.result
@@ -0,0 +1,1491 @@
+set storage_engine=maria;
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL,
+SPATIAL KEY(g)
+) transactional=0 row_format=page;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `fid` int(11) NOT NULL AUTO_INCREMENT,
+ `g` geometry NOT NULL,
+ PRIMARY KEY (`fid`),
+ SPATIAL KEY `g` (`g`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 ROW_FORMAT=PAGE TRANSACTIONAL=0
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(150 150, 150 150)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(149 149, 151 151)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(148 148, 152 152)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(147 147, 153 153)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(146 146, 154 154)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(145 145, 155 155)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(144 144, 156 156)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(143 143, 157 157)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(142 142, 158 158)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(141 141, 159 159)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(140 140, 160 160)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(139 139, 161 161)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(138 138, 162 162)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(137 137, 163 163)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(136 136, 164 164)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(135 135, 165 165)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(134 134, 166 166)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(133 133, 167 167)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(132 132, 168 168)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(131 131, 169 169)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(130 130, 170 170)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(129 129, 171 171)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(128 128, 172 172)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(127 127, 173 173)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(126 126, 174 174)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(125 125, 175 175)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(124 124, 176 176)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(123 123, 177 177)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(122 122, 178 178)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(121 121, 179 179)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(120 120, 180 180)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(119 119, 181 181)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(118 118, 182 182)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(117 117, 183 183)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(116 116, 184 184)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(115 115, 185 185)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(114 114, 186 186)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(113 113, 187 187)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(112 112, 188 188)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(111 111, 189 189)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(110 110, 190 190)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(109 109, 191 191)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(108 108, 192 192)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(107 107, 193 193)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(106 106, 194 194)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(105 105, 195 195)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(104 104, 196 196)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(103 103, 197 197)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(102 102, 198 198)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(101 101, 199 199)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(100 100, 200 200)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(99 99, 201 201)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(98 98, 202 202)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(97 97, 203 203)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(96 96, 204 204)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(95 95, 205 205)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(94 94, 206 206)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(93 93, 207 207)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(92 92, 208 208)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(91 91, 209 209)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(90 90, 210 210)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(89 89, 211 211)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(88 88, 212 212)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(87 87, 213 213)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(86 86, 214 214)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(85 85, 215 215)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(84 84, 216 216)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(83 83, 217 217)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(82 82, 218 218)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(81 81, 219 219)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(80 80, 220 220)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(79 79, 221 221)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(78 78, 222 222)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(77 77, 223 223)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(76 76, 224 224)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(75 75, 225 225)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(74 74, 226 226)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(73 73, 227 227)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(72 72, 228 228)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(71 71, 229 229)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(70 70, 230 230)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(69 69, 231 231)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(68 68, 232 232)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(67 67, 233 233)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(66 66, 234 234)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(65 65, 235 235)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(64 64, 236 236)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(63 63, 237 237)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(62 62, 238 238)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(61 61, 239 239)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(60 60, 240 240)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(59 59, 241 241)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(58 58, 242 242)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(57 57, 243 243)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(56 56, 244 244)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(55 55, 245 245)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(54 54, 246 246)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(53 53, 247 247)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(52 52, 248 248)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(51 51, 249 249)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(50 50, 250 250)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(49 49, 251 251)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(48 48, 252 252)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(47 47, 253 253)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(46 46, 254 254)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(45 45, 255 255)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(44 44, 256 256)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(43 43, 257 257)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(42 42, 258 258)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(41 41, 259 259)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(40 40, 260 260)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(39 39, 261 261)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(38 38, 262 262)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(37 37, 263 263)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(36 36, 264 264)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(35 35, 265 265)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(34 34, 266 266)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(33 33, 267 267)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(32 32, 268 268)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(31 31, 269 269)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(30 30, 270 270)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(29 29, 271 271)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(28 28, 272 272)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(27 27, 273 273)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(26 26, 274 274)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(25 25, 275 275)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(24 24, 276 276)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(23 23, 277 277)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(22 22, 278 278)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(21 21, 279 279)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(20 20, 280 280)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(19 19, 281 281)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(18 18, 282 282)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(17 17, 283 283)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(16 16, 284 284)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(15 15, 285 285)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(14 14, 286 286)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(13 13, 287 287)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(12 12, 288 288)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(11 11, 289 289)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(10 10, 290 290)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(9 9, 291 291)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(8 8, 292 292)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(7 7, 293 293)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(6 6, 294 294)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(5 5, 295 295)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(4 4, 296 296)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(3 3, 297 297)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(2 2, 298 298)'));
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 1, 299 299)'));
+SELECT count(*) FROM t1;
+count(*)
+150
+EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range g g 34 NULL 11 Using where
+SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+fid AsText(g)
+1 LINESTRING(150 150,150 150)
+2 LINESTRING(149 149,151 151)
+3 LINESTRING(148 148,152 152)
+4 LINESTRING(147 147,153 153)
+5 LINESTRING(146 146,154 154)
+6 LINESTRING(145 145,155 155)
+7 LINESTRING(144 144,156 156)
+8 LINESTRING(143 143,157 157)
+9 LINESTRING(142 142,158 158)
+10 LINESTRING(141 141,159 159)
+11 LINESTRING(140 140,160 160)
+DROP TABLE t1;
+CREATE TABLE t2 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL
+) transactional=0 row_format=page;
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10))));
+INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10))));
+ALTER TABLE t2 ADD SPATIAL KEY(g);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `fid` int(11) NOT NULL AUTO_INCREMENT,
+ `g` geometry NOT NULL,
+ PRIMARY KEY (`fid`),
+ SPATIAL KEY `g` (`g`)
+) ENGINE=MARIA AUTO_INCREMENT=101 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 ROW_FORMAT=PAGE TRANSACTIONAL=0
+SELECT count(*) FROM t2;
+count(*)
+100
+EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range g g 34 NULL 4 Using where
+SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+fid AsText(g)
+45 LINESTRING(51 51,60 60)
+46 LINESTRING(51 41,60 50)
+55 LINESTRING(41 51,50 60)
+56 LINESTRING(41 41,50 50)
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 10 * 10 - 9), Point(10 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+99
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 9 * 10 - 9), Point(10 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+98
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 8 * 10 - 9), Point(10 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+97
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 7 * 10 - 9), Point(10 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+96
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 6 * 10 - 9), Point(10 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+95
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 5 * 10 - 9), Point(10 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+94
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 4 * 10 - 9), Point(10 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+93
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 3 * 10 - 9), Point(10 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+92
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 2 * 10 - 9), Point(10 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+91
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(10 * 10 - 9, 1 * 10 - 9), Point(10 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+90
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 10 * 10 - 9), Point(9 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+89
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 9 * 10 - 9), Point(9 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+88
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 8 * 10 - 9), Point(9 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+87
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 7 * 10 - 9), Point(9 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+86
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 6 * 10 - 9), Point(9 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+85
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 5 * 10 - 9), Point(9 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+84
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 4 * 10 - 9), Point(9 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+83
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 3 * 10 - 9), Point(9 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+82
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 2 * 10 - 9), Point(9 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+81
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(9 * 10 - 9, 1 * 10 - 9), Point(9 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+80
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 10 * 10 - 9), Point(8 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+79
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 9 * 10 - 9), Point(8 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+78
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 8 * 10 - 9), Point(8 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+77
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 7 * 10 - 9), Point(8 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+76
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 6 * 10 - 9), Point(8 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+75
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 5 * 10 - 9), Point(8 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+74
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 4 * 10 - 9), Point(8 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+73
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 3 * 10 - 9), Point(8 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+72
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 2 * 10 - 9), Point(8 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+71
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(8 * 10 - 9, 1 * 10 - 9), Point(8 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+70
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 10 * 10 - 9), Point(7 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+69
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 9 * 10 - 9), Point(7 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+68
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 8 * 10 - 9), Point(7 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+67
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 7 * 10 - 9), Point(7 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+66
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 6 * 10 - 9), Point(7 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+65
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 5 * 10 - 9), Point(7 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+64
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 4 * 10 - 9), Point(7 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+63
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 3 * 10 - 9), Point(7 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+62
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 2 * 10 - 9), Point(7 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+61
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(7 * 10 - 9, 1 * 10 - 9), Point(7 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+60
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 10 * 10 - 9), Point(6 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+59
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 9 * 10 - 9), Point(6 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+58
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 8 * 10 - 9), Point(6 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+57
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 7 * 10 - 9), Point(6 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+56
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 6 * 10 - 9), Point(6 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+55
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 5 * 10 - 9), Point(6 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+54
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 4 * 10 - 9), Point(6 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+53
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 3 * 10 - 9), Point(6 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+52
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 2 * 10 - 9), Point(6 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+51
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(6 * 10 - 9, 1 * 10 - 9), Point(6 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+50
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 10 * 10 - 9), Point(5 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+49
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 9 * 10 - 9), Point(5 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+48
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 8 * 10 - 9), Point(5 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+47
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 7 * 10 - 9), Point(5 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+46
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 6 * 10 - 9), Point(5 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+45
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 5 * 10 - 9), Point(5 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+44
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 4 * 10 - 9), Point(5 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+43
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 3 * 10 - 9), Point(5 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+42
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 2 * 10 - 9), Point(5 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+41
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(5 * 10 - 9, 1 * 10 - 9), Point(5 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+40
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 10 * 10 - 9), Point(4 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+39
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 9 * 10 - 9), Point(4 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+38
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 8 * 10 - 9), Point(4 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+37
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 7 * 10 - 9), Point(4 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+36
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 6 * 10 - 9), Point(4 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+35
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 5 * 10 - 9), Point(4 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+34
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 4 * 10 - 9), Point(4 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+33
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 3 * 10 - 9), Point(4 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+32
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 2 * 10 - 9), Point(4 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+31
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(4 * 10 - 9, 1 * 10 - 9), Point(4 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+30
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 10 * 10 - 9), Point(3 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+29
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 9 * 10 - 9), Point(3 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+28
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 8 * 10 - 9), Point(3 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+27
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 7 * 10 - 9), Point(3 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+26
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 6 * 10 - 9), Point(3 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+25
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 5 * 10 - 9), Point(3 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+24
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 4 * 10 - 9), Point(3 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+23
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 3 * 10 - 9), Point(3 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+22
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 2 * 10 - 9), Point(3 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+21
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(3 * 10 - 9, 1 * 10 - 9), Point(3 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+20
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 10 * 10 - 9), Point(2 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+19
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 9 * 10 - 9), Point(2 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+18
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 8 * 10 - 9), Point(2 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+17
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 7 * 10 - 9), Point(2 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+16
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 6 * 10 - 9), Point(2 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+15
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 5 * 10 - 9), Point(2 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+14
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 4 * 10 - 9), Point(2 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+13
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 3 * 10 - 9), Point(2 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+12
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 2 * 10 - 9), Point(2 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+11
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(2 * 10 - 9, 1 * 10 - 9), Point(2 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+10
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 10 * 10 - 9), Point(1 * 10, 10 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+9
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 9 * 10 - 9), Point(1 * 10, 9 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+8
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 8 * 10 - 9), Point(1 * 10, 8 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+7
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 7 * 10 - 9), Point(1 * 10, 7 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+6
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 6 * 10 - 9), Point(1 * 10, 6 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+5
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 5 * 10 - 9), Point(1 * 10, 5 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+4
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 4 * 10 - 9), Point(1 * 10, 4 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+3
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 3 * 10 - 9), Point(1 * 10, 3 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+2
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 2 * 10 - 9), Point(1 * 10, 2 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+1
+DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point(1 * 10 - 9, 1 * 10 - 9), Point(1 * 10, 1 * 10)))));
+SELECT count(*) FROM t2;
+count(*)
+0
+DROP TABLE t2;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a)) transactional=0 row_format=page;
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+drop table t1;
+CREATE TABLE t1 (
+fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+g GEOMETRY NOT NULL,
+SPATIAL KEY(g)
+) transactional=0 row_format=page;
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
+drop table t1;
+CREATE TABLE t1 (
+line LINESTRING NOT NULL,
+kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+name VARCHAR(32),
+SPATIAL KEY (line)
+) transactional=0 row_format=page;
+ALTER TABLE t1 DISABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES
+("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+ALTER TABLE t1 ENABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES ("austria", "pp", GeomFromText('LINESTRING(14.9906 48.9887,14.9946 48.9904,14.9947 48.9916)'));
+drop table t1;
+CREATE TABLE t1 (st varchar(100));
+INSERT INTO t1 VALUES ("Fake string");
+CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)) transactional=0 row_format=page;
+INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+drop table t1, t2;
+CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) transactional=0 row_format=page DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'geometry' can't have a default value
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
+-66.8158332999, -18.7186111000 -66.8102777000, -18.7211111000 -66.9269443999,
+-18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-65.7402776999 -96.6686111000, -65.7372222000
+-96.5516666000, -65.8502777000 -96.5461111000, -65.8527777000 -96.6627777000,
+-65.7402776999 -96.6686111000))'));
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+CREATE TABLE t1 (
+c1 geometry NOT NULL default '',
+SPATIAL KEY i1 (c1)
+) transactional=0 row_format=page DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'c1' can't have a default value
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 geometry NOT NULL default '',
+SPATIAL KEY i1 (c1)
+) transactional=0 row_format=page DEFAULT CHARSET=latin1;
+Warnings:
+Warning 1101 BLOB/TEXT column 'c1' can't have a default value
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-65.7402776999 -96.6686111000,
+ -65.7372222000 -96.5516666000,
+ -65.8502777000 -96.5461111000,
+ -65.8527777000 -96.6627777000,
+ -65.7402776999 -96.6686111000))'));
+INSERT INTO t1 (c1) VALUES (
+PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=0 row_format=page;
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
+SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
+1
+1
+1
+1
+DROP TABLE t1;
+CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
+c2 varchar(15) collate utf8_bin default NULL,
+c1 varchar(15) collate utf8_bin default NULL,
+c3 varchar(10) collate utf8_bin default NULL,
+spatial_point point NOT NULL,
+PRIMARY KEY(id),
+SPATIAL KEY (spatial_point)
+)transactional=0 row_format=page DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('y', 's', 'j', GeomFromText('POINT(167 74)')),
+('r', 'n', 'd', GeomFromText('POINT(215 118)')),
+('g', 'n', 'e', GeomFromText('POINT(203 98)')),
+('h', 'd', 'd', GeomFromText('POINT(54 193)')),
+('r', 'x', 'y', GeomFromText('POINT(47 69)')),
+('t', 'q', 'r', GeomFromText('POINT(109 42)')),
+('a', 'z', 'd', GeomFromText('POINT(0 154)')),
+('x', 'v', 'o', GeomFromText('POINT(174 131)')),
+('b', 'r', 'a', GeomFromText('POINT(114 253)')),
+('x', 'z', 'i', GeomFromText('POINT(163 21)')),
+('w', 'p', 'i', GeomFromText('POINT(42 102)')),
+('g', 'j', 'j', GeomFromText('POINT(170 133)')),
+('m', 'g', 'n', GeomFromText('POINT(28 22)')),
+('b', 'z', 'h', GeomFromText('POINT(174 28)')),
+('q', 'k', 'f', GeomFromText('POINT(233 73)')),
+('w', 'w', 'a', GeomFromText('POINT(124 200)')),
+('t', 'j', 'w', GeomFromText('POINT(252 101)')),
+('d', 'r', 'd', GeomFromText('POINT(98 18)')),
+('w', 'o', 'y', GeomFromText('POINT(165 31)')),
+('y', 'h', 't', GeomFromText('POINT(14 220)')),
+('d', 'p', 'u', GeomFromText('POINT(223 196)')),
+('g', 'y', 'g', GeomFromText('POINT(207 96)')),
+('x', 'm', 'n', GeomFromText('POINT(214 3)')),
+('g', 'v', 'e', GeomFromText('POINT(140 205)')),
+('g', 'm', 'm', GeomFromText('POINT(10 236)')),
+('i', 'r', 'j', GeomFromText('POINT(137 228)')),
+('w', 's', 'p', GeomFromText('POINT(115 6)')),
+('o', 'n', 'k', GeomFromText('POINT(158 129)')),
+('j', 'h', 'l', GeomFromText('POINT(129 72)')),
+('f', 'x', 'l', GeomFromText('POINT(139 207)')),
+('u', 'd', 'n', GeomFromText('POINT(125 109)')),
+('b', 'a', 'z', GeomFromText('POINT(30 32)')),
+('m', 'h', 'o', GeomFromText('POINT(251 251)')),
+('f', 'r', 'd', GeomFromText('POINT(243 211)')),
+('b', 'd', 'r', GeomFromText('POINT(232 80)')),
+('g', 'k', 'v', GeomFromText('POINT(15 100)')),
+('i', 'f', 'c', GeomFromText('POINT(109 66)')),
+('r', 't', 'j', GeomFromText('POINT(178 6)')),
+('y', 'n', 'f', GeomFromText('POINT(233 211)')),
+('f', 'y', 'm', GeomFromText('POINT(99 16)')),
+('z', 'q', 'l', GeomFromText('POINT(39 49)')),
+('j', 'c', 'r', GeomFromText('POINT(75 187)')),
+('c', 'y', 'y', GeomFromText('POINT(246 253)')),
+('w', 'u', 'd', GeomFromText('POINT(56 190)')),
+('n', 'q', 'm', GeomFromText('POINT(73 149)')),
+('d', 'y', 'a', GeomFromText('POINT(134 6)')),
+('z', 's', 'w', GeomFromText('POINT(216 225)')),
+('d', 'u', 'k', GeomFromText('POINT(132 70)')),
+('f', 'v', 't', GeomFromText('POINT(187 141)')),
+('r', 'r', 'a', GeomFromText('POINT(152 39)')),
+('y', 'p', 'o', GeomFromText('POINT(45 27)')),
+('p', 'n', 'm', GeomFromText('POINT(228 148)')),
+('e', 'g', 'e', GeomFromText('POINT(88 81)')),
+('m', 'a', 'h', GeomFromText('POINT(35 29)')),
+('m', 'h', 'f', GeomFromText('POINT(30 71)')),
+('h', 'k', 'i', GeomFromText('POINT(244 78)')),
+('z', 'v', 'd', GeomFromText('POINT(241 38)')),
+('q', 'l', 'j', GeomFromText('POINT(13 71)')),
+('s', 'p', 'g', GeomFromText('POINT(108 38)')),
+('q', 's', 'j', GeomFromText('POINT(92 101)')),
+('l', 'h', 'g', GeomFromText('POINT(120 78)')),
+('w', 't', 'b', GeomFromText('POINT(193 109)')),
+('b', 's', 's', GeomFromText('POINT(223 211)')),
+('w', 'w', 'y', GeomFromText('POINT(122 42)')),
+('q', 'c', 'c', GeomFromText('POINT(104 102)')),
+('w', 'g', 'n', GeomFromText('POINT(213 120)')),
+('p', 'q', 'a', GeomFromText('POINT(247 148)')),
+('c', 'z', 'e', GeomFromText('POINT(18 106)')),
+('z', 'u', 'n', GeomFromText('POINT(70 133)')),
+('j', 'n', 'x', GeomFromText('POINT(232 13)')),
+('e', 'h', 'f', GeomFromText('POINT(22 135)')),
+('w', 'l', 'f', GeomFromText('POINT(9 180)')),
+('a', 'v', 'q', GeomFromText('POINT(163 228)')),
+('i', 'z', 'o', GeomFromText('POINT(180 100)')),
+('e', 'c', 'l', GeomFromText('POINT(182 231)')),
+('c', 'k', 'o', GeomFromText('POINT(19 60)')),
+('q', 'f', 'p', GeomFromText('POINT(79 95)')),
+('m', 'd', 'r', GeomFromText('POINT(3 127)')),
+('m', 'e', 't', GeomFromText('POINT(136 154)')),
+('w', 'w', 'w', GeomFromText('POINT(102 15)')),
+('l', 'n', 'q', GeomFromText('POINT(71 196)')),
+('p', 'k', 'c', GeomFromText('POINT(47 139)')),
+('j', 'o', 'r', GeomFromText('POINT(177 128)')),
+('j', 'q', 'a', GeomFromText('POINT(170 6)')),
+('b', 'a', 'o', GeomFromText('POINT(63 211)')),
+('g', 's', 'o', GeomFromText('POINT(144 251)')),
+('w', 'u', 'w', GeomFromText('POINT(221 214)')),
+('g', 'a', 'm', GeomFromText('POINT(14 102)')),
+('u', 'q', 'z', GeomFromText('POINT(86 200)')),
+('k', 'a', 'm', GeomFromText('POINT(144 222)')),
+('j', 'u', 'r', GeomFromText('POINT(216 142)')),
+('q', 'k', 'v', GeomFromText('POINT(121 236)')),
+('p', 'o', 'r', GeomFromText('POINT(108 102)')),
+('b', 'd', 'x', GeomFromText('POINT(127 198)')),
+('k', 's', 'a', GeomFromText('POINT(2 150)')),
+('f', 'm', 'f', GeomFromText('POINT(160 191)')),
+('q', 'y', 'x', GeomFromText('POINT(98 111)')),
+('o', 'f', 'm', GeomFromText('POINT(232 218)')),
+('c', 'w', 'j', GeomFromText('POINT(156 165)')),
+('s', 'q', 'v', GeomFromText('POINT(98 161)'));
+SET @@RAND_SEED1=692635050, @@RAND_SEED2=297339954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=159925977, @@RAND_SEED2=942570618;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=328169745, @@RAND_SEED2=410451954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(19 81)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(20 177)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(221 193)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(195 205)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(15 213)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(214 63)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(243 171)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(198 82)') where c1 like 'y%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('f', 'y', 'p', GeomFromText('POINT(109 235)')),
+('b', 'e', 'v', GeomFromText('POINT(20 48)')),
+('i', 'u', 'f', GeomFromText('POINT(15 55)')),
+('o', 'r', 'z', GeomFromText('POINT(105 64)')),
+('a', 'p', 'a', GeomFromText('POINT(142 236)')),
+('g', 'i', 'k', GeomFromText('POINT(10 49)')),
+('x', 'z', 'x', GeomFromText('POINT(192 200)')),
+('c', 'v', 'r', GeomFromText('POINT(94 168)')),
+('y', 'z', 'e', GeomFromText('POINT(141 51)')),
+('h', 'm', 'd', GeomFromText('POINT(35 251)')),
+('v', 'm', 'q', GeomFromText('POINT(44 90)')),
+('j', 'l', 'z', GeomFromText('POINT(67 237)')),
+('i', 'v', 'a', GeomFromText('POINT(75 14)')),
+('b', 'q', 't', GeomFromText('POINT(153 33)')),
+('e', 'm', 'a', GeomFromText('POINT(247 49)')),
+('l', 'y', 'g', GeomFromText('POINT(56 203)')),
+('v', 'o', 'r', GeomFromText('POINT(90 54)')),
+('r', 'n', 'd', GeomFromText('POINT(135 83)')),
+('j', 't', 'u', GeomFromText('POINT(174 239)')),
+('u', 'n', 'g', GeomFromText('POINT(104 191)')),
+('p', 'q', 'y', GeomFromText('POINT(63 171)')),
+('o', 'q', 'p', GeomFromText('POINT(192 103)')),
+('f', 'x', 'e', GeomFromText('POINT(244 30)')),
+('n', 'x', 'c', GeomFromText('POINT(92 103)')),
+('r', 'q', 'z', GeomFromText('POINT(166 20)')),
+('s', 'a', 'j', GeomFromText('POINT(137 205)')),
+('z', 't', 't', GeomFromText('POINT(99 134)')),
+('o', 'm', 'j', GeomFromText('POINT(217 3)')),
+('n', 'h', 'j', GeomFromText('POINT(211 17)')),
+('v', 'v', 'a', GeomFromText('POINT(41 137)')),
+('q', 'o', 'j', GeomFromText('POINT(5 92)')),
+('z', 'y', 'e', GeomFromText('POINT(175 212)')),
+('j', 'z', 'h', GeomFromText('POINT(224 194)')),
+('a', 'g', 'm', GeomFromText('POINT(31 119)')),
+('p', 'c', 'f', GeomFromText('POINT(17 221)')),
+('t', 'h', 'k', GeomFromText('POINT(26 203)')),
+('u', 'w', 'p', GeomFromText('POINT(47 185)')),
+('z', 'a', 'c', GeomFromText('POINT(61 133)')),
+('u', 'k', 'a', GeomFromText('POINT(210 115)')),
+('k', 'f', 'h', GeomFromText('POINT(125 113)')),
+('t', 'v', 'y', GeomFromText('POINT(12 239)')),
+('u', 'v', 'd', GeomFromText('POINT(90 24)')),
+('m', 'y', 'w', GeomFromText('POINT(25 243)')),
+('d', 'n', 'g', GeomFromText('POINT(122 92)')),
+('z', 'm', 'f', GeomFromText('POINT(235 110)')),
+('q', 'd', 'f', GeomFromText('POINT(233 217)')),
+('a', 'v', 'u', GeomFromText('POINT(69 59)')),
+('x', 'k', 'p', GeomFromText('POINT(240 14)')),
+('i', 'v', 'r', GeomFromText('POINT(154 42)')),
+('w', 'h', 'l', GeomFromText('POINT(178 156)')),
+('d', 'h', 'n', GeomFromText('POINT(65 157)')),
+('c', 'k', 'z', GeomFromText('POINT(62 33)')),
+('e', 'l', 'w', GeomFromText('POINT(162 1)')),
+('r', 'f', 'i', GeomFromText('POINT(127 71)')),
+('q', 'm', 'c', GeomFromText('POINT(63 118)')),
+('c', 'h', 'u', GeomFromText('POINT(205 203)')),
+('d', 't', 'p', GeomFromText('POINT(234 87)')),
+('s', 'g', 'h', GeomFromText('POINT(149 34)')),
+('o', 'b', 'q', GeomFromText('POINT(159 179)')),
+('k', 'u', 'f', GeomFromText('POINT(202 254)')),
+('u', 'f', 'g', GeomFromText('POINT(70 15)')),
+('x', 's', 'b', GeomFromText('POINT(25 181)')),
+('s', 'c', 'g', GeomFromText('POINT(252 17)')),
+('a', 'c', 'f', GeomFromText('POINT(89 67)')),
+('r', 'e', 'q', GeomFromText('POINT(55 54)')),
+('f', 'i', 'k', GeomFromText('POINT(178 230)')),
+('p', 'e', 'l', GeomFromText('POINT(198 28)')),
+('w', 'o', 'd', GeomFromText('POINT(204 189)')),
+('c', 'a', 'g', GeomFromText('POINT(230 178)')),
+('r', 'o', 'e', GeomFromText('POINT(61 116)')),
+('w', 'a', 'a', GeomFromText('POINT(178 237)')),
+('v', 'd', 'e', GeomFromText('POINT(70 85)')),
+('k', 'c', 'e', GeomFromText('POINT(147 118)')),
+('d', 'q', 't', GeomFromText('POINT(218 77)')),
+('k', 'g', 'f', GeomFromText('POINT(192 113)')),
+('w', 'n', 'e', GeomFromText('POINT(92 124)')),
+('r', 'm', 'q', GeomFromText('POINT(130 65)')),
+('o', 'r', 'r', GeomFromText('POINT(174 233)')),
+('k', 'n', 't', GeomFromText('POINT(175 147)')),
+('q', 'm', 'r', GeomFromText('POINT(18 208)')),
+('l', 'd', 'i', GeomFromText('POINT(13 104)')),
+('w', 'o', 'y', GeomFromText('POINT(207 39)')),
+('p', 'u', 'o', GeomFromText('POINT(114 31)')),
+('y', 'a', 'p', GeomFromText('POINT(106 59)')),
+('a', 'x', 'z', GeomFromText('POINT(17 57)')),
+('v', 'h', 'x', GeomFromText('POINT(170 13)')),
+('t', 's', 'u', GeomFromText('POINT(84 18)')),
+('z', 'z', 'f', GeomFromText('POINT(250 197)')),
+('l', 'z', 't', GeomFromText('POINT(59 80)')),
+('j', 'g', 's', GeomFromText('POINT(54 26)')),
+('g', 'v', 'm', GeomFromText('POINT(89 98)')),
+('q', 'v', 'b', GeomFromText('POINT(39 240)')),
+('x', 'k', 'v', GeomFromText('POINT(246 207)')),
+('k', 'u', 'i', GeomFromText('POINT(105 111)')),
+('w', 'z', 's', GeomFromText('POINT(235 8)')),
+('d', 'd', 'd', GeomFromText('POINT(105 4)')),
+('c', 'z', 'q', GeomFromText('POINT(13 140)')),
+('m', 'k', 'i', GeomFromText('POINT(208 120)')),
+('g', 'a', 'g', GeomFromText('POINT(9 182)')),
+('z', 'j', 'r', GeomFromText('POINT(149 153)')),
+('h', 'f', 'g', GeomFromText('POINT(81 236)')),
+('m', 'e', 'q', GeomFromText('POINT(209 215)')),
+('c', 'h', 'y', GeomFromText('POINT(235 70)')),
+('i', 'e', 'g', GeomFromText('POINT(138 26)')),
+('m', 't', 'u', GeomFromText('POINT(119 237)')),
+('o', 'w', 's', GeomFromText('POINT(193 166)')),
+('f', 'm', 'q', GeomFromText('POINT(85 96)')),
+('x', 'l', 'x', GeomFromText('POINT(58 115)')),
+('x', 'q', 'u', GeomFromText('POINT(108 210)')),
+('b', 'h', 'i', GeomFromText('POINT(250 139)')),
+('y', 'd', 'x', GeomFromText('POINT(199 135)')),
+('w', 'h', 'p', GeomFromText('POINT(247 233)')),
+('p', 'z', 't', GeomFromText('POINT(148 249)')),
+('q', 'a', 'u', GeomFromText('POINT(174 78)')),
+('v', 't', 'm', GeomFromText('POINT(70 228)')),
+('t', 'n', 'f', GeomFromText('POINT(123 2)')),
+('x', 't', 'b', GeomFromText('POINT(35 50)')),
+('r', 'j', 'f', GeomFromText('POINT(200 51)')),
+('s', 'q', 'o', GeomFromText('POINT(23 184)')),
+('u', 'v', 'z', GeomFromText('POINT(7 113)')),
+('v', 'u', 'l', GeomFromText('POINT(145 190)')),
+('o', 'k', 'i', GeomFromText('POINT(161 122)')),
+('l', 'y', 'e', GeomFromText('POINT(17 232)')),
+('t', 'b', 'e', GeomFromText('POINT(120 50)')),
+('e', 's', 'u', GeomFromText('POINT(254 1)')),
+('d', 'd', 'u', GeomFromText('POINT(167 140)')),
+('o', 'b', 'x', GeomFromText('POINT(186 237)')),
+('m', 's', 's', GeomFromText('POINT(172 149)')),
+('t', 'y', 'a', GeomFromText('POINT(149 85)')),
+('x', 't', 'r', GeomFromText('POINT(10 165)')),
+('g', 'c', 'e', GeomFromText('POINT(95 165)')),
+('e', 'e', 'z', GeomFromText('POINT(98 65)')),
+('f', 'v', 'i', GeomFromText('POINT(149 144)')),
+('o', 'p', 'm', GeomFromText('POINT(233 67)')),
+('t', 'u', 'b', GeomFromText('POINT(109 215)')),
+('o', 'o', 'b', GeomFromText('POINT(130 48)')),
+('e', 'm', 'h', GeomFromText('POINT(88 189)')),
+('e', 'v', 'y', GeomFromText('POINT(55 29)')),
+('e', 't', 'm', GeomFromText('POINT(129 55)')),
+('p', 'p', 'i', GeomFromText('POINT(126 222)')),
+('c', 'i', 'c', GeomFromText('POINT(19 158)')),
+('c', 'b', 's', GeomFromText('POINT(13 19)')),
+('u', 'y', 'a', GeomFromText('POINT(114 5)')),
+('a', 'o', 'f', GeomFromText('POINT(227 232)')),
+('t', 'c', 'z', GeomFromText('POINT(63 62)')),
+('d', 'o', 'k', GeomFromText('POINT(48 228)')),
+('x', 'c', 'e', GeomFromText('POINT(204 2)')),
+('e', 'e', 'g', GeomFromText('POINT(125 43)')),
+('o', 'r', 'f', GeomFromText('POINT(171 140)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(163 157)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(53 151)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(96 183)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(57 91)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 110)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('b', 'c', 'e', GeomFromText('POINT(41 137)')),
+('p', 'y', 'k', GeomFromText('POINT(50 22)')),
+('s', 'c', 'h', GeomFromText('POINT(208 173)')),
+('x', 'u', 'l', GeomFromText('POINT(199 175)')),
+('s', 'r', 'h', GeomFromText('POINT(85 192)')),
+('j', 'k', 'u', GeomFromText('POINT(18 25)')),
+('p', 'w', 'h', GeomFromText('POINT(152 197)')),
+('e', 'd', 'c', GeomFromText('POINT(229 3)')),
+('o', 'x', 'k', GeomFromText('POINT(187 155)')),
+('o', 'b', 'k', GeomFromText('POINT(208 150)')),
+('d', 'a', 'j', GeomFromText('POINT(70 87)')),
+('f', 'e', 'k', GeomFromText('POINT(156 96)')),
+('u', 'y', 'p', GeomFromText('POINT(239 193)')),
+('n', 'v', 'p', GeomFromText('POINT(223 98)')),
+('z', 'j', 'r', GeomFromText('POINT(87 89)')),
+('h', 'x', 'x', GeomFromText('POINT(92 0)')),
+('r', 'v', 'r', GeomFromText('POINT(159 139)')),
+('v', 'g', 'g', GeomFromText('POINT(16 229)')),
+('z', 'k', 'u', GeomFromText('POINT(99 52)')),
+('p', 'p', 'o', GeomFromText('POINT(105 125)')),
+('w', 'h', 'y', GeomFromText('POINT(105 154)')),
+('v', 'y', 'z', GeomFromText('POINT(134 238)')),
+('x', 'o', 'o', GeomFromText('POINT(178 88)')),
+('z', 'w', 'd', GeomFromText('POINT(123 60)')),
+('q', 'f', 'u', GeomFromText('POINT(64 90)')),
+('s', 'n', 't', GeomFromText('POINT(50 138)')),
+('v', 'p', 't', GeomFromText('POINT(114 91)')),
+('a', 'o', 'n', GeomFromText('POINT(78 43)')),
+('k', 'u', 'd', GeomFromText('POINT(185 161)')),
+('w', 'd', 'n', GeomFromText('POINT(25 92)')),
+('k', 'w', 'a', GeomFromText('POINT(59 238)')),
+('t', 'c', 'f', GeomFromText('POINT(65 87)')),
+('g', 's', 'p', GeomFromText('POINT(238 126)')),
+('d', 'n', 'y', GeomFromText('POINT(107 173)')),
+('l', 'a', 'w', GeomFromText('POINT(125 152)')),
+('m', 'd', 'j', GeomFromText('POINT(146 53)')),
+('q', 'm', 'c', GeomFromText('POINT(217 187)')),
+('i', 'r', 'r', GeomFromText('POINT(6 113)')),
+('e', 'j', 'b', GeomFromText('POINT(37 83)')),
+('w', 'w', 'h', GeomFromText('POINT(83 199)')),
+('k', 'b', 's', GeomFromText('POINT(170 64)')),
+('s', 'b', 'c', GeomFromText('POINT(163 130)')),
+('c', 'h', 'a', GeomFromText('POINT(141 3)')),
+('k', 'j', 'u', GeomFromText('POINT(143 76)')),
+('r', 'h', 'o', GeomFromText('POINT(243 92)')),
+('i', 'd', 'b', GeomFromText('POINT(205 13)')),
+('r', 'y', 'q', GeomFromText('POINT(138 8)')),
+('m', 'o', 'i', GeomFromText('POINT(36 45)')),
+('v', 'g', 'm', GeomFromText('POINT(0 40)')),
+('f', 'e', 'i', GeomFromText('POINT(76 6)')),
+('c', 'q', 'q', GeomFromText('POINT(115 248)')),
+('x', 'c', 'i', GeomFromText('POINT(29 74)')),
+('l', 's', 't', GeomFromText('POINT(83 18)')),
+('t', 't', 'a', GeomFromText('POINT(26 168)')),
+('u', 'n', 'x', GeomFromText('POINT(200 110)')),
+('j', 'b', 'd', GeomFromText('POINT(216 136)')),
+('s', 'p', 'w', GeomFromText('POINT(38 156)')),
+('f', 'b', 'v', GeomFromText('POINT(29 186)')),
+('v', 'e', 'r', GeomFromText('POINT(149 40)')),
+('v', 't', 'm', GeomFromText('POINT(184 24)')),
+('y', 'g', 'a', GeomFromText('POINT(219 105)')),
+('s', 'f', 'i', GeomFromText('POINT(114 130)')),
+('e', 'q', 'h', GeomFromText('POINT(203 135)')),
+('h', 'g', 'b', GeomFromText('POINT(9 208)')),
+('o', 'l', 'r', GeomFromText('POINT(245 79)')),
+('s', 's', 'v', GeomFromText('POINT(238 198)')),
+('w', 'w', 'z', GeomFromText('POINT(209 232)')),
+('v', 'd', 'n', GeomFromText('POINT(30 193)')),
+('q', 'w', 'k', GeomFromText('POINT(133 18)')),
+('o', 'h', 'o', GeomFromText('POINT(42 140)')),
+('f', 'f', 'h', GeomFromText('POINT(145 1)')),
+('u', 's', 'r', GeomFromText('POINT(70 62)')),
+('x', 'n', 'q', GeomFromText('POINT(33 86)')),
+('u', 'p', 'v', GeomFromText('POINT(232 220)')),
+('z', 'e', 'a', GeomFromText('POINT(130 69)')),
+('r', 'u', 'z', GeomFromText('POINT(243 241)')),
+('b', 'n', 't', GeomFromText('POINT(120 12)')),
+('u', 'f', 's', GeomFromText('POINT(190 212)')),
+('a', 'd', 'q', GeomFromText('POINT(235 191)')),
+('f', 'q', 'm', GeomFromText('POINT(176 2)')),
+('n', 'c', 's', GeomFromText('POINT(218 163)')),
+('e', 'm', 'h', GeomFromText('POINT(163 108)')),
+('c', 'f', 'l', GeomFromText('POINT(220 115)')),
+('c', 'v', 'q', GeomFromText('POINT(66 45)')),
+('w', 'v', 'x', GeomFromText('POINT(251 220)')),
+('f', 'w', 'z', GeomFromText('POINT(146 149)')),
+('h', 'n', 'h', GeomFromText('POINT(148 128)')),
+('y', 'k', 'v', GeomFromText('POINT(28 110)')),
+('c', 'x', 'q', GeomFromText('POINT(13 13)')),
+('e', 'd', 's', GeomFromText('POINT(91 190)')),
+('c', 'w', 'c', GeomFromText('POINT(10 231)')),
+('u', 'j', 'n', GeomFromText('POINT(250 21)')),
+('w', 'n', 'x', GeomFromText('POINT(141 69)')),
+('f', 'p', 'y', GeomFromText('POINT(228 246)')),
+('d', 'q', 'f', GeomFromText('POINT(194 22)')),
+('d', 'z', 'l', GeomFromText('POINT(233 181)')),
+('c', 'a', 'q', GeomFromText('POINT(183 96)')),
+('m', 'i', 'd', GeomFromText('POINT(117 226)')),
+('z', 'y', 'y', GeomFromText('POINT(62 81)')),
+('g', 'v', 'm', GeomFromText('POINT(66 158)'));
+SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1072017234, @@RAND_SEED2=484203885;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=358851897, @@RAND_SEED2=358495224;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=509031459, @@RAND_SEED2=675962925;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(61 203)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 194)') where c1 like 'f%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(228 18)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 18)') where c1 like 'l%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(176 94)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(44 47)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 191)') where c1 like 'b%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(179 218)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(239 40)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(248 41)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(167 82)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(13 104)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(139 84)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(145 108)') where c1 like 'p%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(147 57)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(217 144)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(160 224)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(38 28)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(104 114)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 19)') where c1 like 'c%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('f', 'x', 'p', GeomFromText('POINT(92 181)')),
+('s', 'i', 'c', GeomFromText('POINT(49 60)')),
+('c', 'c', 'i', GeomFromText('POINT(7 57)')),
+('n', 'g', 'k', GeomFromText('POINT(252 105)')),
+('g', 'b', 'm', GeomFromText('POINT(180 11)')),
+('u', 'l', 'r', GeomFromText('POINT(32 90)')),
+('c', 'x', 'e', GeomFromText('POINT(143 24)')),
+('x', 'u', 'a', GeomFromText('POINT(123 92)')),
+('s', 'b', 'h', GeomFromText('POINT(190 108)')),
+('c', 'x', 'b', GeomFromText('POINT(104 100)')),
+('i', 'd', 't', GeomFromText('POINT(214 104)')),
+('r', 'w', 'g', GeomFromText('POINT(29 67)')),
+('b', 'f', 'g', GeomFromText('POINT(149 46)')),
+('r', 'r', 'd', GeomFromText('POINT(242 196)')),
+('j', 'l', 'a', GeomFromText('POINT(90 196)')),
+('e', 't', 'b', GeomFromText('POINT(190 64)')),
+('l', 'x', 'w', GeomFromText('POINT(250 73)')),
+('q', 'y', 'r', GeomFromText('POINT(120 182)')),
+('s', 'j', 'a', GeomFromText('POINT(180 175)')),
+('n', 'i', 'y', GeomFromText('POINT(124 136)')),
+('s', 'x', 's', GeomFromText('POINT(176 209)')),
+('u', 'f', 's', GeomFromText('POINT(215 173)')),
+('m', 'j', 'x', GeomFromText('POINT(44 140)')),
+('v', 'g', 'x', GeomFromText('POINT(177 233)')),
+('u', 't', 'b', GeomFromText('POINT(136 197)')),
+('f', 'g', 'b', GeomFromText('POINT(10 8)')),
+('v', 'c', 'j', GeomFromText('POINT(13 81)')),
+('d', 's', 'q', GeomFromText('POINT(200 100)')),
+('a', 'p', 'j', GeomFromText('POINT(33 40)')),
+('i', 'c', 'g', GeomFromText('POINT(168 204)')),
+('k', 'h', 'i', GeomFromText('POINT(93 243)')),
+('s', 'b', 's', GeomFromText('POINT(157 13)')),
+('v', 'l', 'l', GeomFromText('POINT(103 6)')),
+('r', 'b', 'k', GeomFromText('POINT(244 137)')),
+('l', 'd', 'r', GeomFromText('POINT(162 254)')),
+('q', 'b', 'z', GeomFromText('POINT(136 246)')),
+('x', 'x', 'p', GeomFromText('POINT(120 37)')),
+('m', 'e', 'z', GeomFromText('POINT(203 167)')),
+('q', 'n', 'p', GeomFromText('POINT(94 119)')),
+('b', 'g', 'u', GeomFromText('POINT(93 248)')),
+('r', 'v', 'v', GeomFromText('POINT(53 88)')),
+('y', 'a', 'i', GeomFromText('POINT(98 219)')),
+('a', 's', 'g', GeomFromText('POINT(173 138)')),
+('c', 'a', 't', GeomFromText('POINT(235 135)')),
+('q', 'm', 'd', GeomFromText('POINT(224 208)')),
+('e', 'p', 'k', GeomFromText('POINT(161 238)')),
+('n', 'g', 'q', GeomFromText('POINT(35 204)')),
+('t', 't', 'x', GeomFromText('POINT(230 178)')),
+('w', 'f', 'a', GeomFromText('POINT(150 221)')),
+('z', 'm', 'z', GeomFromText('POINT(119 42)')),
+('l', 'j', 's', GeomFromText('POINT(97 96)')),
+('f', 'z', 'x', GeomFromText('POINT(208 65)')),
+('i', 'v', 'c', GeomFromText('POINT(145 79)')),
+('l', 'f', 'k', GeomFromText('POINT(83 234)')),
+('u', 'a', 's', GeomFromText('POINT(250 49)')),
+('o', 'k', 'p', GeomFromText('POINT(46 50)')),
+('d', 'e', 'z', GeomFromText('POINT(30 198)')),
+('r', 'r', 'l', GeomFromText('POINT(78 189)')),
+('y', 'l', 'f', GeomFromText('POINT(188 132)')),
+('d', 'q', 'm', GeomFromText('POINT(247 107)')),
+('p', 'j', 'n', GeomFromText('POINT(148 227)')),
+('b', 'o', 'i', GeomFromText('POINT(172 25)')),
+('e', 'v', 'd', GeomFromText('POINT(94 248)')),
+('q', 'd', 'f', GeomFromText('POINT(15 29)')),
+('w', 'b', 'b', GeomFromText('POINT(74 111)')),
+('g', 'q', 'f', GeomFromText('POINT(107 215)')),
+('o', 'h', 'r', GeomFromText('POINT(25 168)')),
+('u', 't', 'w', GeomFromText('POINT(251 188)')),
+('h', 's', 'w', GeomFromText('POINT(254 247)')),
+('f', 'f', 'b', GeomFromText('POINT(166 103)'));
+SET @@RAND_SEED1=866613816, @@RAND_SEED2=92289615;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+('l', 'c', 'l', GeomFromText('POINT(202 98)')),
+('k', 'c', 'b', GeomFromText('POINT(46 206)')),
+('r', 'y', 'm', GeomFromText('POINT(74 140)')),
+('y', 'z', 'd', GeomFromText('POINT(200 160)')),
+('s', 'y', 's', GeomFromText('POINT(156 205)')),
+('u', 'v', 'p', GeomFromText('POINT(86 82)')),
+('j', 's', 's', GeomFromText('POINT(91 233)')),
+('x', 'j', 'f', GeomFromText('POINT(3 14)')),
+('l', 'z', 'v', GeomFromText('POINT(123 156)')),
+('h', 'i', 'o', GeomFromText('POINT(145 229)')),
+('o', 'r', 'd', GeomFromText('POINT(15 22)')),
+('f', 'x', 't', GeomFromText('POINT(21 60)')),
+('t', 'g', 'h', GeomFromText('POINT(50 153)')),
+('g', 'u', 'b', GeomFromText('POINT(82 85)')),
+('v', 'a', 'p', GeomFromText('POINT(231 178)')),
+('n', 'v', 'o', GeomFromText('POINT(183 25)')),
+('j', 'n', 'm', GeomFromText('POINT(50 144)')),
+('e', 'f', 'i', GeomFromText('POINT(46 16)')),
+('d', 'w', 'a', GeomFromText('POINT(66 6)')),
+('f', 'x', 'a', GeomFromText('POINT(107 197)')),
+('m', 'o', 'a', GeomFromText('POINT(142 80)')),
+('q', 'l', 'g', GeomFromText('POINT(251 23)')),
+('c', 's', 's', GeomFromText('POINT(158 43)')),
+('y', 'd', 'o', GeomFromText('POINT(196 228)')),
+('d', 'p', 'l', GeomFromText('POINT(107 5)')),
+('h', 'a', 'b', GeomFromText('POINT(183 166)')),
+('m', 'w', 'p', GeomFromText('POINT(19 59)')),
+('b', 'y', 'o', GeomFromText('POINT(178 30)')),
+('x', 'w', 'i', GeomFromText('POINT(168 94)')),
+('t', 'k', 'z', GeomFromText('POINT(171 5)')),
+('r', 'm', 'a', GeomFromText('POINT(222 19)')),
+('u', 'v', 'e', GeomFromText('POINT(224 80)')),
+('q', 'r', 'k', GeomFromText('POINT(212 218)')),
+('d', 'p', 'j', GeomFromText('POINT(169 7)')),
+('d', 'r', 'v', GeomFromText('POINT(193 23)')),
+('n', 'y', 'y', GeomFromText('POINT(130 178)')),
+('m', 'z', 'r', GeomFromText('POINT(81 200)')),
+('j', 'e', 'w', GeomFromText('POINT(145 239)')),
+('v', 'h', 'x', GeomFromText('POINT(24 105)')),
+('z', 'm', 'a', GeomFromText('POINT(175 129)')),
+('b', 'c', 'v', GeomFromText('POINT(213 10)')),
+('t', 't', 'u', GeomFromText('POINT(2 129)')),
+('r', 's', 'v', GeomFromText('POINT(209 192)')),
+('x', 'p', 'g', GeomFromText('POINT(43 63)')),
+('t', 'e', 'u', GeomFromText('POINT(139 210)')),
+('l', 'e', 't', GeomFromText('POINT(245 148)')),
+('a', 'i', 'k', GeomFromText('POINT(167 195)')),
+('m', 'o', 'h', GeomFromText('POINT(206 120)')),
+('g', 'z', 's', GeomFromText('POINT(169 240)')),
+('z', 'u', 's', GeomFromText('POINT(202 120)')),
+('i', 'b', 'a', GeomFromText('POINT(216 18)')),
+('w', 'y', 'g', GeomFromText('POINT(119 236)')),
+('h', 'y', 'p', GeomFromText('POINT(161 24)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(33 100)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(41 46)') where c1 like 'f%';
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+create table t1 (a geometry not null, spatial index(a)) transactional=0 row_format=page;
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072)));
+insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0)));
+insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241)));
+insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231)));
+insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260)));
+insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125)));
+insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29)));
+insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86)));
+insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130)));
+insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34)));
+insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183)));
+insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178)));
+drop table t1;
+CREATE TABLE t1(foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=0 row_format=page;
+INSERT INTO t1(foo) VALUES (NULL);
+ERROR 23000: Column 'foo' cannot be null
+INSERT INTO t1() VALUES ();
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+INSERT INTO t1(foo) VALUES ('');
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+DROP TABLE t1;
+CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)) transactional=0 row_format=page;
+INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)'));
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b GEOMETRY NOT NULL, SPATIAL KEY b(b)) transactional=0 row_format=page;
+INSERT INTO t1 VALUES (1, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+INSERT INTO t1 VALUES (2, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+SELECT COUNT(*) FROM t1 WHERE
+MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+COUNT(*)
+2
+SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE
+MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+COUNT(*)
+2
+DROP TABLE t1;
+End of 5.0 tests.
diff --git a/mysql-test/suite/maria/r/maria-mvcc.result b/mysql-test/suite/maria/r/maria-mvcc.result
new file mode 100644
index 00000000000..3919dfc597e
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-mvcc.result
@@ -0,0 +1,172 @@
+set global maria_page_checksum=1;
+drop table if exists t1;
+create table t1 (i int) engine=maria;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+insert into t1 values (0);
+lock tables t1 write concurrent;
+insert into t1 values (1);
+insert into t1 values (2);
+/* should see 0, 1 and 2 */
+select i from t1;
+i
+0
+1
+2
+select count(*) from t1;
+count(*)
+3
+/* should see 0 */
+select i from t1;
+i
+0
+select count(*) from t1;
+count(*)
+1
+lock tables t1 write concurrent;
+insert into t1 values (3);
+insert into t1 values (4);
+/* should see 0, 3 and 4 */
+select i from t1;
+i
+0
+3
+4
+select count(*) from t1;
+count(*)
+3
+unlock tables;
+lock tables t1 write concurrent;
+insert into t1 values (5);
+/* should see 0, 3, 4 and 5 */
+select i from t1;
+i
+0
+3
+4
+5
+select count(*) from t1;
+count(*)
+4
+lock tables t1 write concurrent;
+/* should see 0, 3, 4 */
+select i from t1;
+i
+0
+3
+4
+select count(*) from t1;
+count(*)
+3
+insert into t1 values (6);
+/* Should see 0, 1, 2, 6 */
+select i from t1;
+i
+0
+1
+2
+6
+select count(*) from t1;
+count(*)
+4
+unlock tables;
+lock tables t1 write concurrent;
+/* Should see 0, 1, 2, 3, 4 and 6 */
+select i from t1;
+i
+0
+1
+2
+3
+4
+6
+select count(*) from t1;
+count(*)
+6
+/* should see 0, 3, 4, 5 */
+select i from t1;
+i
+0
+3
+4
+5
+select count(*) from t1;
+count(*)
+4
+unlock tables;
+/* should see 0, 1, 2, 3, 4, 5, 6 */
+select i from t1;
+i
+0
+1
+2
+3
+4
+5
+6
+select count(*) from t1;
+count(*)
+7
+unlock tables;
+/* should see 0, 1, 2, 3, 4, 5, 6 */
+select i from t1;
+i
+0
+1
+2
+3
+4
+5
+6
+select count(*) from t1;
+count(*)
+7
+insert into t1 values (7);
+/* should see 0, 3, 4, 7 */
+select i from t1;
+i
+0
+3
+4
+7
+select count(*) from t1;
+count(*)
+4
+unlock tables;
+/* should see 0, 1, 2, 3, 4, 5, 6, 7 */
+select i from t1;
+i
+0
+1
+2
+3
+4
+5
+6
+7
+select count(*) from t1;
+count(*)
+8
+drop table t1;
+CREATE TABLE t1 (fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, g GEOMETRY NOT NULL, SPATIAL KEY(g) ) transactional=1 row_format=page engine=maria;
+lock tables t1 write concurrent, t1 as t2 write concurrent;
+insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
+select fid from t1 as t2;
+fid
+1
+select count(*) from t1 as t2;
+count(*)
+1
+insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
+select fid from t1 as t2;
+fid
+1
+2
+select count(*) from t1 as t2;
+count(*)
+2
+unlock tables;
+drop table t1;
diff --git a/mysql-test/suite/maria/r/maria-no-logging.result b/mysql-test/suite/maria/r/maria-no-logging.result
new file mode 100644
index 00000000000..e72842ae71b
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-no-logging.result
@@ -0,0 +1,51 @@
+set global maria_log_file_size=4294967295;
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+set global maria_checkpoint_interval=0;
+create table t2 (a varchar(100)) engine=myisam;
+insert into t2 select repeat('z',100);
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+* shut down mysqld, removed logs, restarted it
+create table t1 (a varchar(100)) engine=maria transactional=1;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(100) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+show engine maria logs;
+Type Name Status
+MARIA Size 16384 maria_log.00000001 unknown
+insert into t1 values('a');
+insert into t1 select * from t2;
+show engine maria logs;
+Type Name Status
+MARIA Size 24576 maria_log.00000001 unknown
+* shut down mysqld, removed logs, restarted it
+truncate table t1;
+insert into t1 select * from t2;
+show engine maria logs;
+Type Name Status
+MARIA Size 16384 maria_log.00000001 unknown
+drop table t1;
+* shut down mysqld, removed logs, restarted it
+create table t1 (a varchar(100)) engine=maria transactional=1;
+insert into t1 values('a');
+create table if not exists t1 select * from t2;
+Warnings:
+Note 1050 Table 't1' already exists
+show engine maria logs;
+Type Name Status
+MARIA Size 24576 maria_log.00000001 unknown
+* shut down mysqld, removed logs, restarted it
+drop table t1;
+create table t1 engine=maria transactional=1 select * from t2;
+show engine maria logs;
+Type Name Status
+MARIA Size 16384 maria_log.00000001 unknown
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria-page-checksum.result b/mysql-test/suite/maria/r/maria-page-checksum.result
new file mode 100644
index 00000000000..0319bd9e9ca
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-page-checksum.result
@@ -0,0 +1,940 @@
+drop table if exists t1;
+select @@global.maria_page_checksum;
+@@global.maria_page_checksum
+1
+# iteration 1
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 2
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 3
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 4
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 5
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 6
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 7
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 8
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 9
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 10
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 11
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 12
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 13
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 14
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 15
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 16
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 17
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 18
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 19
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 20
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 21
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 22
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 23
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 24
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 25
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 26
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 27
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 28
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 29
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 30
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 31
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 32
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 33
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 34
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 35
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+Page checksums are not used
+drop table t1;
+# iteration 36
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Page checksums are used
+drop table t1;
+# iteration 1
+create table t1(a int) engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+alter table t1 modify a bigint ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(20) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+drop table t1;
+# iteration 2
+create table t1(a int) engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+alter table t1 transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 3
+create table t1(a int) engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+alter table t1 transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
+# iteration 4
+create table t1(a int) engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+alter table t1 engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+drop table t1;
+# iteration 5
+create table t1(a int) engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+alter table t1 engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 6
+create table t1(a int) engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+Crashsafe: yes
+alter table t1 engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
+# iteration 7
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+alter table t1 modify a bigint ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(20) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 8
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+alter table t1 transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 9
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+alter table t1 transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
+# iteration 10
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+alter table t1 engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 11
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+alter table t1 engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 12
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+alter table t1 engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
+# iteration 13
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+alter table t1 modify a bigint ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(20) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
+# iteration 14
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+alter table t1 transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 15
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+alter table t1 transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
+# iteration 16
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+alter table t1 engine=maria ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
+# iteration 17
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+alter table t1 engine=maria transactional=0 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=0
+Crashsafe: no
+drop table t1;
+# iteration 18
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+alter table t1 engine=maria transactional=1 ;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+Crashsafe: yes
+drop table t1;
diff --git a/mysql-test/suite/maria/r/maria-preload.result b/mysql-test/suite/maria/r/maria-preload.result
new file mode 100644
index 00000000000..1fa4222416b
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-preload.result
@@ -0,0 +1,163 @@
+drop table if exists t1, t2;
+set global maria_checkpoint_interval=0;
+create temporary table initial
+select variable_name,variable_value from
+information_schema.global_status where variable_name like "Maria_pagecache_reads";
+create table t1 (
+a int not null auto_increment,
+b char(16) not null,
+primary key (a),
+key (b)
+) engine=maria row_format=dynamic;
+create table t2(
+a int not null auto_increment,
+b char(16) not null,
+primary key (a),
+key (b)
+) engine=maria row_format=dynamic;
+insert into t1(b) values
+('test0'),
+('test1'),
+('test2'),
+('test3'),
+('test4'),
+('test5'),
+('test6'),
+('test7');
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+select count(*) from t1;
+count(*)
+33448
+select count(*) from t2;
+count(*)
+20672
+flush tables;
+flush status;
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 2
+select count(*) from t1 where b = 'test1';
+count(*)
+4181
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 9
+select count(*) from t1 where b = 'test1';
+count(*)
+4181
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 9
+flush tables;
+flush status;
+select @@preload_buffer_size;
+@@preload_buffer_size
+32768
+load index into cache t1;
+Table Op Msg_type Msg_text
+test.t1 preload_keys status OK
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 80
+select count(*) from t1 where b = 'test1';
+count(*)
+4181
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 80
+flush tables;
+flush status;
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 80
+set session preload_buffer_size=256*1024;
+select @@preload_buffer_size;
+@@preload_buffer_size
+262144
+load index into cache t1 ignore leaves;
+Table Op Msg_type Msg_text
+test.t1 preload_keys status OK
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 151
+select count(*) from t1 where b = 'test1';
+count(*)
+4181
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 157
+flush tables;
+flush status;
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 157
+set session preload_buffer_size=1*1024;
+select @@preload_buffer_size;
+@@preload_buffer_size
+1024
+load index into cache t1, t2 key (primary,b) ignore leaves;
+Table Op Msg_type Msg_text
+test.t1 preload_keys status OK
+test.t2 preload_keys status OK
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 271
+select count(*) from t1 where b = 'test1';
+count(*)
+4181
+select count(*) from t2 where b = 'test1';
+count(*)
+2584
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 274
+flush tables;
+flush status;
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 274
+load index into cache t3, t2 key (primary,b) ;
+Table Op Msg_type Msg_text
+test.t3 preload_keys Error Table 'test.t3' doesn't exist
+test.t3 preload_keys error Corrupt
+test.t2 preload_keys status OK
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 317
+flush tables;
+flush status;
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 317
+load index into cache t3 key (b), t2 key (c) ;
+Table Op Msg_type Msg_text
+test.t3 preload_keys Error Table 'test.t3' doesn't exist
+test.t3 preload_keys error Corrupt
+test.t2 preload_keys Error Key 'c' doesn't exist in table 't2'
+test.t2 preload_keys status Operation failed
+select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+variable_name g.variable_value-i.variable_value
+MARIA_PAGECACHE_READS 317
+drop table t1, t2;
+drop temporary table initial;
+show status like "key_read%";
+Variable_name Value
+Key_read_requests 0
+Key_reads 0
diff --git a/mysql-test/suite/maria/r/maria-purge.result b/mysql-test/suite/maria/r/maria-purge.result
new file mode 100644
index 00000000000..eb67bab8cde
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-purge.result
@@ -0,0 +1,93 @@
+* shut down mysqld, removed logs, restarted it
+set global storage_engine=maria;
+set session storage_engine=maria;
+set global maria_log_file_size=4294967295;
+drop table if exists t1,t2;
+SET SQL_WARNINGS=1;
+CREATE TABLE t1 (
+STRING_DATA char(255) default NULL
+);
+CREATE TABLE t2 (
+STRING_DATA char(255) default NULL
+);
+INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
+INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD');
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+set global maria_log_file_size=16777216;
+set global maria_checkpoint_interval=30;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000002 in use
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+set global maria_checkpoint_interval=30;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000004 in use
+set global maria_log_file_size=16777216;
+select @@global.maria_log_file_size;
+@@global.maria_log_file_size
+16777216
+set global maria_checkpoint_interval=30;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000004 in use
+set global maria_log_file_size=8388608;
+select @@global.maria_log_file_size;
+@@global.maria_log_file_size
+8388608
+set global maria_log_purge_type=at_flush;
+insert into t1 select * from t2;
+set global maria_checkpoint_interval=30;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000004 free
+MARIA maria_log.00000005 free
+MARIA maria_log.00000006 free
+MARIA maria_log.00000007 free
+MARIA maria_log.00000008 in use
+flush logs;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000008 in use
+set global maria_log_file_size=16777216;
+set global maria_log_purge_type=external;
+insert into t1 select * from t2;
+set global maria_checkpoint_interval=30;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000008 free
+MARIA maria_log.00000009 in use
+flush logs;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000008 free
+MARIA maria_log.00000009 in use
+set global maria_log_purge_type=immediate;
+insert into t1 select * from t2;
+set global maria_checkpoint_interval=30;
+SHOW ENGINE maria logs;
+Type Name Status
+MARIA maria_log.00000011 in use
+drop table t1, t2;
diff --git a/mysql-test/suite/maria/r/maria-recover.result b/mysql-test/suite/maria/r/maria-recover.result
new file mode 100644
index 00000000000..b4f5c21b26b
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recover.result
@@ -0,0 +1,38 @@
+call mtr.add_suppression("Checking table: '.\/mysqltest\/t_corrupted2'");
+call mtr.add_suppression("Recovering table: '.\/mysqltest\/t_corrupted2'");
+call mtr.add_suppression("Table '.\/mysqltest\/t_corrupted2' is marked as crashed and should be repaired");
+select @@global.maria_recover;
+@@global.maria_recover
+BACKUP
+set global maria_recover=off;
+select @@global.maria_recover;
+@@global.maria_recover
+OFF
+set global maria_recover=default;
+select @@global.maria_recover;
+@@global.maria_recover
+OFF
+set global maria_recover=normal;
+select @@global.maria_recover;
+@@global.maria_recover
+NORMAL
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+create table t1 (a varchar(1000), index(a)) engine=maria;
+insert into t1 values("ThursdayMorningsMarket");
+flush table t1;
+insert into t1 select concat(a,'b') from t1 limit 1;
+select * from t_corrupted2;
+a
+ThursdayMorningsMarket
+Warnings:
+Error 145 t_corrupted2' is marked as crashed and should be repaired
+Error 1194 t_corrupted2' is marked as crashed and should be repaired
+Error 1034 1 client is using or hasn't closed the table properly
+Error 1034 Wrong base information on indexpage at page: 1
+select * from t_corrupted2;
+a
+ThursdayMorningsMarket
+drop database mysqltest;
+set global maria_recover=backup;
diff --git a/mysql-test/suite/maria/r/maria-recovery-big.result b/mysql-test/suite/maria/r/maria-recovery-big.result
new file mode 100644
index 00000000000..ecc53de437e
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recovery-big.result
@@ -0,0 +1,79 @@
+set global maria_log_file_size=4294967295;
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+* TEST of recovery with blobs
+* shut down mysqld, removed logs, restarted it
+create table t1 (a int, b longtext) engine=maria table_checksum=1;
+* copied t1 for feeding_recovery
+insert into t1 values (1,"123456789012345678901234567890"),(2,"09876543210987654321");
+flush table t1;
+* copied t1 for comparison
+lock table t1 write;
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+update t1 set b=CONCAT(b,b);
+select a,length(b) from t1;
+a length(b)
+1 31457280
+2 20971520
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+update t1 set b=mid(b,1,length(b)/2);
+select a,length(b) from t1;
+a length(b)
+1 8
+2 5
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* copied t1 back for feeding_recovery
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop table t1;
+drop database mysqltest_for_feeding_recovery;
+drop database mysqltest_for_comparison;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria-recovery-bitmap.result b/mysql-test/suite/maria/r/maria-recovery-bitmap.result
new file mode 100644
index 00000000000..01255c2394f
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recovery-bitmap.result
@@ -0,0 +1,46 @@
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+* shut down mysqld, removed logs, restarted it
+create table t1 (a varchar(10000)) engine=maria;
+* TEST of over-allocated bitmap not flushed by checkpoint
+insert into t1 values ("bbbbbbb");
+flush table t1;
+* copied t1 for comparison
+insert into t1 values ("bbbbbbb");
+delete from t1 limit 1;
+set session debug="+d,info,enter,exit,maria_over_alloc_bitmap";
+insert into t1 values ("aaaaaaaaa");
+set global maria_checkpoint_interval=1;
+SET SESSION debug="+d,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+* TEST of bitmap flushed without REDO-UNDO in the log (WAL violation)
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values (REPEAT('a', 6000));
+SET SESSION debug="+d,maria_flush_bitmap,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop table t1;
+drop database mysqltest_for_comparison;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria-recovery-rtree-ft.result b/mysql-test/suite/maria/r/maria-recovery-rtree-ft.result
new file mode 100644
index 00000000000..b8b0daa0ad8
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recovery-rtree-ft.result
@@ -0,0 +1,161 @@
+set global maria_log_file_size=4294967295;
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+* shut down mysqld, removed logs, restarted it
+CREATE TABLE t1 (
+line LINESTRING NOT NULL,
+kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+name VARCHAR(32)
+,SPATIAL key (line)
+) transactional=1 row_format=page engine=maria;
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 line 1 line A NULL 32 NULL SPATIAL
+CREATE TABLE t2 (a VARCHAR(200), b TEXT, FULLTEXT (a,b)
+) transactional=1 row_format=page engine=maria;
+SHOW INDEX FROM t2;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t2 1 a 1 a NULL NULL NULL NULL YES FULLTEXT
+t2 1 a 2 b NULL NULL NULL NULL YES FULLTEXT
+* TEST of REDO: see if recovery can reconstruct if we give it an old table
+* copied t2 for feeding_recovery
+* copied t1 for feeding_recovery
+flush table t2;
+* copied t2 for comparison
+flush table t1;
+* copied t1 for comparison
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* copied t2 back for feeding_recovery
+* copied t1 back for feeding_recovery
+* recovery happens
+check table t2 extended;
+Table Op Msg_type Msg_text
+mysqltest.t2 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+* TEST of INSERT and DELETE's rollback
+flush table t2;
+* copied t2 for comparison
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write, t2 write;
+SET SESSION debug="+d,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t2 extended;
+Table Op Msg_type Msg_text
+mysqltest.t2 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+flush table t2;
+* copied t2 for comparison
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write, t2 write;
+SET SESSION debug="+d,maria_flush_whole_page_cache,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t2 extended;
+Table Op Msg_type Msg_text
+mysqltest.t2 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+flush table t2;
+* copied t2 for comparison
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write, t2 write;
+SET SESSION debug="+d,maria_flush_states,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t2 extended;
+Table Op Msg_type Msg_text
+mysqltest.t2 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+flush table t2;
+* copied t2 for comparison
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write, t2 write;
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t2 extended;
+Table Op Msg_type Msg_text
+mysqltest.t2 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t2 extended;
+Table Op Msg_type Msg_text
+mysqltest.t2 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop database mysqltest_for_feeding_recovery;
+drop database mysqltest_for_comparison;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria-recovery.result b/mysql-test/suite/maria/r/maria-recovery.result
new file mode 100644
index 00000000000..b0440489cd1
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recovery.result
@@ -0,0 +1,242 @@
+set global maria_log_file_size=4294967295;
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+* shut down mysqld, removed logs, restarted it
+create table t1 (a varchar(1000)) engine=maria;
+* TEST of REDO: see if recovery can reconstruct if we give it an old table
+* copied t1 for feeding_recovery
+insert into t1 values ("00000000");
+flush table t1;
+* copied t1 for comparison
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* copied t1 back for feeding_recovery
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+* compared t1 to old version
+use mysqltest;
+select * from t1;
+a
+00000000
+* TEST of REDO+UNDO: normal recovery test (no moving tables under its feet)
+insert into t1 values ("00000000");
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values ("aaaaaaaaa");
+SET SESSION debug="+d,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+select * from t1;
+a
+00000000
+00000000
+insert into t1 values ("00000000");
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values ("aaaaaaaaa");
+SET SESSION debug="+d,maria_flush_whole_page_cache,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+select * from t1;
+a
+00000000
+00000000
+00000000
+insert into t1 values ("00000000");
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values ("aaaaaaaaa");
+SET SESSION debug="+d,maria_flush_states,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+select * from t1;
+a
+00000000
+00000000
+00000000
+00000000
+insert into t1 values ("00000000");
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values ("aaaaaaaaa");
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+select * from t1;
+a
+00000000
+00000000
+00000000
+00000000
+00000000
+drop table t1;
+* TEST of two REDOs for same page in one REDO group
+* shut down mysqld, removed logs, restarted it
+CREATE TABLE t1 (
+i int,
+b blob default NULL,
+c varchar(6000) default NULL
+) ENGINE=MARIA CHECKSUM=1;
+* copied t1 for feeding_recovery
+INSERT INTO t1 VALUES (1, REPEAT('a', 5000), REPEAT('b', 5000));
+UPDATE t1 SET i=3, b=CONCAT(b,'c') WHERE i=1;
+SELECT LENGTH(b) FROM t1 WHERE i=3;
+LENGTH(b)
+5001
+flush table t1;
+* copied t1 for comparison
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* copied t1 back for feeding_recovery
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+SELECT LENGTH(b) FROM t1 WHERE i=3;
+LENGTH(b)
+5001
+drop table t1;
+* TEST of INSERT vs state.auto_increment
+* shut down mysqld, removed logs, restarted it
+CREATE TABLE t1 (
+i int auto_increment primary key,
+c varchar(6),
+key(c)
+) ENGINE=MARIA;
+insert into t1 values(null,"b");
+* copied t1 for feeding_recovery
+insert into t1 values(null,"a"), (null,"c"), (null,"d");
+delete from t1 where c="d";
+flush table t1;
+* copied t1 for comparison
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* copied t1 back for feeding_recovery
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) NOT NULL AUTO_INCREMENT,
+ `c` varchar(6) DEFAULT NULL,
+ PRIMARY KEY (`i`),
+ KEY `c` (`c`)
+) ENGINE=MARIA AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+* TEST of UPDATE vs state.auto_increment
+* copied t1 for feeding_recovery
+update t1 set i=15 where c="a";
+flush table t1;
+* copied t1 for comparison
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* copied t1 back for feeding_recovery
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) NOT NULL AUTO_INCREMENT,
+ `c` varchar(6) DEFAULT NULL,
+ PRIMARY KEY (`i`),
+ KEY `c` (`c`)
+) ENGINE=MARIA AUTO_INCREMENT=16 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+* TEST of INSERT's rollback vs state.auto_increment
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values(null, "e");
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `i` int(11) NOT NULL AUTO_INCREMENT,
+ `c` varchar(6) DEFAULT NULL,
+ PRIMARY KEY (`i`),
+ KEY `c` (`c`)
+) ENGINE=MARIA AUTO_INCREMENT=17 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+insert into t1 values(null, "f");
+drop table t1;
+drop database mysqltest_for_feeding_recovery;
+drop database mysqltest_for_comparison;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria-recovery2.result b/mysql-test/suite/maria/r/maria-recovery2.result
new file mode 100644
index 00000000000..88db518254f
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recovery2.result
@@ -0,0 +1,147 @@
+call mtr.add_suppression("File '.*maria_log.000.*' not found \\(Errcode: 2\\)");
+call mtr.add_suppression("Table '.\/mysqltest\/t_corrupted1' is crashed, skipping it. Please repair it with maria_chk -r");
+set global maria_log_file_size=4294967295;
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+* TEST of removing logs manually
+* shut down mysqld, removed logs, restarted it
+* TEST of UNDO_ROW_DELETE preserving rowid
+create table t1(a int) engine=maria;
+insert into t1 values(1),(2);
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values(3);
+delete from t1 where a in (1,2,3);
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop table t1;
+* TEST of checkpoint
+set global debug="+d,info,query,enter,exit,loop,maria_checkpoint_indirect";
+set global maria_checkpoint_interval=10000;
+create table t1(a int, b varchar(10), index(a,b)) engine=maria;
+insert into t1 values(1,"a"),(2,"b"),(3,"c");
+delete from t1 where b="b";
+update t1 set b="d" where a=1;
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values(4,"e"),(5,"f"),(6,"g");
+update t1 set b="h" where a=5;
+delete from t1 where b="g";
+show status like "Maria_pagecache_blocks_not_flushed";
+Variable_name Value
+Maria_pagecache_blocks_not_flushed 3
+set global maria_checkpoint_interval=10000;
+update t1 set b="i" where a=5;
+SET SESSION debug="+d,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop table t1;
+Test of REPAIR's implicit commit
+create table t1 (a varchar(100), key(a)) engine=maria;
+insert into t1 values(3);
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write;
+insert into t1 values (1);
+repair table t1;
+Table Op Msg_type Msg_text
+mysqltest.t1 repair status OK
+insert into t1 values(2);
+select * from t1;
+a
+1
+2
+3
+SET SESSION debug="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+failure
+use mysqltest;
+select * from t1;
+a
+1
+3
+drop table t1;
+* TEST of recovery when crash before bulk-insert-with-repair is committed
+create table t1 (a varchar(100), key(a)) engine=maria;
+create table t2 (a varchar(100)) engine=myisam;
+set rand_seed1=12, rand_seed2=254;
+insert into t2 values (rand());
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t1 values(30);
+flush table t1;
+* copied t1 for comparison
+lock tables t1 write, t2 read;
+delete from t1 limit 1;
+insert into t1 select * from t2;
+SET SESSION debug="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 1 NULL NULL YES BTREE
+drop table t1;
+* TEST of recovery when OPTIMIZE has replaced the index file and crash
+create table t_corrupted1 (a varchar(100), key(a)) engine=maria;
+insert into t_corrupted1 select (rand()) from t2;
+flush table t_corrupted1;
+* copied t_corrupted1 for comparison
+SET SESSION debug="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash_sort_index";
+* crashing mysqld intentionally
+optimize table t_corrupted1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t_corrupted1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t_corrupted1 check warning Table is marked as crashed and last repair failed
+mysqltest.t_corrupted1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop table t_corrupted1, t2;
+drop database mysqltest_for_comparison;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria-recovery3.result b/mysql-test/suite/maria/r/maria-recovery3.result
new file mode 100644
index 00000000000..118ec537901
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recovery3.result
@@ -0,0 +1,94 @@
+set global maria_log_file_size=4294967295;
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+* shut down mysqld, removed logs, restarted it
+* TEST of Checkpoint between writing the commit log record and committing in trnman
+create table t1(a int primary key) engine=maria;
+insert into t1 values(1);
+flush table t1;
+* copied t1 for comparison
+set session debug="+d,maria_sleep_in_commit";
+insert into t1 values(2);
+set global maria_checkpoint_interval=1000;
+delete from t1 where a=2;
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop table t1;
+* TEST of logging of BLOBs
+CREATE TABLE `t1` (
+`blob` blob,
+`blob_key` blob
+) ENGINE=maria ROW_FORMAT=page
+;
+* copied t1 for feeding_recovery
+* compared t1 to old version
+set global maria_checkpoint_interval=0;
+INSERT INTO `t1` VALUES (NULL,repeat('A',5198));
+INSERT INTO `t1` VALUES (NULL,repeat('B',65535));
+INSERT INTO `t1` VALUES (repeat('K',5198),repeat('L',2325));
+INSERT INTO `t1` VALUES (repeat('C',65535),NULL);
+INSERT INTO `t1` VALUES (NULL,repeat('D',65535));
+INSERT INTO `t1` VALUES (repeat('E',65535),repeat('F',16111));
+INSERT INTO `t1` VALUES (repeat('G',65535),repeat('H',65535));
+INSERT INTO `t1` VALUES (repeat('I',5198),repeat('J',65535));
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+flush table t1;
+* copied t1 for comparison
+* compared t1 to old version
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* copied t1 back for feeding_recovery
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+* compared t1 to old version
+use mysqltest;
+drop table t1;
+create table t1 engine=maria select 1;
+* copied t1 for feeding_recovery
+set global maria_checkpoint_interval=0;
+insert into t1 values(2);
+truncate table t1;
+flush table t1;
+* copied t1 for comparison
+truncate table t1;
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash_create_table";
+* crashing mysqld intentionally
+truncate table t1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check warning Size of indexfile is: 372 Should be: 8192
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+truncate table t1;
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+drop table t1;
+drop database mysqltest_for_feeding_recovery;
+drop database mysqltest_for_comparison;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/r/maria.result b/mysql-test/suite/maria/r/maria.result
new file mode 100644
index 00000000000..d36a222aea4
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria.result
@@ -0,0 +1,2597 @@
+select * from INFORMATION_SCHEMA.ENGINES where ENGINE="MARIA";
+ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
+MARIA YES Crash-safe tables with MyISAM heritage YES NO NO
+set global storage_engine=maria;
+set session storage_engine=maria;
+set global maria_page_checksum=0;
+set global maria_log_file_size=4294967295;
+drop table if exists t1,t2;
+drop view if exists v1;
+SET SQL_WARNINGS=1;
+CREATE TABLE t1 (
+STRING_DATA char(255) default NULL,
+KEY string_data (STRING_DATA)
+);
+INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
+INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD');
+INSERT INTO t1 VALUES ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
+INSERT INTO t1 VALUES ('FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG');
+INSERT INTO t1 VALUES ('HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH');
+INSERT INTO t1 VALUES ('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW');
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a));
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+repair table t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+delete from t1 where (a & 1);
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+repair table t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+flush table t1;
+repair table t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+drop table t1;
+create table t1 (a int not null auto_increment, b int not null, primary key (a), index(b));
+insert into t1 (b) values (1),(2),(2),(2),(2);
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 0 PRIMARY 1 a A 5 NULL NULL BTREE
+t1 1 b 1 b A 1 NULL NULL BTREE
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status Table is already up to date
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 0 PRIMARY 1 a A 5 NULL NULL BTREE
+t1 1 b 1 b A 1 NULL NULL BTREE
+drop table t1;
+create table t1 (a int not null, b int not null, c int not null, primary key (a),key(b));
+insert into t1 values (3,3,3),(1,1,1),(2,2,2),(4,4,4);
+explain select * from t1 order by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select * from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select * from t1 order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select a from t1 order by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 4 Using index
+explain select b from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 4 NULL 4 Using index
+explain select a,b from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using filesort
+explain select a,b from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4
+explain select a,b,c from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 4
+drop table t1;
+set autocommit=0;
+begin;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+LOCK TABLES t1 WRITE;
+INSERT INTO t1 VALUES (1), (2), (3);
+commit;
+set autocommit=1;
+UNLOCK TABLES;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+DROP TABLE t1;
+create table t1 ( t1 char(255), key(t1(250)));
+insert t1 values ('137513751375137513751375137513751375137569516951695169516951695169516951695169');
+insert t1 values ('178417841784178417841784178417841784178403420342034203420342034203420342034203');
+insert t1 values ('213872387238723872387238723872387238723867376737673767376737673767376737673767');
+insert t1 values ('242624262426242624262426242624262426242607890789078907890789078907890789078907');
+insert t1 values ('256025602560256025602560256025602560256011701170117011701170117011701170117011');
+insert t1 values ('276027602760276027602760276027602760276001610161016101610161016101610161016101');
+insert t1 values ('281528152815281528152815281528152815281564956495649564956495649564956495649564');
+insert t1 values ('292129212921292129212921292129212921292102100210021002100210021002100210021002');
+insert t1 values ('380638063806380638063806380638063806380634483448344834483448344834483448344834');
+insert t1 values ('411641164116411641164116411641164116411616301630163016301630163016301630163016');
+insert t1 values ('420842084208420842084208420842084208420899889988998899889988998899889988998899');
+insert t1 values ('438443844384438443844384438443844384438482448244824482448244824482448244824482');
+insert t1 values ('443244324432443244324432443244324432443239613961396139613961396139613961396139');
+insert t1 values ('485448544854485448544854485448544854485477847784778477847784778477847784778477');
+insert t1 values ('494549454945494549454945494549454945494555275527552755275527552755275527552755');
+insert t1 values ('538647864786478647864786478647864786478688918891889188918891889188918891889188');
+insert t1 values ('565556555655565556555655565556555655565554845484548454845484548454845484548454');
+insert t1 values ('607860786078607860786078607860786078607856665666566656665666566656665666566656');
+insert t1 values ('640164016401640164016401640164016401640141274127412741274127412741274127412741');
+insert t1 values ('719471947194719471947194719471947194719478717871787178717871787178717871787178');
+insert t1 values ('742574257425742574257425742574257425742549604960496049604960496049604960496049');
+insert t1 values ('887088708870887088708870887088708870887035963596359635963596359635963596359635');
+insert t1 values ('917791779177917791779177917791779177917773857385738573857385738573857385738573');
+insert t1 values ('933293329332933293329332933293329332933278987898789878987898789878987898789878');
+insert t1 values ('963896389638963896389638963896389638963877807780778077807780778077807780778077');
+delete from t1 where t1>'2';
+insert t1 values ('70'), ('84'), ('60'), ('20'), ('76'), ('89'), ('49'), ('50'),
+('88'), ('61'), ('42'), ('98'), ('39'), ('30'), ('25'), ('66'), ('61'), ('48'),
+('80'), ('84'), ('98'), ('19'), ('91'), ('42'), ('47');
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
+int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17
+int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
+int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
+i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
+int, i52 int, i53 int, i54 int, i55 int, i56 int, i57 int, i58 int, i59 int,
+i60 int, i61 int, i62 int, i63 int, i64 int, i65 int, i66 int, i67 int, i68
+int, i69 int, i70 int, i71 int, i72 int, i73 int, i74 int, i75 int, i76 int,
+i77 int, i78 int, i79 int, i80 int, i81 int, i82 int, i83 int, i84 int, i85
+int, i86 int, i87 int, i88 int, i89 int, i90 int, i91 int, i92 int, i93 int,
+i94 int, i95 int, i96 int, i97 int, i98 int, i99 int, i100 int, i101 int, i102
+int, i103 int, i104 int, i105 int, i106 int, i107 int, i108 int, i109 int, i110
+int, i111 int, i112 int, i113 int, i114 int, i115 int, i116 int, i117 int, i118
+int, i119 int, i120 int, i121 int, i122 int, i123 int, i124 int, i125 int, i126
+int, i127 int, i128 int, i129 int, i130 int, i131 int, i132 int, i133 int, i134
+int, i135 int, i136 int, i137 int, i138 int, i139 int, i140 int, i141 int, i142
+int, i143 int, i144 int, i145 int, i146 int, i147 int, i148 int, i149 int, i150
+int, i151 int, i152 int, i153 int, i154 int, i155 int, i156 int, i157 int, i158
+int, i159 int, i160 int, i161 int, i162 int, i163 int, i164 int, i165 int, i166
+int, i167 int, i168 int, i169 int, i170 int, i171 int, i172 int, i173 int, i174
+int, i175 int, i176 int, i177 int, i178 int, i179 int, i180 int, i181 int, i182
+int, i183 int, i184 int, i185 int, i186 int, i187 int, i188 int, i189 int, i190
+int, i191 int, i192 int, i193 int, i194 int, i195 int, i196 int, i197 int, i198
+int, i199 int, i200 int, i201 int, i202 int, i203 int, i204 int, i205 int, i206
+int, i207 int, i208 int, i209 int, i210 int, i211 int, i212 int, i213 int, i214
+int, i215 int, i216 int, i217 int, i218 int, i219 int, i220 int, i221 int, i222
+int, i223 int, i224 int, i225 int, i226 int, i227 int, i228 int, i229 int, i230
+int, i231 int, i232 int, i233 int, i234 int, i235 int, i236 int, i237 int, i238
+int, i239 int, i240 int, i241 int, i242 int, i243 int, i244 int, i245 int, i246
+int, i247 int, i248 int, i249 int, i250 int, i251 int, i252 int, i253 int, i254
+int, i255 int, i256 int, i257 int, i258 int, i259 int, i260 int, i261 int, i262
+int, i263 int, i264 int, i265 int, i266 int, i267 int, i268 int, i269 int, i270
+int, i271 int, i272 int, i273 int, i274 int, i275 int, i276 int, i277 int, i278
+int, i279 int, i280 int, i281 int, i282 int, i283 int, i284 int, i285 int, i286
+int, i287 int, i288 int, i289 int, i290 int, i291 int, i292 int, i293 int, i294
+int, i295 int, i296 int, i297 int, i298 int, i299 int, i300 int, i301 int, i302
+int, i303 int, i304 int, i305 int, i306 int, i307 int, i308 int, i309 int, i310
+int, i311 int, i312 int, i313 int, i314 int, i315 int, i316 int, i317 int, i318
+int, i319 int, i320 int, i321 int, i322 int, i323 int, i324 int, i325 int, i326
+int, i327 int, i328 int, i329 int, i330 int, i331 int, i332 int, i333 int, i334
+int, i335 int, i336 int, i337 int, i338 int, i339 int, i340 int, i341 int, i342
+int, i343 int, i344 int, i345 int, i346 int, i347 int, i348 int, i349 int, i350
+int, i351 int, i352 int, i353 int, i354 int, i355 int, i356 int, i357 int, i358
+int, i359 int, i360 int, i361 int, i362 int, i363 int, i364 int, i365 int, i366
+int, i367 int, i368 int, i369 int, i370 int, i371 int, i372 int, i373 int, i374
+int, i375 int, i376 int, i377 int, i378 int, i379 int, i380 int, i381 int, i382
+int, i383 int, i384 int, i385 int, i386 int, i387 int, i388 int, i389 int, i390
+int, i391 int, i392 int, i393 int, i394 int, i395 int, i396 int, i397 int, i398
+int, i399 int, i400 int, i401 int, i402 int, i403 int, i404 int, i405 int, i406
+int, i407 int, i408 int, i409 int, i410 int, i411 int, i412 int, i413 int, i414
+int, i415 int, i416 int, i417 int, i418 int, i419 int, i420 int, i421 int, i422
+int, i423 int, i424 int, i425 int, i426 int, i427 int, i428 int, i429 int, i430
+int, i431 int, i432 int, i433 int, i434 int, i435 int, i436 int, i437 int, i438
+int, i439 int, i440 int, i441 int, i442 int, i443 int, i444 int, i445 int, i446
+int, i447 int, i448 int, i449 int, i450 int, i451 int, i452 int, i453 int, i454
+int, i455 int, i456 int, i457 int, i458 int, i459 int, i460 int, i461 int, i462
+int, i463 int, i464 int, i465 int, i466 int, i467 int, i468 int, i469 int, i470
+int, i471 int, i472 int, i473 int, i474 int, i475 int, i476 int, i477 int, i478
+int, i479 int, i480 int, i481 int, i482 int, i483 int, i484 int, i485 int, i486
+int, i487 int, i488 int, i489 int, i490 int, i491 int, i492 int, i493 int, i494
+int, i495 int, i496 int, i497 int, i498 int, i499 int, i500 int, i501 int, i502
+int, i503 int, i504 int, i505 int, i506 int, i507 int, i508 int, i509 int, i510
+int, i511 int, i512 int, i513 int, i514 int, i515 int, i516 int, i517 int, i518
+int, i519 int, i520 int, i521 int, i522 int, i523 int, i524 int, i525 int, i526
+int, i527 int, i528 int, i529 int, i530 int, i531 int, i532 int, i533 int, i534
+int, i535 int, i536 int, i537 int, i538 int, i539 int, i540 int, i541 int, i542
+int, i543 int, i544 int, i545 int, i546 int, i547 int, i548 int, i549 int, i550
+int, i551 int, i552 int, i553 int, i554 int, i555 int, i556 int, i557 int, i558
+int, i559 int, i560 int, i561 int, i562 int, i563 int, i564 int, i565 int, i566
+int, i567 int, i568 int, i569 int, i570 int, i571 int, i572 int, i573 int, i574
+int, i575 int, i576 int, i577 int, i578 int, i579 int, i580 int, i581 int, i582
+int, i583 int, i584 int, i585 int, i586 int, i587 int, i588 int, i589 int, i590
+int, i591 int, i592 int, i593 int, i594 int, i595 int, i596 int, i597 int, i598
+int, i599 int, i600 int, i601 int, i602 int, i603 int, i604 int, i605 int, i606
+int, i607 int, i608 int, i609 int, i610 int, i611 int, i612 int, i613 int, i614
+int, i615 int, i616 int, i617 int, i618 int, i619 int, i620 int, i621 int, i622
+int, i623 int, i624 int, i625 int, i626 int, i627 int, i628 int, i629 int, i630
+int, i631 int, i632 int, i633 int, i634 int, i635 int, i636 int, i637 int, i638
+int, i639 int, i640 int, i641 int, i642 int, i643 int, i644 int, i645 int, i646
+int, i647 int, i648 int, i649 int, i650 int, i651 int, i652 int, i653 int, i654
+int, i655 int, i656 int, i657 int, i658 int, i659 int, i660 int, i661 int, i662
+int, i663 int, i664 int, i665 int, i666 int, i667 int, i668 int, i669 int, i670
+int, i671 int, i672 int, i673 int, i674 int, i675 int, i676 int, i677 int, i678
+int, i679 int, i680 int, i681 int, i682 int, i683 int, i684 int, i685 int, i686
+int, i687 int, i688 int, i689 int, i690 int, i691 int, i692 int, i693 int, i694
+int, i695 int, i696 int, i697 int, i698 int, i699 int, i700 int, i701 int, i702
+int, i703 int, i704 int, i705 int, i706 int, i707 int, i708 int, i709 int, i710
+int, i711 int, i712 int, i713 int, i714 int, i715 int, i716 int, i717 int, i718
+int, i719 int, i720 int, i721 int, i722 int, i723 int, i724 int, i725 int, i726
+int, i727 int, i728 int, i729 int, i730 int, i731 int, i732 int, i733 int, i734
+int, i735 int, i736 int, i737 int, i738 int, i739 int, i740 int, i741 int, i742
+int, i743 int, i744 int, i745 int, i746 int, i747 int, i748 int, i749 int, i750
+int, i751 int, i752 int, i753 int, i754 int, i755 int, i756 int, i757 int, i758
+int, i759 int, i760 int, i761 int, i762 int, i763 int, i764 int, i765 int, i766
+int, i767 int, i768 int, i769 int, i770 int, i771 int, i772 int, i773 int, i774
+int, i775 int, i776 int, i777 int, i778 int, i779 int, i780 int, i781 int, i782
+int, i783 int, i784 int, i785 int, i786 int, i787 int, i788 int, i789 int, i790
+int, i791 int, i792 int, i793 int, i794 int, i795 int, i796 int, i797 int, i798
+int, i799 int, i800 int, i801 int, i802 int, i803 int, i804 int, i805 int, i806
+int, i807 int, i808 int, i809 int, i810 int, i811 int, i812 int, i813 int, i814
+int, i815 int, i816 int, i817 int, i818 int, i819 int, i820 int, i821 int, i822
+int, i823 int, i824 int, i825 int, i826 int, i827 int, i828 int, i829 int, i830
+int, i831 int, i832 int, i833 int, i834 int, i835 int, i836 int, i837 int, i838
+int, i839 int, i840 int, i841 int, i842 int, i843 int, i844 int, i845 int, i846
+int, i847 int, i848 int, i849 int, i850 int, i851 int, i852 int, i853 int, i854
+int, i855 int, i856 int, i857 int, i858 int, i859 int, i860 int, i861 int, i862
+int, i863 int, i864 int, i865 int, i866 int, i867 int, i868 int, i869 int, i870
+int, i871 int, i872 int, i873 int, i874 int, i875 int, i876 int, i877 int, i878
+int, i879 int, i880 int, i881 int, i882 int, i883 int, i884 int, i885 int, i886
+int, i887 int, i888 int, i889 int, i890 int, i891 int, i892 int, i893 int, i894
+int, i895 int, i896 int, i897 int, i898 int, i899 int, i900 int, i901 int, i902
+int, i903 int, i904 int, i905 int, i906 int, i907 int, i908 int, i909 int, i910
+int, i911 int, i912 int, i913 int, i914 int, i915 int, i916 int, i917 int, i918
+int, i919 int, i920 int, i921 int, i922 int, i923 int, i924 int, i925 int, i926
+int, i927 int, i928 int, i929 int, i930 int, i931 int, i932 int, i933 int, i934
+int, i935 int, i936 int, i937 int, i938 int, i939 int, i940 int, i941 int, i942
+int, i943 int, i944 int, i945 int, i946 int, i947 int, i948 int, i949 int, i950
+int, i951 int, i952 int, i953 int, i954 int, i955 int, i956 int, i957 int, i958
+int, i959 int, i960 int, i961 int, i962 int, i963 int, i964 int, i965 int, i966
+int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
+int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
+int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
+int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
+int, i999 int, i1000 int, b blob) row_format=dynamic;
+insert into t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "Sergei");
+update t1 set b=repeat('a',256);
+update t1 set i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+delete from t1 where i8=1;
+select i1,i2 from t1;
+i1 i2
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+CREATE TABLE `t1` (
+`post_id` mediumint(8) unsigned NOT NULL auto_increment,
+`topic_id` mediumint(8) unsigned NOT NULL default '0',
+`post_time` datetime NOT NULL default '0000-00-00 00:00:00',
+`post_text` text NOT NULL,
+`icon_url` varchar(10) NOT NULL default '',
+`sign` tinyint(1) unsigned NOT NULL default '0',
+`post_edit` varchar(150) NOT NULL default '',
+`poster_login` varchar(35) NOT NULL default '',
+`ip` varchar(15) NOT NULL default '',
+PRIMARY KEY (`post_id`),
+KEY `post_time` (`post_time`),
+KEY `ip` (`ip`),
+KEY `poster_login` (`poster_login`),
+KEY `topic_id` (`topic_id`),
+FULLTEXT KEY `post_text` (`post_text`)
+) TRANSACTIONAL=0;
+INSERT INTO t1 (post_text) VALUES ('ceci est un test'),('ceci est un test'),('ceci est un test'),('ceci est un test'),('ceci est un test');
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255), KEY t1 (a, b, c, d, e));
+ERROR 42000: Specified key was too long; max key length is 1112 bytes
+CREATE TABLE t1 (a varchar(32000), unique key(a));
+ERROR 42000: Specified key was too long; max key length is 1112 bytes
+CREATE TABLE t1 (a varchar(1), b varchar(1), key (a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b));
+ERROR 42000: Too many key parts specified; max 16 parts allowed
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255));
+ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e);
+ERROR 42000: Specified key was too long; max key length is 1112 bytes
+DROP TABLE t1;
+CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a));
+INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4);
+create table t2 (a int not null, b int, c int, key(b), key(c), key(a));
+INSERT into t2 values (1,1,1), (2,2,2);
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 b 1 b A 5 NULL NULL YES BTREE
+t1 1 c 1 c A 5 NULL NULL YES BTREE
+t1 1 a 1 a A 1 NULL NULL BTREE
+t1 1 a 2 b A 5 NULL NULL YES BTREE
+t1 1 c_2 1 c A 5 NULL NULL YES BTREE
+t1 1 c_2 2 a A 5 NULL NULL BTREE
+explain select * from t1,t2 where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL a NULL NULL NULL 2
+1 SIMPLE t1 ref a a 4 test.t2.a 3
+explain select * from t1,t2 force index(a) where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL a NULL NULL NULL 2
+1 SIMPLE t1 ref a a 4 test.t2.a 3
+explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL a NULL NULL NULL 2
+1 SIMPLE t1 ref a a 4 test.t2.a 3
+explain select * from t1,t2 where t1.b=t2.b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL b NULL NULL NULL 2
+1 SIMPLE t1 ref b b 5 test.t2.b 1 Using where
+explain select * from t1,t2 force index(c) where t1.a=t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2
+1 SIMPLE t1 ref a a 4 test.t2.a 3
+explain select * from t1 where a=0 or a=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 4 NULL 4 Using where
+explain select * from t1 force index (a) where a=0 or a=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 4 NULL 4 Using where
+explain select * from t1 where c=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref c,c_2 c 5 const 1 Using where
+explain select * from t1 use index() where c=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
+drop table t1,t2;
+create table t1 (a int not null auto_increment primary key, b varchar(255));
+insert into t1 (b) values (repeat('a',100)),(repeat('b',100)),(repeat('c',100));
+update t1 set b=repeat(left(b,1),200) where a=1;
+delete from t1 where (a & 1)= 0;
+update t1 set b=repeat('e',200) where a=1;
+flush tables;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+update t1 set b=repeat(left(b,1),255) where a between 1 and 5;
+update t1 set b=repeat(left(b,1),10) where a between 32 and 43;
+update t1 set b=repeat(left(b,1),2) where a between 64 and 66;
+update t1 set b=repeat(left(b,1),65) where a between 67 and 70;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+insert into t1 (b) values (repeat('z',100));
+update t1 set b="test" where left(b,1) > 'n';
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 ( a text not null, key a (a(20)));
+insert into t1 values ('aaa '),('aaa'),('aa');
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+repair table t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+select concat(a,'.') from t1 where a='aaa';
+concat(a,'.')
+aaa .
+aaa.
+select concat(a,'.') from t1 where binary a='aaa';
+concat(a,'.')
+aaa.
+update t1 set a='bbb' where a='aaa';
+select concat(a,'.') from t1;
+concat(a,'.')
+bbb.
+bbb.
+aa.
+drop table t1;
+create table t1 ( a text not null, key a (a(20))) row_format=dynamic;
+insert into t1 values ('aaa '),('aaa'),('aa');
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+repair table t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+select concat(a,'.') from t1 where a='aaa';
+concat(a,'.')
+aaa .
+aaa.
+select concat(a,'.') from t1 where binary a='aaa';
+concat(a,'.')
+aaa.
+update t1 set a='bbb' where a='aaa';
+select concat(a,'.') from t1;
+concat(a,'.')
+bbb.
+bbb.
+aa.
+drop table t1;
+create table t1(a text not null, b text not null, c text not null, index (a(10),b(10),c(10)));
+insert into t1 values('807780', '477', '165');
+insert into t1 values('807780', '477', '162');
+insert into t1 values('807780', '472', '162');
+select * from t1 where a='807780' and b='477' and c='165';
+a b c
+807780 477 165
+drop table t1;
+CREATE TABLE t1 (a varchar(150) NOT NULL, KEY (a));
+INSERT t1 VALUES ("can \tcan");
+INSERT t1 VALUES ("can can");
+INSERT t1 VALUES ("can");
+SELECT * FROM t1;
+a
+can can
+can
+can can
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+create table t1 (a blob);
+insert into t1 values('a '),('a');
+select concat(a,'.') from t1 where a='a';
+concat(a,'.')
+a.
+select concat(a,'.') from t1 where a='a ';
+concat(a,'.')
+a .
+alter table t1 add key(a(2));
+select concat(a,'.') from t1 where a='a';
+concat(a,'.')
+a.
+select concat(a,'.') from t1 where a='a ';
+concat(a,'.')
+a .
+drop table t1;
+create table t1 (a int not null auto_increment primary key, b text not null, unique b (b(20)));
+insert into t1 (b) values ('a'),('b'),('c');
+select concat(b,'.') from t1;
+concat(b,'.')
+a.
+b.
+c.
+update t1 set b='b ' where a=2;
+update t1 set b='b ' where a > 1;
+ERROR 23000: Duplicate entry 'b ' for key 'b'
+insert into t1 (b) values ('b');
+ERROR 23000: Duplicate entry 'b' for key 'b'
+select * from t1;
+a b
+1 a
+2 b
+3 c
+delete from t1 where b='b';
+select a,concat(b,'.') from t1;
+a concat(b,'.')
+1 a.
+3 c.
+drop table t1;
+create table t1 (a int not null);
+create table t2 (a int not null, primary key (a));
+insert into t1 values (1);
+insert into t2 values (1),(2);
+select sql_big_result distinct t1.a from t1,t2 order by t2.a;
+a
+1
+select distinct t1.a from t1,t2 order by t2.a;
+a
+1
+select sql_big_result distinct t1.a from t1,t2;
+a
+1
+explain select sql_big_result distinct t1.a from t1,t2 order by t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary
+1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index; Distinct
+explain select distinct t1.a from t1,t2 order by t2.a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary
+1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index; Distinct
+drop table t1,t2;
+create table t1 (
+c1 varchar(32),
+key (c1)
+);
+alter table t1 disable keys;
+insert into t1 values ('a'), ('b');
+select c1 from t1 order by c1 limit 1;
+c1
+a
+drop table t1;
+create table t1 (a int not null, primary key(a)) ROW_FORMAT=FIXED;
+create table t2 (a int not null, b int not null, primary key(a,b)) ROW_FORMAT=FIXED;
+insert into t1 values (1),(2),(3),(4),(5),(6);
+insert into t2 values (1,1),(2,1);
+set autocommit=0;
+begin;
+lock tables t1 read local, t2 read local;
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+a a b
+1 1 1
+2 2 1
+insert into t2 values(2,0);
+commit;
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+a a b
+1 1 1
+2 2 1
+drop table t1,t2;
+set autocommit=1;
+CREATE TABLE t1 (c1 varchar(250) NOT NULL) ROW_FORMAT=DYNAMIC;
+CREATE TABLE t2 (c1 varchar(250) NOT NULL, PRIMARY KEY (c1)) ROW_FORMAT=DYNAMIC;
+INSERT INTO t1 VALUES ('test000001'), ('test000002'), ('test000003');
+INSERT INTO t2 VALUES ('test000002'), ('test000003'), ('test000004');
+LOCK TABLES t1 READ LOCAL, t2 READ LOCAL;
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+t1c1 t2c1
+INSERT INTO t2 VALUES ('test000001'), ('test000005');
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+t1c1 t2c1
+DROP TABLE t1,t2;
+CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`));
+Got one of the listed errors
+create table t1 (a int, b varchar(200), c text not null) checksum=1;
+create table t2 (a int, b varchar(200), c text not null) checksum=0;
+insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
+insert t2 select * from t1;
+checksum table t1, t2, t3 quick;
+Table Checksum
+test.t1 3442722830
+test.t2 NULL
+test.t3 NULL
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
+checksum table t1, t2, t3;
+Table Checksum
+test.t1 3442722830
+test.t2 3442722830
+test.t3 NULL
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
+checksum table t1, t2, t3 extended;
+Table Checksum
+test.t1 3442722830
+test.t2 3442722830
+test.t3 NULL
+Warnings:
+Error 1146 Table 'test.t3' doesn't exist
+drop table t1,t2;
+create table t1 (a int, key (a));
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A NULL NULL NULL YES BTREE
+alter table t1 disable keys;
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A NULL NULL NULL YES BTREE disabled
+create table t2 (a int);
+set @@rand_seed1=31415926,@@rand_seed2=2718281828;
+insert t1 select * from t2;
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A NULL NULL NULL YES BTREE disabled
+alter table t1 enable keys;
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 1000 NULL NULL YES BTREE
+alter table t1 engine=heap;
+alter table t1 disable keys;
+Warnings:
+Note 1031 Table storage engine for 't1' doesn't have this option
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a NULL 500 NULL NULL YES HASH
+drop table t1,t2;
+create table t1 ( a tinytext, b char(1), index idx (a(1),b) );
+insert into t1 values (null,''), (null,'');
+explain select count(*) from t1 where a is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref idx idx 4 const 1 Using where
+select count(*) from t1 where a is null;
+count(*)
+2
+drop table t1;
+create table t1 (c1 int, c2 varchar(4) not null default '',
+key(c2(3))) default charset=utf8;
+insert into t1 values (1,'A'), (2, 'B'), (3, 'A');
+update t1 set c2='A B' where c1=2;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (c1 int);
+insert into t1 values (1),(2),(3),(4);
+checksum table t1;
+Table Checksum
+test.t1 149057747
+delete from t1 where c1 = 1;
+create table t2 as select * from t1;
+checksum table t1;
+Table Checksum
+test.t1 984116287
+checksum table t2;
+Table Checksum
+test.t2 984116287
+drop table t1, t2;
+CREATE TABLE t1 (
+twenty int(4),
+hundred int(4) NOT NULL
+) CHECKSUM=1;
+INSERT INTO t1 VALUES (11,91);
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+checksum table t1;
+Table Checksum
+test.t1 3235292310
+checksum table t1 extended;
+Table Checksum
+test.t1 3235292310
+alter table t1 row_format=fixed;
+checksum table t1;
+Table Checksum
+test.t1 3235292310
+alter table t1 row_format=dynamic;
+checksum table t1;
+Table Checksum
+test.t1 4183529555
+alter table t1 engine=myisam;
+checksum table t1;
+Table Checksum
+test.t1 4183529555
+drop table t1;
+show variables like 'maria_stats_method';
+Variable_name Value
+maria_stats_method nulls_unequal
+create table t1 (a int, key(a));
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t1 select NULL from t1;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 10 NULL NULL YES BTREE
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 10 NULL NULL YES BTREE
+set maria_stats_method=nulls_equal;
+show variables like 'maria_stats_method';
+Variable_name Value
+maria_stats_method nulls_equal
+insert into t1 values (11);
+delete from t1 where a=11;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 5 NULL NULL YES BTREE
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 5 NULL NULL YES BTREE
+set maria_stats_method=DEFAULT;
+show variables like 'maria_stats_method';
+Variable_name Value
+maria_stats_method nulls_unequal
+insert into t1 values (11);
+delete from t1 where a=11;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 10 NULL NULL YES BTREE
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 10 NULL NULL YES BTREE
+drop table t1;
+set maria_stats_method=nulls_ignored;
+show variables like 'maria_stats_method';
+Variable_name Value
+maria_stats_method nulls_ignored
+create table t1 (
+a char(3), b char(4), c char(5), d char(6),
+key(a,b,c,d)
+);
+insert into t1 values ('bcd','def1', NULL, 'zz');
+insert into t1 values ('bcd','def2', NULL, 'zz');
+insert into t1 values ('bce','def1', 'yuu', NULL);
+insert into t1 values ('bce','def2', NULL, 'quux');
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 2 NULL NULL YES BTREE
+t1 1 a 2 b A 4 NULL NULL YES BTREE
+t1 1 a 3 c A 4 NULL NULL YES BTREE
+t1 1 a 4 d A 4 NULL NULL YES BTREE
+delete from t1;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 0 NULL NULL YES BTREE
+t1 1 a 2 b A 0 NULL NULL YES BTREE
+t1 1 a 3 c A 0 NULL NULL YES BTREE
+t1 1 a 4 d A 0 NULL NULL YES BTREE
+set maria_stats_method=DEFAULT;
+drop table t1;
+create table t1(
+cip INT NOT NULL,
+time TIME NOT NULL,
+score INT NOT NULL DEFAULT 0,
+bob TINYBLOB
+);
+insert into t1 (cip, time) VALUES (1, '00:01'), (2, '00:02'), (3,'00:03');
+insert into t1 (cip, bob, time) VALUES (4, 'a', '00:04'), (5, 'b', '00:05'),
+(6, 'c', '00:06');
+select * from t1 where bob is null and cip=1;
+cip time score bob
+1 00:01:00 0 NULL
+create index bug on t1 (bob(22), cip, time);
+select * from t1 where bob is null and cip=1;
+cip time score bob
+1 00:01:00 0 NULL
+drop table t1;
+create table t1 (
+id1 int not null auto_increment,
+id2 int not null default '0',
+t text not null,
+primary key (id1),
+key x (id2, t(32))
+) engine=maria;
+insert into t1 (id2, t) values
+(10, 'abc'), (10, 'abc'), (10, 'abc'),
+(20, 'abc'), (20, 'abc'), (20, 'def'),
+(10, 'abc'), (10, 'abc');
+select count(*) from t1 where id2 = 10;
+count(*)
+5
+select count(id1) from t1 where id2 = 10;
+count(id1)
+5
+drop table t1;
+CREATE TABLE t1(a TINYINT, KEY(a));
+INSERT INTO t1 VALUES(1);
+SELECT MAX(a) FROM t1 IGNORE INDEX(a);
+MAX(a)
+1
+ALTER TABLE t1 DISABLE KEYS;
+SELECT MAX(a) FROM t1;
+MAX(a)
+1
+SELECT MAX(a) FROM t1 IGNORE INDEX(a);
+MAX(a)
+1
+DROP TABLE t1;
+CREATE TABLE t1(a CHAR(9), b VARCHAR(7));
+INSERT INTO t1(a) VALUES('xxxxxxxxx'),('xxxxxxxxx');
+UPDATE t1 AS ta1,t1 AS ta2 SET ta1.b='aaaaaa',ta2.b='bbbbbb';
+SELECT * FROM t1;
+a b
+xxxxxxxxx bbbbbb
+xxxxxxxxx bbbbbb
+DROP TABLE t1;
+SET @@maria_repair_threads=2;
+SHOW VARIABLES LIKE 'maria_repair%';
+Variable_name Value
+maria_repair_threads 2
+CREATE TABLE t1 (
+`_id` int(11) NOT NULL default '0',
+`url` text,
+`email` text,
+`description` text,
+`loverlap` int(11) default NULL,
+`roverlap` int(11) default NULL,
+`lneighbor_id` int(11) default NULL,
+`rneighbor_id` int(11) default NULL,
+`length_` int(11) default NULL,
+`sequence` mediumtext,
+`name` text,
+`_obj_class` text NOT NULL,
+PRIMARY KEY (`_id`),
+UNIQUE KEY `sequence_name_index` (`name`(50)),
+KEY (`length_`)
+) DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES
+(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
+(2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
+(3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
+(4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
+(5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
+(6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
+(7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
+(8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
+(9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
+SELECT _id FROM t1;
+_id
+1
+2
+3
+4
+5
+6
+7
+8
+9
+DELETE FROM t1 WHERE _id < 8;
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 2 # # # # 0 # # # # # #
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 2 # # # # 0 # # # # # #
+SELECT _id FROM t1;
+_id
+8
+9
+DROP TABLE t1;
+CREATE TABLE t1 (
+`_id` int(11) NOT NULL default '0',
+`url` text,
+`email` text,
+`description` text,
+`loverlap` int(11) default NULL,
+`roverlap` int(11) default NULL,
+`lneighbor_id` int(11) default NULL,
+`rneighbor_id` int(11) default NULL,
+`length_` int(11) default NULL,
+`sequence` mediumtext,
+`name` text,
+`_obj_class` text NOT NULL,
+PRIMARY KEY (`_id`),
+UNIQUE KEY `sequence_name_index` (`name`(50)),
+KEY (`length_`)
+) DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES
+(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
+(2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
+(3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
+(4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
+(5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
+(6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
+(7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
+(8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
+(9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
+SELECT _id FROM t1;
+_id
+1
+2
+3
+4
+5
+6
+7
+8
+9
+DELETE FROM t1 WHERE _id < 8;
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 2 # # # # 0 # # # # # #
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+REPAIR TABLE t1 QUICK;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 2 # # # # 0 # # # # # #
+SELECT _id FROM t1;
+_id
+8
+9
+DROP TABLE t1;
+SET @@maria_repair_threads=1;
+SHOW VARIABLES LIKE 'maria_repair%';
+Variable_name Value
+maria_repair_threads 1
+drop table if exists t1,t2,t3;
+--- Testing varchar ---
+--- Testing varchar ---
+create table t1 (v varchar(10), c char(10), t text);
+insert into t1 values('+ ', '+ ', '+ ');
+set @a=repeat(' ',20);
+insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a));
+Warnings:
+Note 1265 Data truncated for column 'v' at row 1
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+ *+*+ *
+*+ *+*+ *
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+create table t2 like t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `v` varchar(10) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+create table t3 select * from t1;
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `v` varchar(10) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+alter table t1 modify c varchar(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) DEFAULT NULL,
+ `c` varchar(10) DEFAULT NULL,
+ `t` text
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+alter table t1 modify v char(10);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) DEFAULT NULL,
+ `c` varchar(10) DEFAULT NULL,
+ `t` text
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+alter table t1 modify t varchar(10);
+Warnings:
+Note 1265 Data truncated for column 't' at row 2
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) DEFAULT NULL,
+ `c` varchar(10) DEFAULT NULL,
+ `t` varchar(10) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+select concat('*',v,'*',c,'*',t,'*') from t1;
+concat('*',v,'*',c,'*',t,'*')
+*+*+*+ *
+*+*+*+ *
+drop table t1,t2,t3;
+create table t1 (v varchar(10), c char(10), t text, key(v), key(c), key(t(10)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text,
+ KEY `v` (`v`),
+ KEY `c` (`c`),
+ KEY `t` (`t`(10))
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+select count(*) from t1;
+count(*)
+270
+insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1)));
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where c='a';
+count(*)
+10
+select count(*) from t1 where t='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where c='a ';
+count(*)
+10
+select count(*) from t1 where t='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where c like 'a%';
+count(*)
+11
+select count(*) from t1 where t like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where; Using index
+explain select count(*) from t1 where c='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref c c 11 const # Using where; Using index
+explain select count(*) from t1 where t='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref t t 13 const # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 13 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 13 const # Using where; Using index
+alter table t1 add unique(v);
+ERROR 23000: Duplicate entry '{ ' for key 'v_2'
+alter table t1 add key(v);
+select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a';
+qq
+*a*a*a*
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+*a *a*a *
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v,v_2 # 13 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(c) from t1 group by v limit 10;
+v count(c)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(*) from t1 group by c limit 10;
+c count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result c,count(t) from t1 group by c limit 10;
+c count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(*) from t1 group by t limit 10;
+t count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result t,count(t) from t1 group by t limit 10;
+t count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(300), drop key v, drop key v_2, add key v (v);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where; Using index
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 303 NULL # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where; Using index
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where; Using index
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 303 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 drop key v, add key v (v(30));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(300) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`(30))
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+select count(*) from t1 where v='a';
+count(*)
+10
+select count(*) from t1 where v='a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ';
+count(*)
+10
+select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+count(*)
+10
+select count(*) from t1 where v like 'a%';
+count(*)
+11
+select count(*) from t1 where v like 'a %';
+count(*)
+9
+explain select count(*) from t1 where v='a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+explain select count(*) from t1 where v like 'a%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 33 NULL # Using where
+explain select count(*) from t1 where v between 'a' and 'a ';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+explain select * from t1 where v='a';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref v v 33 const # Using where
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+alter table t1 modify v varchar(600), drop key v, add key v (v);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(600) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text,
+ KEY `c` (`c`),
+ KEY `t` (`t`(10)),
+ KEY `v` (`v`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+select v,count(*) from t1 group by v limit 10;
+v count(*)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+select sql_big_result v,count(t) from t1 group by v limit 10;
+v count(t)
+a 1
+a 10
+b 10
+c 10
+d 10
+e 10
+f 10
+g 10
+h 10
+i 10
+drop table t1;
+create table t1 (a char(10), unique (a));
+insert into t1 values ('a ');
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a' for key 'a'
+alter table t1 modify a varchar(10);
+insert into t1 values ('a '),('a '),('a '),('a ');
+ERROR 23000: Duplicate entry 'a ' for key 'a'
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 'a'
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 'a'
+insert into t1 values ('a ');
+ERROR 23000: Duplicate entry 'a ' for key 'a'
+update t1 set a='a ' where a like 'a%';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='abc ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a %';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+update t1 set a='a ' where a like 'a ';
+select concat(a,'.') from t1;
+concat(a,'.')
+a .
+drop table t1;
+create table t1 (v varchar(10), c char(10), t text, key(v(5)), key(c(5)), key(t(5)));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `t` text,
+ KEY `v` (`v`(5)),
+ KEY `c` (`c`(5)),
+ KEY `t` (`t`(5))
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (v char(10) character set utf8);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` char(10) CHARACTER SET utf8 DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (v varchar(10), c char(10)) row_format=fixed;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` varchar(10) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=FIXED
+insert into t1 values('a','a'),('a ','a ');
+select concat('*',v,'*',c,'*') from t1;
+concat('*',v,'*',c,'*')
+*a*a*
+*a *a*
+drop table t1;
+create table t1 (v varchar(65530), key(v(10)));
+insert into t1 values(repeat('a',65530));
+select length(v) from t1 where v=repeat('a',65530);
+length(v)
+65530
+drop table t1;
+create table t1(a int, b varchar(12), key ba(b, a));
+insert into t1 values (1, 'A'), (20, NULL);
+explain select * from t1 where a=20 and b is null;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref ba ba 20 const,const 1 Using where; Using index
+select * from t1 where a=20 and b is null;
+a b
+20 NULL
+drop table t1;
+create table t1 (v varchar(65530), key(v));
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+drop table if exists t1;
+create table t1 (v varchar(65536));
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+Warnings:
+Note 1246 Converting column 'v' from VARCHAR to TEXT
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `v` mediumtext CHARACTER SET utf8
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (v varchar(65535));
+ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs
+set @save_concurrent_insert=@@concurrent_insert;
+set global concurrent_insert=1;
+create table t1 (a int) ROW_FORMAT=FIXED;
+insert into t1 values (1),(2),(3),(4),(5);
+lock table t1 read local;
+insert into t1 values(6),(7);
+unlock tables;
+delete from t1 where a>=3 and a<=4;
+lock table t1 read local;
+set global concurrent_insert=2;
+insert into t1 values (8),(9);
+unlock tables;
+insert into t1 values (10),(11),(12);
+select * from t1;
+a
+1
+2
+11
+10
+5
+6
+7
+8
+9
+12
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (a int, b varchar(30) default "hello") ROW_FORMAT=DYNAMIC;
+insert into t1 (a) values (1),(2),(3),(4),(5);
+lock table t1 read local;
+insert into t1 (a) values(6),(7);
+unlock tables;
+delete from t1 where a>=3 and a<=4;
+lock table t1 read local;
+set global concurrent_insert=2;
+insert into t1 (a) values (8),(9);
+unlock tables;
+insert into t1 (a) values (10),(11),(12);
+select a from t1;
+a
+1
+2
+11
+10
+5
+6
+7
+8
+9
+12
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+set global concurrent_insert=@save_concurrent_insert;
+create table t1 (a int, key(a));
+insert into t1 values (1),(2),(3),(4),(NULL),(NULL),(NULL),(NULL);
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Table is already up to date
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 8 NULL NULL YES BTREE
+alter table t1 disable keys;
+alter table t1 enable keys;
+show keys from t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
+t1 1 a 1 a A 8 NULL NULL YES BTREE
+drop table t1;
+show create table t1;
+show create table t1;
+create table t1 (a int) select 42 a;
+select * from t1;
+a
+9
+select * from t1;
+a
+99
+select * from t1;
+a
+42
+drop table t1;
+End of 4.1 tests
+create table t1 (c1 int) pack_keys=0;
+create table t2 (c1 int) pack_keys=1;
+create table t3 (c1 int) pack_keys=default;
+create table t4 (c1 int) pack_keys=2;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '2' at line 1
+drop table t1, t2, t3;
+CREATE TABLE t1(a INT, b INT, KEY inx (a), UNIQUE KEY uinx (b));
+INSERT INTO t1(a,b) VALUES (1,1),(2,2),(3,3),(4,4),(5,5);
+SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1;
+a
+1
+ALTER TABLE t1 DISABLE KEYS;
+SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1;
+a
+1
+SELECT a FROM t1 USE INDEX (inx) WHERE a=1;
+a
+1
+SELECT b FROM t1 FORCE INDEX (uinx) WHERE b=1;
+b
+1
+SELECT b FROM t1 USE INDEX (uinx) WHERE b=1;
+b
+1
+SELECT a FROM t1 FORCE INDEX (inx,uinx) WHERE a=1;
+a
+1
+ALTER TABLE t1 ENABLE KEYS;
+SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1;
+a
+1
+DROP TABLE t1;
+CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2));
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 0 # # # 8192 # # # # # # #
+INSERT INTO t1 VALUES (1,1);
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 1 # # # 24576 # # # # # # #
+ALTER TABLE t1 DISABLE KEYS;
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 1 # # # 24576 # # # # # # #
+ALTER TABLE t1 ENABLE KEYS;
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 1 # # # 24576 # # # # # # #
+ALTER TABLE t1 DISABLE KEYS;
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 1 # # # 24576 # # # # # # #
+ALTER TABLE t1 ENABLE KEYS;
+SHOW TABLE STATUS LIKE 't1';
+Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
+t1 MARIA 10 Page 1 # # # 24576 # # # # # # #
+# Enable keys with parallel repair
+SET @@maria_repair_threads=2;
+ALTER TABLE t1 DISABLE KEYS;
+ALTER TABLE t1 ENABLE KEYS;
+SET @@maria_repair_threads=1;
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (id int NOT NULL, ref int NOT NULL, INDEX (id));
+CREATE TABLE t2 LIKE t1;
+INSERT INTO t2 (id, ref) VALUES (1,3), (2,1), (3,2), (4,5), (4,4);
+INSERT INTO t1 SELECT * FROM t2;
+SELECT * FROM t1 AS a INNER JOIN t1 AS b USING (id) WHERE a.ref < b.ref;
+id ref ref
+4 4 5
+SELECT * FROM t1;
+id ref
+1 3
+2 1
+3 2
+4 5
+4 4
+DELETE FROM a USING t1 AS a INNER JOIN t1 AS b USING (id) WHERE a.ref < b.ref;
+SELECT * FROM t1;
+id ref
+1 3
+2 1
+3 2
+4 5
+DROP TABLE t1, t2;
+CREATE TABLE t1 (a INT) ENGINE=MARIA CHECKSUM=1 ROW_FORMAT=DYNAMIC;
+INSERT INTO t1 VALUES (0);
+UPDATE t1 SET a=1;
+SELECT a FROM t1;
+a
+1
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+INSERT INTO t1 VALUES (0), (5), (4), (2);
+UPDATE t1 SET a=2;
+SELECT a FROM t1;
+a
+2
+2
+2
+2
+2
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+End of 5.0 tests
+create table t1 (a int not null, key `a` (a) key_block_size=1024);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a int not null, key `a` (a) key_block_size=2048);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a varchar(2048), key `a` (a));
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`(1112))
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a varchar(2048), key `a` (a) key_block_size=1024);
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`(1112)) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a int not null, b varchar(2048), key (a), key(b)) key_block_size=1024;
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192,
+ KEY `b` (`b`(1112)) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 KEY_BLOCK_SIZE=1024
+alter table t1 key_block_size=2048;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192,
+ KEY `b` (`b`(1112)) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 KEY_BLOCK_SIZE=2048
+alter table t1 add c int, add key (c);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` varchar(2048) DEFAULT NULL,
+ `c` int(11) DEFAULT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192,
+ KEY `b` (`b`(1112)) KEY_BLOCK_SIZE=8192,
+ KEY `c` (`c`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 KEY_BLOCK_SIZE=2048
+alter table t1 key_block_size=0;
+alter table t1 add d int, add key (d);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` varchar(2048) DEFAULT NULL,
+ `c` int(11) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192,
+ KEY `b` (`b`(1112)) KEY_BLOCK_SIZE=8192,
+ KEY `c` (`c`) KEY_BLOCK_SIZE=8192,
+ KEY `d` (`d`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a int not null, b varchar(2048), key (a), key(b)) key_block_size=8192;
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`),
+ KEY `b` (`b`(1112))
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 KEY_BLOCK_SIZE=8192
+drop table t1;
+create table t1 (a int not null, b varchar(2048), key (a) key_block_size=1024, key(b)) key_block_size=8192;
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`),
+ KEY `b` (`b`(1112))
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 KEY_BLOCK_SIZE=8192
+drop table t1;
+create table t1 (a int not null, b int, key (a) key_block_size=1024, key(b) key_block_size=8192) key_block_size=16384;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192,
+ KEY `b` (`b`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 KEY_BLOCK_SIZE=16384
+drop table t1;
+create table t1 (a int not null, key `a` (a) key_block_size=512);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a varchar(2048), key `a` (a) key_block_size=1000000000000000000);
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`(1112)) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a int not null, key `a` (a) key_block_size=1025);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a int not null, key key_block_size=1024 (a));
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '=1024 (a))' at line 1
+create table t1 (a int not null, key `a` key_block_size=1024 (a));
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key_block_size=1024 (a))' at line 1
+CREATE TABLE t1 (
+c1 INT,
+c2 VARCHAR(300),
+KEY (c1) KEY_BLOCK_SIZE 1024,
+KEY (c2) KEY_BLOCK_SIZE 8192
+);
+INSERT INTO t1 VALUES (10, REPEAT('a', CEIL(RAND(10) * 300))),
+(11, REPEAT('b', CEIL(RAND() * 300))),
+(12, REPEAT('c', CEIL(RAND() * 300))),
+(13, REPEAT('d', CEIL(RAND() * 300))),
+(14, REPEAT('e', CEIL(RAND() * 300))),
+(15, REPEAT('f', CEIL(RAND() * 300))),
+(16, REPEAT('g', CEIL(RAND() * 300))),
+(17, REPEAT('h', CEIL(RAND() * 300))),
+(18, REPEAT('i', CEIL(RAND() * 300))),
+(19, REPEAT('j', CEIL(RAND() * 300))),
+(20, REPEAT('k', CEIL(RAND() * 300))),
+(21, REPEAT('l', CEIL(RAND() * 300))),
+(22, REPEAT('m', CEIL(RAND() * 300))),
+(23, REPEAT('n', CEIL(RAND() * 300))),
+(24, REPEAT('o', CEIL(RAND() * 300))),
+(25, REPEAT('p', CEIL(RAND() * 300))),
+(26, REPEAT('q', CEIL(RAND() * 300))),
+(27, REPEAT('r', CEIL(RAND() * 300))),
+(28, REPEAT('s', CEIL(RAND() * 300))),
+(29, REPEAT('t', CEIL(RAND() * 300))),
+(30, REPEAT('u', CEIL(RAND() * 300))),
+(31, REPEAT('v', CEIL(RAND() * 300))),
+(32, REPEAT('w', CEIL(RAND() * 300))),
+(33, REPEAT('x', CEIL(RAND() * 300))),
+(34, REPEAT('y', CEIL(RAND() * 300))),
+(35, REPEAT('z', CEIL(RAND() * 300)));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+DELETE FROM t1 WHERE c1 >= 10;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(130),
+c2 VARCHAR(1)
+) ENGINE=maria;
+INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(130),
+c2 VARCHAR(1)
+) ENGINE=maria;
+INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(130),
+c2 VARCHAR(1)
+) ENGINE=maria;
+INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
+INSERT INTO t1 VALUES('b', 'b');
+INSERT INTO t1 VALUES('c', 'b');
+DELETE FROM t1 WHERE c1='b';
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+2
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+2
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(130),
+c2 VARCHAR(1),
+KEY (c1)
+) ENGINE=maria;
+# Insert 100 rows. Query log disabled.
+UPDATE t1 SET c1=REPEAT("a",128) LIMIT 90;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+100
+ALTER TABLE t1 ENGINE=maria;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+100
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(50),
+c2 VARCHAR(1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(50),
+c2 VARCHAR(1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(50),
+c2 VARCHAR(1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
+INSERT INTO t1 VALUES('b', 'b');
+INSERT INTO t1 VALUES('c', 'b');
+DELETE FROM t1 WHERE c1='b';
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+2
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+2
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 CHAR(50),
+c2 VARCHAR(1),
+KEY (c1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+# Insert 100 rows. Query log disabled.
+UPDATE t1 SET c1=REPEAT(_utf8 x'e0ae85',43) LIMIT 90;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+100
+ALTER TABLE t1 ENGINE=maria;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+100
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 VARCHAR(10) NOT NULL,
+c2 CHAR(10) DEFAULT NULL,
+c3 VARCHAR(10) NOT NULL,
+KEY (c1),
+KEY (c2)
+) ENGINE=maria DEFAULT CHARSET=utf8 PACK_KEYS=0;
+MARIA file: MYSQLD_DATADIR/test/t1
+Record format: Block
+Crashsafe: yes
+Character set: utf8_general_ci (33)
+Data records: 0 Deleted blocks: 0
+Block_size: 8192
+Recordlength: 99
+
+table description:
+Key Start Len Index Type
+1 2 30 multip. varchar
+2 33 30 multip. char NULL
+DROP TABLE t1;
+create table t1 (n int not null, c char(1)) transactional=1;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `n` int(11) NOT NULL,
+ `c` char(1) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 TRANSACTIONAL=1
+drop table t1;
+CREATE TABLE t1 (line LINESTRING NOT NULL) engine=maria;
+INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t1;
+Table Checksum
+test.t1 326284887
+CREATE TABLE t2 (line LINESTRING NOT NULL) engine=maria;
+INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t2;
+Table Checksum
+test.t2 326284887
+CREATE TABLE t3 select * from t1;
+checksum table t3;
+Table Checksum
+test.t3 326284887
+drop table t1,t2,t3;
+End of 5.1 tests
+create table t2(a varchar(255),key(a))engine=maria row_format=dynamic transactional=0;
+insert into t2 values (repeat('o',124)), (repeat('h',226)), (repeat('i',236)),
+(repeat('l',234)), (repeat('b',13)), (repeat('g',236)), (repeat('y',205)),
+(repeat('c',99)), (repeat('g',145)), (repeat('o',131)), (repeat('e',63)),
+(repeat('q',155)), (repeat('k',87)), (repeat('i',54)), (repeat('p',84)),
+(repeat('m',119)), (repeat('c',2)), (repeat('a',174)), (repeat('g',160)),
+(repeat('t',147)), (repeat('n',107));
+insert into t2 values ('nupdjlafwfvuuvruxkyjxpmupihzgspkaybijztkeukgzzkrxmd');
+insert into t2 values (repeat('g',40)), (repeat('i',173)), (repeat('q',126)),
+(repeat('i',217)), (repeat('f',161)), (repeat('i',28)), (repeat('a',35)),
+(repeat('y',27)), (repeat('o',100)), (repeat('o',175)), (repeat('f',69)),
+(repeat('k',156)), (repeat('n',220)), (repeat('q',247)), (repeat('y',180)),
+(repeat('v',209)), (repeat('m',169)), (repeat('y',170)), (repeat('r',151)),
+(repeat('d',38)), (repeat('g',64)), (repeat('k',77)), (repeat('l',150)),
+(repeat('s',150)), (repeat('u',127)), (repeat('l',15)), (repeat('m',33)),
+(repeat('r',177)), (repeat('v',197)), (repeat('k',62)), (repeat('h',219)),
+(repeat('u',161)), (repeat('y',118)), (repeat('i',184)), (repeat('z',202)),
+(repeat('j',113)), (repeat('q',95)), (repeat('q',164)), (repeat('e',54)),
+(repeat('e',60)), (repeat('l',203)), (repeat('g',77)), (repeat('y',44)),
+(repeat('j',196)), (repeat('t',45)), (repeat('l',190)), (repeat('l',89)),
+(repeat('q',45)), (repeat('e',191)), (repeat('t',38)), (repeat('f',148)),
+(repeat('c',25)), (repeat('v',97)), (repeat('i',83)), (repeat('s',166)),
+(repeat('d',96)), (repeat('v',82)), (repeat('n',127)), (repeat('i',201)),
+(repeat('x',184)), (repeat('d',76)), (repeat('u',17)), (repeat('a',178));
+insert into t2 values ('hwvfiavnmufgbulapzrolonwxufheqymvjncnczlzcjokzqlsvmomcjzgzwzquyxpunxdmotdczocwliaprpubwaeccsulvittgizcutxxb');
+insert into t2 values (repeat('x',28)), (repeat('p',21)), (repeat('k',241)),
+(repeat('i',243)), (repeat('b',172)), (repeat('z',94)), (repeat('i',218)),
+(repeat('a',177)), (repeat('g',251)), (repeat('q',161)), (repeat('x',231)),
+(repeat('p',51)), (repeat('f',141)), (repeat('m',28)), (repeat('r',77)),
+(repeat('h',56)), (repeat('k',23)), (repeat('f',198)), (repeat('o',243)),
+(repeat('d',160)), (repeat('h',82));
+check table t2 extended;
+Table Op Msg_type Msg_text
+test.t2 check status OK
+drop table t2;
+CREATE TABLE t1 (
+col0 float DEFAULT NULL,
+col1 date DEFAULT NULL,
+col2 double DEFAULT NULL,
+col3 decimal(10,0) DEFAULT NULL,
+col4 char(218) DEFAULT NULL,
+col5 year(4) DEFAULT NULL,
+col6 datetime DEFAULT NULL,
+col7 varchar(39) DEFAULT NULL,
+col8 double DEFAULT NULL,
+col9 decimal(10,0) DEFAULT NULL,
+col10 enum('test1','test2','test3') DEFAULT NULL,
+col11 year(4) DEFAULT NULL,
+col12 tinytext,
+col13 tinyblob,
+col14 date DEFAULT NULL,
+col15 smallint(6) DEFAULT NULL,
+col16 varchar(81) DEFAULT NULL,
+col17 tinytext,
+col18 blob,
+col19 double DEFAULT NULL,
+col20 double DEFAULT NULL,
+col21 varchar(216) DEFAULT NULL,
+col22 enum('test1','test2','test3') DEFAULT NULL,
+col23 decimal(10,0) DEFAULT NULL,
+col24 text,
+col25 varchar(118) DEFAULT NULL,
+col26 tinytext,
+col27 tinyblob,
+col28 double DEFAULT NULL,
+col29 tinyint(4) DEFAULT NULL,
+col30 longtext,
+col31 tinyint(1) DEFAULT NULL,
+col32 char(212) DEFAULT NULL,
+col33 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+col34 year(4) DEFAULT NULL,
+col35 tinyint(1) DEFAULT NULL,
+col36 enum('test1','test2','test3') DEFAULT NULL,
+col37 decimal(10,0) DEFAULT NULL,
+col38 tinyint(4) DEFAULT NULL,
+col39 double DEFAULT NULL,
+col40 decimal(10,0) DEFAULT NULL,
+col41 enum('test1','test2','test3') DEFAULT NULL,
+col42 longblob,
+col43 text,
+col44 blob,
+col45 year(4) DEFAULT NULL,
+col46 longtext,
+col47 int(11) DEFAULT NULL,
+col48 set('test1','test2','test3') DEFAULT NULL,
+col49 bigint(20) DEFAULT NULL,
+col50 date DEFAULT NULL,
+col51 tinyblob,
+col52 float DEFAULT NULL,
+col53 year(4) DEFAULT NULL,
+col54 decimal(10,0) DEFAULT NULL,
+col55 tinyblob,
+col56 float DEFAULT NULL,
+col57 bigint(20) DEFAULT NULL,
+col58 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+col59 enum('test1','test2','test3') DEFAULT NULL,
+col60 bigint(20) DEFAULT NULL,
+col61 year(4) DEFAULT NULL,
+col62 year(4) DEFAULT NULL,
+col63 double DEFAULT NULL,
+col64 tinytext,
+col65 tinyint(4) DEFAULT NULL,
+col66 longtext,
+col67 time DEFAULT NULL,
+col68 bigint(20) DEFAULT NULL,
+col69 char(142) DEFAULT NULL,
+col70 longtext,
+col71 time DEFAULT NULL,
+col72 year(4) DEFAULT NULL,
+col73 longblob,
+col74 enum('test1','test2','test3') DEFAULT NULL,
+col75 decimal(10,0) DEFAULT NULL,
+col76 smallint(6) DEFAULT NULL,
+col77 tinytext,
+col78 date DEFAULT NULL,
+col79 double DEFAULT NULL,
+col80 tinyint(4) DEFAULT NULL,
+col81 float DEFAULT NULL,
+col82 bigint(20) DEFAULT NULL,
+col83 double DEFAULT NULL,
+col84 varchar(124) DEFAULT NULL,
+col85 double DEFAULT NULL,
+col86 tinyblob,
+col87 tinyblob,
+col88 double DEFAULT NULL,
+col89 date DEFAULT NULL,
+col90 decimal(10,0) DEFAULT NULL,
+col91 set('test1','test2','test3') DEFAULT NULL,
+col92 blob,
+col93 char(174) DEFAULT NULL,
+col94 double DEFAULT NULL,
+col95 tinytext,
+col96 decimal(10,0) DEFAULT NULL,
+col97 year(4) DEFAULT NULL,
+col98 tinyblob,
+col99 datetime DEFAULT NULL,
+col100 longblob,
+col101 date DEFAULT NULL,
+col102 float DEFAULT NULL,
+col103 float DEFAULT NULL,
+col104 int(11) DEFAULT NULL,
+col105 longblob,
+col106 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+col107 float DEFAULT NULL,
+col108 text,
+col109 float DEFAULT NULL,
+col110 decimal(10,0) DEFAULT NULL,
+col111 double DEFAULT NULL,
+col112 double DEFAULT NULL,
+col113 blob,
+col114 varchar(152) DEFAULT NULL,
+col115 bigint(20) DEFAULT NULL,
+col116 decimal(10,0) DEFAULT NULL,
+col117 mediumint(9) DEFAULT NULL,
+col118 tinytext,
+col119 tinyblob,
+col120 int(11) DEFAULT NULL,
+col121 bigint(20) DEFAULT NULL,
+col122 double DEFAULT NULL,
+col123 date DEFAULT NULL,
+col124 longtext,
+col125 longtext,
+col126 double DEFAULT NULL,
+col127 varchar(84) DEFAULT NULL,
+col128 text,
+col129 double DEFAULT NULL,
+col130 enum('test1','test2','test3') DEFAULT NULL,
+col131 time DEFAULT NULL,
+col132 year(4) DEFAULT NULL,
+col133 blob,
+col134 tinytext,
+col135 double DEFAULT NULL,
+col136 tinytext,
+col137 bigint(20) DEFAULT NULL,
+col138 datetime DEFAULT NULL,
+col139 double DEFAULT NULL,
+col140 decimal(10,0) DEFAULT NULL,
+col141 longtext,
+col142 tinyint(1) DEFAULT NULL,
+col143 time DEFAULT NULL,
+col144 time DEFAULT NULL,
+col145 float DEFAULT NULL,
+col146 longblob,
+col147 float DEFAULT NULL,
+col148 text,
+col149 mediumint(9) DEFAULT NULL,
+col150 tinyblob,
+col151 tinyblob,
+col152 tinytext,
+col153 tinyblob,
+col154 tinyblob,
+col155 tinytext,
+col156 tinyint(1) DEFAULT NULL,
+col157 tinytext,
+col158 time DEFAULT NULL,
+col159 date DEFAULT NULL,
+col160 longtext,
+col161 enum('test1','test2','test3') DEFAULT NULL,
+col162 text,
+col163 decimal(10,0) DEFAULT NULL,
+col164 time DEFAULT NULL,
+col165 longblob,
+col166 tinyint(4) DEFAULT NULL,
+col167 bigint(20) DEFAULT NULL,
+col168 decimal(10,0) DEFAULT NULL,
+col169 smallint(6) DEFAULT NULL,
+col170 tinytext,
+col171 tinyint(4) DEFAULT NULL,
+col172 tinyint(1) DEFAULT NULL,
+col173 tinytext,
+col174 decimal(10,0) DEFAULT NULL,
+col175 double DEFAULT NULL
+) engine=maria;
+insert ignore into t1 set
+col10=abs(28449) % 2,
+col11='1973',
+col12=if(abs(-30039)%100<20,null,'forgery\'s'),
+col13=if(abs(24672)%100<20,null,'adductor\'s'),
+col16=if(abs(26872)%100<20,null,'0xf810e016ee0b78e1ce8b1c6cf8d2e82bf8507453768a3908dc20cecfc9a0ac0ac00079d0645a4c'),
+col18=if(abs(-15854)%100<20,null,'unattractiveness'),
+col19=if(abs(4287439673.9896235000)%100<20,null,25288),
+col20=if(abs(4290800136.7527390000)%100<20,null,8887),
+col21=if(abs(-26086)%100<20,null,'0x2334181c6068aab18b348ecc1e2600b81e1c5f821eee3e204824'),
+col22=abs(-21921) % 2,
+col23=if(abs(1503277.6900540178)%100<20,null,-23298),
+col25=if(abs(29674)%100<20,null,'0xc8d094f888ee20c83baef8d9380a168d40f4906e742a4dc0daeacb809e64095c71d510c7c0f83a6a0a04b8d6a0d9bea2dc3d4bd44d9c5002e440707c40ead8b3eb20a100a8524b1616a338a440ea02a25a08041810a08cac087cd47b4a79f08730946c5800600ae45e1c08f637'),
+col26=if(abs(28642)%100<20,null,'insubstantiality\'s'),
+col27=if(abs(-3188)%100<20,null,'exine\'s'),
+col29=if(abs(-47)%100<20,null,-24131),
+col32=if(abs(-3658)%100<20,null,'shortener\'s'),
+col34='1917',
+col36=abs(27782) % 2,
+col37=if(abs(4864972.0244758446)%100<20,null,32302),
+col38=if(abs(97)%100<20,null,-14079),
+col39=if(abs(3362872.0521256141)%100<20,null,27191),
+col40=if(abs(3348292.2110660113)%100<20,null,-1163),
+col41=abs(-18533) % 2,
+col42=if(abs(2094)%100<20,null,'Montparnasse'),
+col43=if(abs(-15983)%100<20,null,'Massasoit\'s'),
+col44=if(abs(2497)%100<20,null,'lags'),
+col45='2057',
+col46=if(abs(-31691)%100<20,null,'miscegenation\'s'),
+col47=if(abs(-1269564297)%100<20,null,1089),
+col49=if(abs(-1815717335)%100<20,null,-17504),
+col51=if(abs(-15263)%100<20,null,'virelay'),
+col52=if(abs(2227333.3279519030)%100<20,null,-5210),
+col53='2032',
+col54=if(abs(791647.5947447127)%100<20,null,32576),
+col55=if(abs(20293)%100<20,null,'tumblebug'),
+col56=if(abs(4288698564.2967925000)%100<20,null,17141),
+col57=if(abs(-2138460927)%100<20,null,14495),
+col59=abs(7624) % 2,
+col60=if(abs(-1500892492)%100<20,null,-68),
+col63=if(abs(4290890487.3789482000)%100<20,null,-32129),
+col65=if(abs(22)%100<20,null,15722),
+col79=if(abs(4292420489.2606282000)%100<20,null,-23891),
+col84=if(abs(-21248)%100<20,null,'0x4f9888d044435050eab83cb3dcad88b01886e434e216'),
+col85=if(abs(4294260188.6230965000)%100<20,null,16867),
+col86=if(abs(-11659)%100<20,null,'prewar'),
+col87=if(abs(-2253)%100<20,null,'Radnorshire'),
+col90=if(abs(4287254529.4026613000)%100<20,null,23506),
+col92=if(abs(6472)%100<20,null,'electroplated'),
+col93=if(abs(-13523)%100<20,null,'sparkiest'),
+col95=if(abs(23998)%100<20,null,'Crimea'),
+col96=if(abs(4287719060.2789087000)%100<20,null,20527),
+col98=if(abs(-14090)%100<20,null,'firebrat'),
+col99='19161023095430',
+col100=if(abs(-31178)%100<20,null,'clinical'),
+col102=if(abs(4407547.5205542166)%100<20,null,18226),
+col103=if(abs(4286834687.5994444000)%100<20,null,27520),
+col104=if(abs(-2105663477)%100<20,null,28591),
+col105=if(abs(1929)%100<20,null,'renascent'),
+col107=if(abs(5972348.8099917602)%100<20,null,-11408),
+col108=if(abs(-11262)%100<20,null,'aircraftmen'),
+col110=if(abs(6530491.4546037167)%100<20,null,-17672),
+col111=if(abs(4289897795.5000763000)%100<20,null,3742),
+col112=if(abs(1680557.8560441907)%100<20,null,13944),
+col113=if(abs(-27195)%100<20,null,'dekameter'),
+col115=if(abs(-2083419827)%100<20,null,-17272),
+col117=if(abs(1704826)%100<20,null,17880),
+col118=if(abs(-2848)%100<20,null,'judicatory'),
+col119=if(abs(-28087)%100<20,null,'mistitles'),
+col120=if(abs(-2100119097)%100<20,null,22465),
+col121=if(abs(-1868777891)%100<20,null,15172),
+col122=if(abs(7039857.3608508557)%100<20,null,-22154),
+col125=if(abs(70)%100<20,null,'Hong\'s'),
+col126=if(abs(3820673.5968199712)%100<20,null,-24185),
+col127=if(abs(12331)%100<20,null,'0x674e14584e88fca3fed0a0b1488a440008228aa01454a65cf09e3f0fa0511c3ce2f8688450'),
+col128=if(abs(20335)%100<20,null,'Zoroaster\'s'),
+col129=if(abs(3916577.6225165562)%100<20,null,-4088),
+col130=abs(-15003) % 2,
+col132='2016',
+col134=if(abs(-26555)%100<20,null,'Caesarea'),
+col135=if(abs(4288484655.2416148000)%100<20,null,-30073),
+col136=if(abs(-17577)%100<20,null,'upbraid'),
+col137=if(abs(-1742797945)%100<20,null,-21651),
+col138='20751113181230',
+col139=if(abs(4288997063.9889216000)%100<20,null,1816),
+col141=if(abs(-31448)%100<20,null,'threnodist'),
+col142=if(abs(88)%100<20,null,-19748),
+col143='6930607',
+col144='5760250',
+col145=if(abs(3591496.9625843074)%100<20,null,76),
+col146=if(abs(20875)%100<20,null,'rename'),
+col147=if(abs(4294789439.6773582000)%100<20,null,32314),
+col148=if(abs(7072)%100<20,null,'recesses'),
+col150=if(abs(-26540)%100<20,null,'cuckoo'),
+col152=if(abs(23553)%100<20,null,'shortened'),
+col153=if(abs(-30422)%100<20,null,'inhabitant'),
+col154=if(abs(30457)%100<20,null,'Orwellian'),
+col155=if(abs(-30263)%100<20,null,'Ptolemies'),
+col156=if(abs(-41)%100<20,null,6382),
+col157=if(abs(2557)%100<20,null,'horsewhips'),
+col158='2764427',
+col160=if(abs(-15872)%100<20,null,'girlhood'),
+col161=abs(15378) % 2,
+col163=if(abs(4286662730.9309368000)%100<20,null,-19516),
+col167=if(abs(-1881918655)%100<20,null,6927),
+col169=if(abs(-14442)%100<20,null,-6392),
+col170=if(abs(29965)%100<20,null,'resynthesis'),
+col173=if(abs(-451)%100<20,null,'Clute'),
+col174=if(abs(3262594.6284981840)%100<20,null,17846);
+Warnings:
+Warning 1265 Data truncated for column 'col25' at row 1
+Warning 1264 Out of range value for column 'col29' at row 1
+Warning 1265 Data truncated for column 'col36' at row 1
+Warning 1264 Out of range value for column 'col38' at row 1
+Warning 1265 Data truncated for column 'col59' at row 1
+Warning 1264 Out of range value for column 'col65' at row 1
+Warning 1264 Out of range value for column 'col142' at row 1
+Warning 1264 Out of range value for column 'col156' at row 1
+Warning 1265 Data truncated for column 'col161' at row 1
+update ignore t1 set col165=repeat('a',7000);
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (a char(200) primary key, b int default 12345) engine=maria;
+insert t1 (a) values (repeat('0', 200));
+insert t1 (a) values (repeat('1', 200)), (repeat('2', 200)), (repeat('3', 200)),
+(repeat('4', 200)), (repeat('5', 200)), (repeat('6', 200)), (repeat('7', 200)),
+(repeat('8', 200)), (repeat('9', 200)), (repeat('a', 200)), (repeat('b', 200)),
+(repeat('c', 200)), (repeat('d', 200)), (repeat('e', 200)), (repeat('f', 200)),
+(repeat('g', 200)), (repeat('h', 200)), (repeat('i', 200)), (repeat('j', 200)),
+(repeat('k', 200)), (repeat('l', 200)), (repeat('m', 200)), (repeat('n', 200)),
+(repeat('o', 200)), (repeat('p', 200)), (repeat('q', 200)), (repeat('r', 200)),
+(repeat('s', 200)), (repeat('t', 200)), (repeat('u', 200)), (repeat('v', 200)),
+(repeat('w', 200)), (repeat('x', 200)), (repeat('y', 200)), (repeat('z', 200)),
+(repeat('+', 200)), (repeat('-', 200)), (repeat('=', 200)), (repeat('*', 200));
+select b from t1 where a >= repeat('f', 200) and a < 'k';
+b
+12345
+12345
+12345
+12345
+12345
+drop table t1;
+create table t1 (a int) engine=maria transactional=1;
+insert into t1 values (1);
+lock table t1 write concurrent;
+delete from t1;
+ERROR 42000: The storage engine for the table doesn't support DELETE in WRITE CONCURRENT
+drop table t1;
+create table t1 (p int primary key, i int, a char(10), key k1(i), key k2(a))
+engine maria;
+insert into t1 values (1, 1, 'qqqq'), (2, 1, 'pppp'),
+(3, 1, 'yyyy'), (4, 3, 'zzzz');
+insert into t1 values (5, 3, 'yyyy'), (6, 3, 'yyyy'), (7, 0, NULL),
+(8, 0, NULL);
+select * from t1 where a='zzzz';
+p i a
+4 3 zzzz
+select * from t1 where a='yyyy';
+p i a
+3 1 yyyy
+5 3 yyyy
+6 3 yyyy
+select * from t1 where a is NULL;
+p i a
+7 0 NULL
+8 0 NULL
+select * from t1;
+p i a
+1 1 qqqq
+2 1 pppp
+3 1 yyyy
+4 3 zzzz
+5 3 yyyy
+6 3 yyyy
+7 0 NULL
+8 0 NULL
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (f1 int unique, f2 int) engine=maria;
+create table t2 (f3 int, f4 int) engine=maria;
+create view v1 as select * from t1, t2 where f1= f3;
+insert into t1 values (1,11), (2,22);
+insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
+ERROR HY000: Can not modify more than one base table through a join view 'test.v1'
+insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
+ERROR HY000: Can not modify more than one base table through a join view 'test.v1'
+drop table t1,t2;
+drop view v1;
+CREATE TABLE t1 (id int, c varchar(10)) engine=maria;
+INSERT INTO t1 VALUES (1,"1");
+ALTER TABLE t1 CHANGE c d varchar(10);
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+drop table t1;
+create table t1 (c1 int);
+create table t2 (c1 int);
+lock table t1 read, t2 read;
+flush tables with read lock;
+unlock tables;
+drop table t1, t2;
+create table t1(a int primary key, b blob, c blob) engine=maria;
+insert into t1 values(1,repeat('a',100), repeat('b',657860));
+Warnings:
+Warning 1265 Data truncated for column 'c' at row 1
+insert into t1 values(1,repeat('a',100), repeat('b',657860));
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
diff --git a/mysql-test/suite/maria/r/maria2.result b/mysql-test/suite/maria/r/maria2.result
new file mode 100644
index 00000000000..e721ceaafae
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria2.result
@@ -0,0 +1,59 @@
+drop table if exists t1,t2;
+CREATE TABLE t1 (
+line BLOB,
+kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+name VARCHAR(32)
+) transactional=0 row_format=page engine=maria;
+select count(*) from t1;
+count(*)
+810
+delete from t1 limit 1000;
+select count(*) from t1;
+count(*)
+0
+select name from t1;
+name
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (i int) engine=maria;
+create table t2 (j int) engine=maria;
+lock table t1 write, t2 read;
+alter table t1 modify i int default 1;
+insert into t1 values (2);
+alter table t1 modify i bigint default 1;
+select count(*) from t1;
+count(*)
+1
+select * from t1;
+i
+2
+drop table t1,t2;
+create table t1(id int, s char(1), unique(s)) engine=maria;
+insert into t1 values(1,"a") on duplicate key update t1.id=t1.id+1;
+insert into t1 values(1,"a") on duplicate key update t1.id=t1.id+1;
+insert into t1 select 1,"a" on duplicate key update t1.id=t1.id+1;
+select * from t1;
+id s
+3 a
+replace into t1 select 1,"a";
+select * from t1;
+id s
+1 a
+drop table t1;
+create table t1 (pk int primary key, apk int unique, data int) engine=maria;
+insert into t1 values (1, 1, 1), (4, 4, 4), (6, 6, 6);
+load data concurrent infile '../../std_data/loaddata5.dat' replace into table t1 fields terminated by '' enclosed by '' ignore 1 lines (pk, apk);
+select * from t1 order by pk;
+pk apk data
+1 1 1
+3 4 NULL
+5 6 NULL
+load data infile '../../std_data/loaddata5.dat' replace into table t1 fields terminated by '' enclosed by '' ignore 1 lines (pk, apk);
+select * from t1 order by pk;
+pk apk data
+1 1 1
+3 4 NULL
+5 6 NULL
+drop table t1;
diff --git a/mysql-test/suite/maria/r/maria3.result b/mysql-test/suite/maria/r/maria3.result
new file mode 100644
index 00000000000..4eeb02565b7
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria3.result
@@ -0,0 +1,553 @@
+select * from INFORMATION_SCHEMA.ENGINES where ENGINE="MARIA";
+ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
+MARIA YES Crash-safe tables with MyISAM heritage YES NO NO
+set global storage_engine=maria;
+set session storage_engine=maria;
+set global maria_page_checksum=0;
+set global maria_log_file_size=4294967295;
+drop table if exists t1,t2;
+SET SQL_WARNINGS=1;
+create table t1 (a int not null, key `a` (a) key_block_size=512);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a varchar(2048), key `a` (a) key_block_size=1000000000000000000);
+Warnings:
+Warning 1071 Specified key was too long; max key length is 1112 bytes
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(2048) DEFAULT NULL,
+ KEY `a` (`a`(1112)) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a int not null, key `a` (a) key_block_size=1025);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ KEY `a` (`a`) KEY_BLOCK_SIZE=8192
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0
+drop table t1;
+create table t1 (a int not null, key key_block_size=1024 (a));
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '=1024 (a))' at line 1
+create table t1 (a int not null, key `a` key_block_size=1024 (a));
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key_block_size=1024 (a))' at line 1
+CREATE TABLE t1 (
+c1 INT,
+c2 VARCHAR(300),
+KEY (c1) KEY_BLOCK_SIZE 1024,
+KEY (c2) KEY_BLOCK_SIZE 8192
+);
+INSERT INTO t1 VALUES (10, REPEAT('a', CEIL(RAND(10) * 300))),
+(11, REPEAT('b', CEIL(RAND() * 300))),
+(12, REPEAT('c', CEIL(RAND() * 300))),
+(13, REPEAT('d', CEIL(RAND() * 300))),
+(14, REPEAT('e', CEIL(RAND() * 300))),
+(15, REPEAT('f', CEIL(RAND() * 300))),
+(16, REPEAT('g', CEIL(RAND() * 300))),
+(17, REPEAT('h', CEIL(RAND() * 300))),
+(18, REPEAT('i', CEIL(RAND() * 300))),
+(19, REPEAT('j', CEIL(RAND() * 300))),
+(20, REPEAT('k', CEIL(RAND() * 300))),
+(21, REPEAT('l', CEIL(RAND() * 300))),
+(22, REPEAT('m', CEIL(RAND() * 300))),
+(23, REPEAT('n', CEIL(RAND() * 300))),
+(24, REPEAT('o', CEIL(RAND() * 300))),
+(25, REPEAT('p', CEIL(RAND() * 300))),
+(26, REPEAT('q', CEIL(RAND() * 300))),
+(27, REPEAT('r', CEIL(RAND() * 300))),
+(28, REPEAT('s', CEIL(RAND() * 300))),
+(29, REPEAT('t', CEIL(RAND() * 300))),
+(30, REPEAT('u', CEIL(RAND() * 300))),
+(31, REPEAT('v', CEIL(RAND() * 300))),
+(32, REPEAT('w', CEIL(RAND() * 300))),
+(33, REPEAT('x', CEIL(RAND() * 300))),
+(34, REPEAT('y', CEIL(RAND() * 300))),
+(35, REPEAT('z', CEIL(RAND() * 300)));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+DELETE FROM t1 WHERE c1 >= 10;
+CHECK TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+DROP TABLE t1;
+create table t1 (a int) transactional=0;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 TRANSACTIONAL=0
+drop table t1;
+create table t1 (a int) row_format=dynamic transactional=0;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=DYNAMIC TRANSACTIONAL=0
+drop table t1;
+create table t1 (a int) row_format=dynamic transactional=1;
+Warnings:
+Note 1478 Row format set to PAGE because of TRANSACTIONAL=1 option
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=PAGE TRANSACTIONAL=1
+alter table t1 row_format=PAGE;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=PAGE TRANSACTIONAL=1
+alter table t1 row_format=DYNAMIC;
+Warnings:
+Note 1478 Row format set to PAGE because of TRANSACTIONAL=1 option
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=PAGE TRANSACTIONAL=1
+alter table t1 transactional=0;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=PAGE TRANSACTIONAL=0
+alter table t1 row_format=DYNAMIC;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=DYNAMIC TRANSACTIONAL=0
+drop table t1;
+create table t1 (a int) row_format=PAGE;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=PAGE
+drop table t1;
+create table t1 (a int) row_format=PAGE TRANSACTIONAL=DEFAULT;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=PAGE
+alter table t1 row_format=DYNAMIC;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=0 ROW_FORMAT=DYNAMIC
+drop table t1;
+create table `t1` (
+t1_name varchar(255) default null,
+t1_id int(10) unsigned not null auto_increment,
+key (t1_name),
+primary key (t1_id)
+) engine=maria auto_increment = 1000 default charset=latin1;
+lock tables t1 write;
+INSERT INTO `t1` VALUES ('bla',1000),('bla',1001),('bla',1002);
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+unlock tables;
+create table t2 like t1;
+insert into t2 select * from t1;
+analyze table t2;
+Table Op Msg_type Msg_text
+test.t2 analyze status Table is already up to date
+delete from t2;
+insert into t2 select * from t1;
+analyze table t2;
+Table Op Msg_type Msg_text
+test.t2 analyze status Table is already up to date
+drop table t1,t2;
+create table t1 (a bigint auto_increment, primary key(a), b char(255), c varchar(20000));
+update t1 set b=repeat('a',100) where a between 1 and 100;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+update t1 set c=repeat('a',8192*2) where a between 200 and 202;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+CREATE TABLE t1 (a int, b int, v varchar(60000)) checksum=1 engine=maria;
+insert into t1 values (1,1,"aaa"),(1,2,null);
+checksum table t1;
+Table Checksum
+test.t1 1112804611
+lock table t1 write;
+insert into t1 values (1,3,repeat('c',30000)),(4,4,repeat('a',30000));
+update t1 set v="row5" where b=4;
+delete from t1 where b=3;
+select a, b, length(v) from t1;
+a b length(v)
+1 1 3
+1 2 NULL
+4 4 4
+drop table t1;
+CREATE TABLE t1 (
+auto int(5) unsigned NOT NULL auto_increment,
+string char(10) default "hello",
+tiny tinyint(4) DEFAULT '0' NOT NULL ,
+short smallint(6) DEFAULT '1' NOT NULL ,
+medium mediumint(8) DEFAULT '0' NOT NULL,
+long_int int(11) DEFAULT '0' NOT NULL,
+longlong bigint(13) DEFAULT '0' NOT NULL,
+real_float float(13,1) DEFAULT 0.0 NOT NULL,
+real_double double(16,4),
+utiny tinyint(3) unsigned DEFAULT '0' NOT NULL,
+ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL,
+umedium mediumint(8) unsigned DEFAULT '0' NOT NULL,
+ulong int(11) unsigned DEFAULT '0' NOT NULL,
+ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL,
+time_stamp timestamp,
+date_field date,
+time_field time,
+date_time datetime,
+blob_col blob,
+tinyblob_col tinyblob,
+mediumblob_col mediumblob not null default '',
+longblob_col longblob not null default '',
+options enum('one','two','tree') not null ,
+flags set('one','two','tree') not null default '',
+PRIMARY KEY (auto),
+KEY (utiny),
+KEY (tiny),
+KEY (short),
+KEY any_name (medium),
+KEY (longlong),
+KEY (real_float),
+KEY (ushort),
+KEY (umedium),
+KEY (ulong),
+KEY (ulonglong,ulong),
+KEY (options,flags)
+) engine=maria;
+insert into t1 values (10,1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one');
+create table t2 (primary key (auto)) engine=maria row_format=page select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
+check table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+test.t2 check status OK
+select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
+t1 t2 length(t3) length(t4) length(t5) length(t6) t7 t8
+1 a 256 256 4096 4096
+drop table t2;
+create table t2 (primary key (auto)) engine=maria row_format=dynamic select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
+check table t2;
+Table Op Msg_type Msg_text
+test.t2 check status OK
+drop table t1,t2;
+CREATE TABLE t1 (seq int, s1 int, s2 blob);
+insert into t1 values (1, 1, MD5(1));
+update t1 set s1=2 where seq=1;
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+show variables like 'maria%';
+Variable_name Value
+maria_block_size 8192
+maria_checkpoint_interval 30
+maria_force_start_after_recovery_failures 0
+maria_log_file_size 4294959104
+maria_log_purge_type immediate
+maria_max_sort_file_size 9223372036853727232
+maria_page_checksum OFF
+maria_pagecache_age_threshold 300
+maria_pagecache_buffer_size 8384512
+maria_pagecache_division_limit 100
+maria_recover OFF
+maria_repair_threads 1
+maria_sort_buffer_size 8388608
+maria_stats_method nulls_unequal
+maria_sync_log_dir NEWFILE
+show status like 'maria%';
+Variable_name Value
+Maria_pagecache_blocks_not_flushed #
+Maria_pagecache_blocks_unused #
+Maria_pagecache_blocks_used #
+Maria_pagecache_read_requests #
+Maria_pagecache_reads #
+Maria_pagecache_write_requests #
+Maria_pagecache_writes #
+create table t1 (b char(0));
+insert into t1 values(NULL),("");
+select length(b) from t1;
+length(b)
+NULL
+0
+alter table t1 add column c char(0), add key (c);
+insert into t1 values("",""),("",NULL);
+select length(b),length(c) from t1;
+length(b) length(c)
+NULL NULL
+0 NULL
+0 0
+0 NULL
+select length(b),length(c) from t1 where c is null;
+length(b) length(c)
+NULL NULL
+0 NULL
+0 NULL
+select length(b),length(c) from t1 where c is not null;
+length(b) length(c)
+0 0
+select length(b),length(c) from t1 order by c;
+length(b) length(c)
+NULL NULL
+0 NULL
+0 NULL
+0 0
+alter table t1 add column d char(0) not null, add key (d);
+ERROR 42000: The used storage engine can't index column 'd'
+drop table t1;
+CREATE TABLE t1 (a bit(3));
+insert into t1 values (NULL),(0),(1),(2),(3),(4),(5),(6),(7);
+select hex(a) from t1;
+hex(a)
+NULL
+0
+1
+2
+3
+4
+5
+6
+7
+drop table t1;
+create table t1(a bit not null);
+insert into t1 values(0),(1);
+select a+0 from t1;
+a+0
+0
+1
+drop table t1;
+CREATE TABLE t1 (col1 int, s1 char(16) DEFAULT NULL, s2 char(16) DEFAULT NULL, KEY (s1,s2));
+insert into t1 (col1) values(0);
+drop table t1;
+set global maria_page_checksum=1;
+create table t1 (a int);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+drop table t1;
+set global maria_log_file_size=4294967296;
+Warnings:
+Warning 1292 Truncated incorrect log_file_size value: '4294967296'
+create table t1 (a int not null);
+lock tables t1 write;
+insert into t1 values (1),(2);
+delete from t1;
+unlock tables;
+select * from t1;
+a
+insert into t1 values (1),(2);
+delete from t1;
+select * from t1;
+a
+drop table t1;
+create table t1 (c int);
+insert into t1 values(1),(2);
+create table t2 select * from t1;
+create table t3 select * from t1, t2;
+ERROR 42S21: Duplicate column name 'c'
+create table t3 select t1.c AS c1, t2.c AS c2,1 as "const" from t1, t2;
+drop table t1, t2, t3;
+create table t1 (t datetime) engine=maria;
+insert into t1 values (101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030100000000),(20030000000000);
+select * from t1;
+t
+2000-01-01 00:00:00
+2069-12-31 00:00:00
+1970-01-01 00:00:00
+1999-12-31 00:00:00
+1000-01-01 00:00:00
+9999-12-31 00:00:00
+2000-01-01 00:00:00
+2069-12-31 00:00:00
+1970-01-01 00:00:00
+1999-12-31 23:59:59
+1000-01-01 00:00:00
+9999-12-31 23:59:59
+2003-01-00 00:00:00
+2003-00-00 00:00:00
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+delete from t1 where t > 0;
+optimize table t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
+CREATE TABLE t1 (id int(11) PRIMARY KEY auto_increment,f1 varchar(10) NOT NULL UNIQUE);
+INSERT IGNORE INTO t1 (f1) VALUES ("test1");
+INSERT IGNORE INTO t1 (f1) VALUES ("test1");
+INSERT IGNORE INTO t1 (f1) VALUES ("test2");
+SELECT * FROM t1;
+id f1
+1 test1
+2 test2
+drop table t1;
+SET SQL_MODE = 'TRADITIONAL';
+create table t1 (n int not null primary key auto_increment, c char(1), unique(c));
+insert into t1 values(100, "a");
+insert into t1 values(300, "b");
+insert into t1 values(50, "a");
+ERROR 23000: Duplicate entry 'a' for key 'c'
+insert into t1 values(null, "c");
+select * from t1;
+n c
+100 a
+300 b
+301 c
+update t1 set n=400,c='a' where n=301;
+ERROR 23000: Duplicate entry 'a' for key 'c'
+insert into t1 values(null, "d");
+select * from t1;
+n c
+100 a
+300 b
+301 c
+302 d
+drop table t1;
+create table t1 (n int not null primary key auto_increment, c char(1), unique(c)) transactional=0 row_format=dynamic;
+insert into t1 values(100, "a");
+insert into t1 values(300, "b");
+insert into t1 values(50, "a");
+ERROR 23000: Duplicate entry 'a' for key 'c'
+insert into t1 values(null, "c");
+select * from t1;
+n c
+100 a
+300 b
+301 c
+update t1 set n=400,c='a' where n=301;
+ERROR 23000: Duplicate entry 'a' for key 'c'
+insert into t1 values(null, "d");
+select * from t1;
+n c
+100 a
+300 b
+301 c
+302 d
+drop table t1;
+create table t1 (n int not null, c char(1)) engine=maria;
+alter table t1 engine=myisam;
+alter table t1 engine=maria;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `n` int(11) NOT NULL,
+ `c` char(1) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+drop table t1;
+create table t1 (n int not null, c char(1)) engine=maria transactional=1;
+alter table t1 engine=myisam;
+Warnings:
+Error 1478 Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
+alter table t1 engine=maria;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `n` int(11) NOT NULL,
+ `c` char(1) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+drop table t1;
+create table t1 (n int not null, c char(1)) engine=myisam transactional=1;
+Warnings:
+Error 1478 Table storage engine 'MyISAM' does not support the create option 'TRANSACTIONAL=1'
+alter table t1 engine=maria;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `n` int(11) NOT NULL,
+ `c` char(1) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 TRANSACTIONAL=1
+drop table t1;
+create table t1 (a int, key(a)) transactional=0;
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t1 select NULL from t1;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create temporary table t1 (a int, key(a)) transactional=1;
+create temporary table t2 (a int, key(a)) transactional=1;
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t2 select * from t1;
+insert into t1 select NULL from t2;
+select count(*) from t1;
+count(*)
+10
+select count(*) from t1 where a >= 4;
+count(*)
+1
+drop table t1, t2;
+create table t1 (i int auto_increment not null primary key) transactional=0;
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+delete from t1 where i = 10;
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1 (i int auto_increment not null primary key);
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+delete from t1 where i = 10;
+check table t1 extended;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+CREATE TABLE t1(a VARCHAR(20), FULLTEXT(a)) transactional=0;
+INSERT INTO t1 VALUES('Offside'),('City Of God');
+SELECT a FROM t1 WHERE MATCH a AGAINST ('+city of*' IN BOOLEAN MODE);
+a
+City Of God
+SELECT a FROM t1 WHERE MATCH a AGAINST ('+city (of)*' IN BOOLEAN MODE);
+a
+City Of God
+DROP TABLE t1;
+create table t1(a int) engine=maria transactional=1;
+select CREATE_OPTIONS from information_schema.TABLES where
+TABLE_SCHEMA='test' and TABLE_NAME='t1';
+CREATE_OPTIONS
+transactional=1
+drop table t1;
+create table t1 (a int, unique(a)) engine=maria transactional=1;
+insert into t1 values(1);
+insert into t1 values(2),(2);
+ERROR 23000: Duplicate entry '2' for key 'a'
+create table t2 (a int, unique(a)) engine=maria transactional=0 row_format=dynamic;
+insert into t2 values(1);
+insert into t2 values(2),(2);
+ERROR 23000: Duplicate entry '2' for key 'a'
+insert into t1 values(3);
+insert into t2 values(3);
+drop table t1, t2;
diff --git a/mysql-test/suite/maria/r/maria_notembedded.result b/mysql-test/suite/maria/r/maria_notembedded.result
new file mode 100644
index 00000000000..77325d24421
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria_notembedded.result
@@ -0,0 +1,56 @@
+set session storage_engine=maria;
+create table t1 (a int) row_format=page;
+insert delayed into t1 values(1);
+ERROR HY000: DELAYED option not supported for table 't1'
+drop table t1;
+create table t1 (a int) row_format=page transactional=0;
+insert delayed into t1 values(1);
+flush table t1;
+select * from t1;
+a
+1
+select count(*) from t1;
+count(*)
+1
+drop table t1;
+create table t1 (a int) row_format=dynamic;
+insert delayed into t1 values(1);
+flush table t1;
+select * from t1;
+a
+1
+select count(*) from t1;
+count(*)
+1
+drop table t1;
+create table t1 (a int unique) transactional=1;
+insert t1 values (1);
+lock table t1 write concurrent;
+insert t1 values (2);
+lock table t1 write concurrent;
+insert t1 values (3);
+insert t1 values (2);
+lock table t1 write concurrent;
+insert t1 values (4);
+insert t1 values (3);
+lock table t1 write concurrent;
+insert t1 values (5);
+insert t1 values (4);
+lock table t1 write concurrent;
+insert t1 values (6);
+insert t1 values (5);
+insert t1 values (6);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+unlock tables;
+ERROR 23000: Duplicate entry '2' for key 'a'
+unlock tables;
+ERROR 23000: Duplicate entry '3' for key 'a'
+unlock tables;
+ERROR 23000: Duplicate entry '4' for key 'a'
+unlock tables;
+ERROR 23000: Duplicate entry '5' for key 'a'
+unlock tables;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
diff --git a/mysql-test/suite/maria/r/maria_partition.result b/mysql-test/suite/maria/r/maria_partition.result
new file mode 100644
index 00000000000..e501af7ec4a
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria_partition.result
@@ -0,0 +1,35 @@
+set global storage_engine=maria;
+set session storage_engine=maria;
+set global maria_page_checksum=0;
+drop table if exists t1,t2;
+drop view if exists v1;
+SET SQL_WARNINGS=1;
+create table t1 (s1 int);
+insert into t1 values (1);
+alter table t1 partition by list (s1) (partition p1 values in (2));
+ERROR HY000: Table has no partition for value 1
+drop table t1;
+create table t2(a blob) engine=maria;
+create table t1(a int primary key) engine=maria;
+insert into t2 values ('foo'),('bar');
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+a a
+insert into t1 values (1);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+a a
+insert into t1 values (2);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+a a
+drop table t1,t2;
+create table t2(a blob);
+create table t1(a int primary key) PARTITION BY HASH (a) PARTITIONS 2;
+insert into t2 values ('foo'),('bar');
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+a a
+insert into t1 values (1);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+a a
+insert into t1 values (2);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+a a
+drop table t1,t2;
diff --git a/mysql-test/suite/maria/r/maria_showlog_error.result b/mysql-test/suite/maria/r/maria_showlog_error.result
new file mode 100644
index 00000000000..b27b4a5b21c
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria_showlog_error.result
@@ -0,0 +1,5 @@
+* shut down mysqld, removed logs, restarted it
+show engine maria logs;
+Type Name Status
+MARIA Size unknown ; maria_log.00000001 can't stat
+* shut down mysqld, removed logs, restarted it
diff --git a/mysql-test/suite/maria/r/ps_maria.result b/mysql-test/suite/maria/r/ps_maria.result
new file mode 100644
index 00000000000..10172868474
--- /dev/null
+++ b/mysql-test/suite/maria/r/ps_maria.result
@@ -0,0 +1,3144 @@
+use test;
+drop table if exists t1, t9 ;
+create table t1
+(
+a int, b varchar(30),
+primary key(a)
+) engine = 'MARIA' ;
+create table t9
+(
+c1 tinyint, c2 smallint, c3 mediumint, c4 int,
+c5 integer, c6 bigint, c7 float, c8 double,
+c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4),
+c13 date, c14 datetime, c15 timestamp, c16 time,
+c17 year, c18 tinyint, c19 bool, c20 char,
+c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext,
+c25 blob, c26 text, c27 mediumblob, c28 mediumtext,
+c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'),
+c32 set('monday', 'tuesday', 'wednesday'),
+primary key(c1)
+) engine = 'MARIA' ;
+delete from t1 ;
+insert into t1 values (1,'one');
+insert into t1 values (2,'two');
+insert into t1 values (3,'three');
+insert into t1 values (4,'four');
+commit ;
+delete from t9 ;
+insert into t9
+set c1= 1, c2= 1, c3= 1, c4= 1, c5= 1, c6= 1, c7= 1, c8= 1, c9= 1,
+c10= 1, c11= 1, c12 = 1,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=true, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='one', c32= 'monday';
+insert into t9
+set c1= 9, c2= 9, c3= 9, c4= 9, c5= 9, c6= 9, c7= 9, c8= 9, c9= 9,
+c10= 9, c11= 9, c12 = 9,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=false, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday';
+commit ;
+test_sequence
+------ simple select tests ------
+prepare stmt1 from ' select * from t9 order by c1 ' ;
+execute stmt1;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t9 t9 c1 c1 1 4 1 N 49155 0 63
+def test t9 t9 c2 c2 2 6 1 Y 32768 0 63
+def test t9 t9 c3 c3 9 9 1 Y 32768 0 63
+def test t9 t9 c4 c4 3 11 1 Y 32768 0 63
+def test t9 t9 c5 c5 3 11 1 Y 32768 0 63
+def test t9 t9 c6 c6 8 20 1 Y 32768 0 63
+def test t9 t9 c7 c7 4 12 1 Y 32768 31 63
+def test t9 t9 c8 c8 5 22 1 Y 32768 31 63
+def test t9 t9 c9 c9 5 22 1 Y 32768 31 63
+def test t9 t9 c10 c10 5 22 1 Y 32768 31 63
+def test t9 t9 c11 c11 246 9 6 Y 0 4 63
+def test t9 t9 c12 c12 246 10 6 Y 0 4 63
+def test t9 t9 c13 c13 10 10 10 Y 128 0 63
+def test t9 t9 c14 c14 12 19 19 Y 128 0 63
+def test t9 t9 c15 c15 7 19 19 N 9441 0 63
+def test t9 t9 c16 c16 11 8 8 Y 128 0 63
+def test t9 t9 c17 c17 13 4 4 Y 32864 0 63
+def test t9 t9 c18 c18 1 4 1 Y 32768 0 63
+def test t9 t9 c19 c19 1 1 1 Y 32768 0 63
+def test t9 t9 c20 c20 254 1 1 Y 0 0 8
+def test t9 t9 c21 c21 254 10 10 Y 0 0 8
+def test t9 t9 c22 c22 253 30 30 Y 0 0 8
+def test t9 t9 c23 c23 252 255 8 Y 144 0 63
+def test t9 t9 c24 c24 252 255 8 Y 16 0 8
+def test t9 t9 c25 c25 252 65535 4 Y 144 0 63
+def test t9 t9 c26 c26 252 65535 4 Y 16 0 8
+def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63
+def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8
+def test t9 t9 c29 c29 252 4294967295 8 Y 144 0 63
+def test t9 t9 c30 c30 252 4294967295 8 Y 16 0 8
+def test t9 t9 c31 c31 254 5 3 Y 256 0 8
+def test t9 t9 c32 c32 254 24 7 Y 2048 0 8
+c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday
+set @arg00='SELECT' ;
+@arg00 a from t1 where a=1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1
+prepare stmt1 from ' ? a from t1 where a=1 ';
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1
+set @arg00=1 ;
+select @arg00, b from t1 where a=1 ;
+@arg00 b
+1 one
+prepare stmt1 from ' select ?, b from t1 where a=1 ' ;
+execute stmt1 using @arg00 ;
+? b
+1 one
+set @arg00='lion' ;
+select @arg00, b from t1 where a=1 ;
+@arg00 b
+lion one
+prepare stmt1 from ' select ?, b from t1 where a=1 ' ;
+execute stmt1 using @arg00 ;
+? b
+lion one
+set @arg00=NULL ;
+select @arg00, b from t1 where a=1 ;
+@arg00 b
+NULL one
+prepare stmt1 from ' select ?, b from t1 where a=1 ' ;
+execute stmt1 using @arg00 ;
+? b
+NULL one
+set @arg00=1 ;
+select b, a - @arg00 from t1 where a=1 ;
+b a - @arg00
+one 0
+prepare stmt1 from ' select b, a - ? from t1 where a=1 ' ;
+execute stmt1 using @arg00 ;
+b a - ?
+one 0
+set @arg00=null ;
+select @arg00 as my_col ;
+my_col
+NULL
+prepare stmt1 from ' select ? as my_col';
+execute stmt1 using @arg00 ;
+my_col
+NULL
+select @arg00 + 1 as my_col ;
+my_col
+NULL
+prepare stmt1 from ' select ? + 1 as my_col';
+execute stmt1 using @arg00 ;
+my_col
+NULL
+select 1 + @arg00 as my_col ;
+my_col
+NULL
+prepare stmt1 from ' select 1 + ? as my_col';
+execute stmt1 using @arg00 ;
+my_col
+NULL
+set @arg00='MySQL' ;
+select substr(@arg00,1,2) from t1 where a=1 ;
+substr(@arg00,1,2)
+My
+prepare stmt1 from ' select substr(?,1,2) from t1 where a=1 ' ;
+execute stmt1 using @arg00 ;
+substr(?,1,2)
+My
+set @arg00=3 ;
+select substr('MySQL',@arg00,5) from t1 where a=1 ;
+substr('MySQL',@arg00,5)
+SQL
+prepare stmt1 from ' select substr(''MySQL'',?,5) from t1 where a=1 ' ;
+execute stmt1 using @arg00 ;
+substr('MySQL',?,5)
+SQL
+select substr('MySQL',1,@arg00) from t1 where a=1 ;
+substr('MySQL',1,@arg00)
+MyS
+prepare stmt1 from ' select substr(''MySQL'',1,?) from t1 where a=1 ' ;
+execute stmt1 using @arg00 ;
+substr('MySQL',1,?)
+MyS
+set @arg00='MySQL' ;
+select a , concat(@arg00,b) from t1 order by a;
+a concat(@arg00,b)
+1 MySQLone
+2 MySQLtwo
+3 MySQLthree
+4 MySQLfour
+prepare stmt1 from ' select a , concat(?,b) from t1 order by a ' ;
+execute stmt1 using @arg00;
+a concat(?,b)
+1 MySQLone
+2 MySQLtwo
+3 MySQLthree
+4 MySQLfour
+select a , concat(b,@arg00) from t1 order by a ;
+a concat(b,@arg00)
+1 oneMySQL
+2 twoMySQL
+3 threeMySQL
+4 fourMySQL
+prepare stmt1 from ' select a , concat(b,?) from t1 order by a ' ;
+execute stmt1 using @arg00;
+a concat(b,?)
+1 oneMySQL
+2 twoMySQL
+3 threeMySQL
+4 fourMySQL
+set @arg00='MySQL' ;
+select group_concat(@arg00,b order by a) from t1
+group by 'a' ;
+group_concat(@arg00,b order by a)
+MySQLone,MySQLtwo,MySQLthree,MySQLfour
+prepare stmt1 from ' select group_concat(?,b order by a) from t1
+group by ''a'' ' ;
+execute stmt1 using @arg00;
+group_concat(?,b order by a)
+MySQLone,MySQLtwo,MySQLthree,MySQLfour
+select group_concat(b,@arg00 order by a) from t1
+group by 'a' ;
+group_concat(b,@arg00 order by a)
+oneMySQL,twoMySQL,threeMySQL,fourMySQL
+prepare stmt1 from ' select group_concat(b,? order by a) from t1
+group by ''a'' ' ;
+execute stmt1 using @arg00;
+group_concat(b,? order by a)
+oneMySQL,twoMySQL,threeMySQL,fourMySQL
+set @arg00='first' ;
+set @arg01='second' ;
+set @arg02=NULL;
+select @arg00, @arg01 from t1 where a=1 ;
+@arg00 @arg01
+first second
+prepare stmt1 from ' select ?, ? from t1 where a=1 ' ;
+execute stmt1 using @arg00, @arg01 ;
+? ?
+first second
+execute stmt1 using @arg02, @arg01 ;
+? ?
+NULL second
+execute stmt1 using @arg00, @arg02 ;
+? ?
+first NULL
+execute stmt1 using @arg02, @arg02 ;
+? ?
+NULL NULL
+drop table if exists t5 ;
+create table t5 (id1 int(11) not null default '0',
+value2 varchar(100), value1 varchar(100)) ;
+insert into t5 values (1,'hh','hh'),(2,'hh','hh'),
+(1,'ii','ii'),(2,'ii','ii') ;
+prepare stmt1 from ' select id1,value1 from t5 where id1=? or value1=? order by id1,value1 ' ;
+set @arg00=1 ;
+set @arg01='hh' ;
+execute stmt1 using @arg00, @arg01 ;
+id1 value1
+1 hh
+1 ii
+2 hh
+drop table t5 ;
+drop table if exists t5 ;
+create table t5(session_id char(9) not null) ;
+insert into t5 values ('abc') ;
+prepare stmt1 from ' select * from t5
+where ?=''1111'' and session_id = ''abc'' ' ;
+set @arg00='abc' ;
+execute stmt1 using @arg00 ;
+session_id
+set @arg00='1111' ;
+execute stmt1 using @arg00 ;
+session_id
+abc
+set @arg00='abc' ;
+execute stmt1 using @arg00 ;
+session_id
+drop table t5 ;
+set @arg00='FROM' ;
+select a @arg00 t1 where a=1 ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 t1 where a=1' at line 1
+prepare stmt1 from ' select a ? t1 where a=1 ' ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? t1 where a=1' at line 1
+set @arg00='t1' ;
+select a from @arg00 where a=1 ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 where a=1' at line 1
+prepare stmt1 from ' select a from ? where a=1 ' ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? where a=1' at line 1
+set @arg00='WHERE' ;
+select a from t1 @arg00 a=1 ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a=1' at line 1
+prepare stmt1 from ' select a from t1 ? a=1 ' ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a=1' at line 1
+set @arg00=1 ;
+select a FROM t1 where a=@arg00 ;
+a
+1
+prepare stmt1 from ' select a FROM t1 where a=? ' ;
+execute stmt1 using @arg00 ;
+a
+1
+set @arg00=1000 ;
+execute stmt1 using @arg00 ;
+a
+set @arg00=NULL ;
+select a FROM t1 where a=@arg00 ;
+a
+prepare stmt1 from ' select a FROM t1 where a=? ' ;
+execute stmt1 using @arg00 ;
+a
+set @arg00=4 ;
+select a FROM t1 where a=sqrt(@arg00) ;
+a
+2
+prepare stmt1 from ' select a FROM t1 where a=sqrt(?) ' ;
+execute stmt1 using @arg00 ;
+a
+2
+set @arg00=NULL ;
+select a FROM t1 where a=sqrt(@arg00) ;
+a
+prepare stmt1 from ' select a FROM t1 where a=sqrt(?) ' ;
+execute stmt1 using @arg00 ;
+a
+set @arg00=2 ;
+set @arg01=3 ;
+select a FROM t1 where a in (@arg00,@arg01) order by a;
+a
+2
+3
+prepare stmt1 from ' select a FROM t1 where a in (?,?) order by a ';
+execute stmt1 using @arg00, @arg01;
+a
+2
+3
+set @arg00= 'one' ;
+set @arg01= 'two' ;
+set @arg02= 'five' ;
+prepare stmt1 from ' select b FROM t1 where b in (?,?,?) order by b ' ;
+execute stmt1 using @arg00, @arg01, @arg02 ;
+b
+one
+two
+prepare stmt1 from ' select b FROM t1 where b like ? ';
+set @arg00='two' ;
+execute stmt1 using @arg00 ;
+b
+two
+set @arg00='tw%' ;
+execute stmt1 using @arg00 ;
+b
+two
+set @arg00='%wo' ;
+execute stmt1 using @arg00 ;
+b
+two
+set @arg00=null ;
+insert into t9 set c1= 0, c5 = NULL ;
+select c5 from t9 where c5 > NULL ;
+c5
+prepare stmt1 from ' select c5 from t9 where c5 > ? ';
+execute stmt1 using @arg00 ;
+c5
+select c5 from t9 where c5 < NULL ;
+c5
+prepare stmt1 from ' select c5 from t9 where c5 < ? ';
+execute stmt1 using @arg00 ;
+c5
+select c5 from t9 where c5 = NULL ;
+c5
+prepare stmt1 from ' select c5 from t9 where c5 = ? ';
+execute stmt1 using @arg00 ;
+c5
+select c5 from t9 where c5 <=> NULL ;
+c5
+NULL
+prepare stmt1 from ' select c5 from t9 where c5 <=> ? ';
+execute stmt1 using @arg00 ;
+c5
+NULL
+delete from t9 where c1= 0 ;
+set @arg00='>' ;
+select a FROM t1 where a @arg00 1 ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 1' at line 1
+prepare stmt1 from ' select a FROM t1 where a ? 1 ' ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? 1' at line 1
+set @arg00=1 ;
+select a,b FROM t1 where a is not NULL
+AND b is not NULL group by a - @arg00 ;
+a b
+1 one
+2 two
+3 three
+4 four
+prepare stmt1 from ' select a,b FROM t1 where a is not NULL
+AND b is not NULL group by a - ? ' ;
+execute stmt1 using @arg00 ;
+a b
+1 one
+2 two
+3 three
+4 four
+set @arg00='two' ;
+select a,b FROM t1 where a is not NULL
+AND b is not NULL having b <> @arg00 order by a ;
+a b
+1 one
+3 three
+4 four
+prepare stmt1 from ' select a,b FROM t1 where a is not NULL
+AND b is not NULL having b <> ? order by a ' ;
+execute stmt1 using @arg00 ;
+a b
+1 one
+3 three
+4 four
+set @arg00=1 ;
+select a,b FROM t1 where a is not NULL
+AND b is not NULL order by a - @arg00 ;
+a b
+1 one
+2 two
+3 three
+4 four
+prepare stmt1 from ' select a,b FROM t1 where a is not NULL
+AND b is not NULL order by a - ? ' ;
+execute stmt1 using @arg00 ;
+a b
+1 one
+2 two
+3 three
+4 four
+set @arg00=2 ;
+select a,b from t1 order by 2 ;
+a b
+4 four
+1 one
+3 three
+2 two
+prepare stmt1 from ' select a,b from t1
+order by ? ';
+execute stmt1 using @arg00;
+a b
+4 four
+1 one
+3 three
+2 two
+set @arg00=1 ;
+execute stmt1 using @arg00;
+a b
+1 one
+2 two
+3 three
+4 four
+set @arg00=0 ;
+execute stmt1 using @arg00;
+ERROR 42S22: Unknown column '?' in 'order clause'
+set @arg00=1;
+prepare stmt1 from ' select a,b from t1 order by a
+limit 1 ';
+execute stmt1 ;
+a b
+1 one
+prepare stmt1 from ' select a,b from t1 order by a limit ? ';
+execute stmt1 using @arg00;
+a b
+1 one
+set @arg00='b' ;
+set @arg01=0 ;
+set @arg02=2 ;
+set @arg03=2 ;
+select sum(a), @arg00 from t1 where a > @arg01
+and b is not null group by substr(b,@arg02)
+having sum(a) <> @arg03 ;
+sum(a) @arg00
+3 b
+1 b
+4 b
+prepare stmt1 from ' select sum(a), ? from t1 where a > ?
+and b is not null group by substr(b,?)
+having sum(a) <> ? ';
+execute stmt1 using @arg00, @arg01, @arg02, @arg03;
+sum(a) ?
+3 b
+1 b
+4 b
+test_sequence
+------ join tests ------
+select first.a as a1, second.a as a2
+from t1 first, t1 second
+where first.a = second.a order by a1 ;
+a1 a2
+1 1
+2 2
+3 3
+4 4
+prepare stmt1 from ' select first.a as a1, second.a as a2
+ from t1 first, t1 second
+ where first.a = second.a order by a1 ';
+execute stmt1 ;
+a1 a2
+1 1
+2 2
+3 3
+4 4
+set @arg00='ABC';
+set @arg01='two';
+set @arg02='one';
+select first.a, @arg00, second.a FROM t1 first, t1 second
+where @arg01 = first.b or first.a = second.a or second.b = @arg02
+order by second.a, first.a;
+a @arg00 a
+1 ABC 1
+2 ABC 1
+3 ABC 1
+4 ABC 1
+2 ABC 2
+2 ABC 3
+3 ABC 3
+2 ABC 4
+4 ABC 4
+prepare stmt1 from ' select first.a, ?, second.a FROM t1 first, t1 second
+ where ? = first.b or first.a = second.a or second.b = ?
+ order by second.a, first.a';
+execute stmt1 using @arg00, @arg01, @arg02;
+a ? a
+1 ABC 1
+2 ABC 1
+3 ABC 1
+4 ABC 1
+2 ABC 2
+2 ABC 3
+3 ABC 3
+2 ABC 4
+4 ABC 4
+drop table if exists t2 ;
+create table t2 as select * from t1 ;
+set @query1= 'SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a ' ;
+set @query2= 'SELECT * FROM t2 natural join t1 order by t2.a ' ;
+set @query3= 'SELECT * FROM t2 join t1 using(a) order by t2.a ' ;
+set @query4= 'SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a ' ;
+set @query5= 'SELECT * FROM t2 natural left join t1 order by t2.a ' ;
+set @query6= 'SELECT * FROM t2 left join t1 using(a) order by t2.a ' ;
+set @query7= 'SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a ' ;
+set @query8= 'SELECT * FROM t2 natural right join t1 order by t2.a ' ;
+set @query9= 'SELECT * FROM t2 right join t1 using(a) order by t2.a ' ;
+the join statement is:
+SELECT * FROM t2 right join t1 using(a) order by t2.a
+prepare stmt1 from @query9 ;
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+the join statement is:
+SELECT * FROM t2 natural right join t1 order by t2.a
+prepare stmt1 from @query8 ;
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+the join statement is:
+SELECT * FROM t2 right join t1 on(t1.a=t2.a) order by t2.a
+prepare stmt1 from @query7 ;
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+the join statement is:
+SELECT * FROM t2 left join t1 using(a) order by t2.a
+prepare stmt1 from @query6 ;
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+the join statement is:
+SELECT * FROM t2 natural left join t1 order by t2.a
+prepare stmt1 from @query5 ;
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+the join statement is:
+SELECT * FROM t2 left join t1 on(t1.a=t2.a) order by t2.a
+prepare stmt1 from @query4 ;
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+the join statement is:
+SELECT * FROM t2 join t1 using(a) order by t2.a
+prepare stmt1 from @query3 ;
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+execute stmt1 ;
+a b b
+1 one one
+2 two two
+3 three three
+4 four four
+the join statement is:
+SELECT * FROM t2 natural join t1 order by t2.a
+prepare stmt1 from @query2 ;
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+the join statement is:
+SELECT * FROM t2 join t1 on (t1.a=t2.a) order by t2.a
+prepare stmt1 from @query1 ;
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+execute stmt1 ;
+a b a b
+1 one 1 one
+2 two 2 two
+3 three 3 three
+4 four 4 four
+drop table t2 ;
+test_sequence
+------ subquery tests ------
+prepare stmt1 from ' select a, b FROM t1 outer_table where
+ a = (select a from t1 where b = ''two'') ';
+execute stmt1 ;
+a b
+2 two
+set @arg00='two' ;
+select a, b FROM t1 outer_table where
+a = (select a from t1 where b = 'two' ) and b=@arg00 ;
+a b
+2 two
+prepare stmt1 from ' select a, b FROM t1 outer_table where
+ a = (select a from t1 where b = ''two'') and b=? ';
+execute stmt1 using @arg00;
+a b
+2 two
+set @arg00='two' ;
+select a, b FROM t1 outer_table where
+a = (select a from t1 where b = @arg00 ) and b='two' ;
+a b
+2 two
+prepare stmt1 from ' select a, b FROM t1 outer_table where
+ a = (select a from t1 where b = ? ) and b=''two'' ' ;
+execute stmt1 using @arg00;
+a b
+2 two
+set @arg00=3 ;
+set @arg01='three' ;
+select a,b FROM t1 where (a,b) in (select 3, 'three');
+a b
+3 three
+select a FROM t1 where (a,b) in (select @arg00,@arg01);
+a
+3
+prepare stmt1 from ' select a FROM t1 where (a,b) in (select ?, ?) ';
+execute stmt1 using @arg00, @arg01;
+a
+3
+set @arg00=1 ;
+set @arg01='two' ;
+set @arg02=2 ;
+set @arg03='two' ;
+select a, @arg00, b FROM t1 outer_table where
+b=@arg01 and a = (select @arg02 from t1 where b = @arg03 ) ;
+a @arg00 b
+2 1 two
+prepare stmt1 from ' select a, ?, b FROM t1 outer_table where
+ b=? and a = (select ? from t1 where b = ? ) ' ;
+execute stmt1 using @arg00, @arg01, @arg02, @arg03 ;
+a ? b
+2 1 two
+prepare stmt1 from 'select c4 FROM t9 where
+ c13 = (select MAX(b) from t1 where a = ?) and c22 = ? ' ;
+execute stmt1 using @arg01, @arg02;
+c4
+prepare stmt1 from ' select a, b FROM t1 outer_table where
+ a = (select a from t1 where b = outer_table.b ) order by a ';
+execute stmt1 ;
+a b
+1 one
+2 two
+3 three
+4 four
+prepare stmt1 from ' SELECT a as ccc from t1 outr where a+1=
+ (SELECT 1+outr.a from t1 where outr.a+1=a+1 and a=1) ';
+execute stmt1 ;
+ccc
+1
+deallocate prepare stmt1 ;
+prepare stmt1 from ' SELECT a as ccc from t1 outr where a+1=
+ (SELECT 1+outr.a from t1 where outr.a+1=a+1 and a=1) ';
+execute stmt1 ;
+ccc
+1
+deallocate prepare stmt1 ;
+prepare stmt1 from ' SELECT a as ccc from t1 outr where a+1=
+ (SELECT 1+outr.a from t1 where outr.a+1=a+1 and a=1) ';
+execute stmt1 ;
+ccc
+1
+deallocate prepare stmt1 ;
+set @arg00='two' ;
+select a, b FROM t1 outer_table where
+a = (select a from t1 where b = outer_table.b ) and b=@arg00 ;
+a b
+2 two
+prepare stmt1 from ' select a, b FROM t1 outer_table where
+ a = (select a from t1 where b = outer_table.b) and b=? ';
+execute stmt1 using @arg00;
+a b
+2 two
+set @arg00=2 ;
+select a, b FROM t1 outer_table where
+a = (select a from t1 where a = @arg00 and b = outer_table.b) and b='two' ;
+a b
+2 two
+prepare stmt1 from ' select a, b FROM t1 outer_table where
+ a = (select a from t1 where a = ? and b = outer_table.b) and b=''two'' ' ;
+execute stmt1 using @arg00;
+a b
+2 two
+set @arg00=2 ;
+select a, b FROM t1 outer_table where
+a = (select a from t1 where outer_table.a = @arg00 and a=2) and b='two' ;
+a b
+2 two
+prepare stmt1 from ' select a, b FROM t1 outer_table where
+ a = (select a from t1 where outer_table.a = ? and a=2) and b=''two'' ' ;
+execute stmt1 using @arg00;
+a b
+2 two
+set @arg00=1 ;
+set @arg01='two' ;
+set @arg02=2 ;
+set @arg03='two' ;
+select a, @arg00, b FROM t1 outer_table where
+b=@arg01 and a = (select @arg02 from t1 where outer_table.b = @arg03
+and outer_table.a=a ) ;
+a @arg00 b
+2 1 two
+prepare stmt1 from ' select a, ?, b FROM t1 outer_table where
+ b=? and a = (select ? from t1 where outer_table.b = ?
+ and outer_table.a=a ) ' ;
+execute stmt1 using @arg00, @arg01, @arg02, @arg03 ;
+a ? b
+2 1 two
+set @arg00=1 ;
+set @arg01=0 ;
+select a, @arg00
+from ( select a - @arg00 as a from t1 where a=@arg00 ) as t2
+where a=@arg01;
+a @arg00
+0 1
+prepare stmt1 from ' select a, ?
+ from ( select a - ? as a from t1 where a=? ) as t2
+ where a=? ';
+execute stmt1 using @arg00, @arg00, @arg00, @arg01 ;
+a ?
+0 1
+drop table if exists t2 ;
+create table t2 as select * from t1;
+prepare stmt1 from ' select a in (select a from t2) from t1 ' ;
+execute stmt1 ;
+a in (select a from t2)
+1
+1
+1
+1
+drop table if exists t5, t6, t7 ;
+create table t5 (a int , b int) ;
+create table t6 like t5 ;
+create table t7 like t5 ;
+insert into t5 values (0, 100), (1, 2), (1, 3), (2, 2), (2, 7),
+(2, -1), (3, 10) ;
+insert into t6 values (0, 0), (1, 1), (2, 1), (3, 1), (4, 1) ;
+insert into t7 values (3, 3), (2, 2), (1, 1) ;
+prepare stmt1 from ' select a, (select count(distinct t5.b) as sum from t5, t6
+ where t5.a=t6.a and t6.b > 0 and t5.a <= t7.b
+ group by t5.a order by sum limit 1) from t7 ' ;
+execute stmt1 ;
+a (select count(distinct t5.b) as sum from t5, t6
+ where t5.a=t6.a and t6.b > 0 and t5.a <= t7.b
+ group by t5.a order by sum limit 1)
+3 1
+2 2
+1 2
+execute stmt1 ;
+a (select count(distinct t5.b) as sum from t5, t6
+ where t5.a=t6.a and t6.b > 0 and t5.a <= t7.b
+ group by t5.a order by sum limit 1)
+3 1
+2 2
+1 2
+execute stmt1 ;
+a (select count(distinct t5.b) as sum from t5, t6
+ where t5.a=t6.a and t6.b > 0 and t5.a <= t7.b
+ group by t5.a order by sum limit 1)
+3 1
+2 2
+1 2
+drop table t5, t6, t7 ;
+drop table if exists t2 ;
+create table t2 as select * from t9;
+set @stmt= ' SELECT
+ (SELECT SUM(c1 + c12 + 0.0) FROM t2
+ where (t9.c2 - 0e-3) = t2.c2
+ GROUP BY t9.c15 LIMIT 1) as scalar_s,
+ exists (select 1.0e+0 from t2
+ where t2.c3 * 9.0000000000 = t9.c4) as exists_s,
+ c5 * 4 in (select c6 + 0.3e+1 from t2) as in_s,
+ (c7 - 4, c8 - 4) in (select c9 + 4.0, c10 + 40e-1 from t2) as in_row_s
+FROM t9,
+(select c25 x, c32 y from t2) tt WHERE x = c25 ' ;
+prepare stmt1 from @stmt ;
+execute stmt1 ;
+execute stmt1 ;
+set @stmt= concat('explain ',@stmt);
+prepare stmt1 from @stmt ;
+execute stmt1 ;
+execute stmt1 ;
+set @stmt= ' SELECT
+ (SELECT SUM(c1+c12+?) FROM t2 where (t9.c2-?)=t2.c2
+ GROUP BY t9.c15 LIMIT 1) as scalar_s,
+ exists (select ? from t2
+ where t2.c3*?=t9.c4) as exists_s,
+ c5*? in (select c6+? from t2) as in_s,
+ (c7-?, c8-?) in (select c9+?, c10+? from t2) as in_row_s
+FROM t9,
+(select c25 x, c32 y from t2) tt WHERE x =c25 ' ;
+set @arg00= 0.0 ;
+set @arg01= 0e-3 ;
+set @arg02= 1.0e+0 ;
+set @arg03= 9.0000000000 ;
+set @arg04= 4 ;
+set @arg05= 0.3e+1 ;
+set @arg06= 4 ;
+set @arg07= 4 ;
+set @arg08= 4.0 ;
+set @arg09= 40e-1 ;
+prepare stmt1 from @stmt ;
+execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04, @arg05, @arg06,
+@arg07, @arg08, @arg09 ;
+execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04, @arg05, @arg06,
+@arg07, @arg08, @arg09 ;
+set @stmt= concat('explain ',@stmt);
+prepare stmt1 from @stmt ;
+execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04, @arg05, @arg06,
+@arg07, @arg08, @arg09 ;
+execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04, @arg05, @arg06,
+@arg07, @arg08, @arg09 ;
+drop table t2 ;
+select 1 < (select a from t1) ;
+ERROR 21000: Subquery returns more than 1 row
+prepare stmt1 from ' select 1 < (select a from t1) ' ;
+execute stmt1 ;
+ERROR 21000: Subquery returns more than 1 row
+select 1 as my_col ;
+my_col
+1
+test_sequence
+------ union tests ------
+prepare stmt1 from ' select a FROM t1 where a=1
+ union distinct
+ select a FROM t1 where a=1 ';
+execute stmt1 ;
+a
+1
+execute stmt1 ;
+a
+1
+prepare stmt1 from ' select a FROM t1 where a=1
+ union all
+ select a FROM t1 where a=1 ';
+execute stmt1 ;
+a
+1
+1
+prepare stmt1 from ' SELECT 1, 2 union SELECT 1 ' ;
+ERROR 21000: The used SELECT statements have a different number of columns
+prepare stmt1 from ' SELECT 1 union SELECT 1, 2 ' ;
+ERROR 21000: The used SELECT statements have a different number of columns
+prepare stmt1 from ' SELECT * from t1 union SELECT 1 ' ;
+ERROR 21000: The used SELECT statements have a different number of columns
+prepare stmt1 from ' SELECT 1 union SELECT * from t1 ' ;
+ERROR 21000: The used SELECT statements have a different number of columns
+set @arg00=1 ;
+select @arg00 FROM t1 where a=1
+union distinct
+select 1 FROM t1 where a=1;
+@arg00
+1
+prepare stmt1 from ' select ? FROM t1 where a=1
+ union distinct
+ select 1 FROM t1 where a=1 ' ;
+execute stmt1 using @arg00;
+?
+1
+set @arg00=1 ;
+select 1 FROM t1 where a=1
+union distinct
+select @arg00 FROM t1 where a=1;
+1
+1
+prepare stmt1 from ' select 1 FROM t1 where a=1
+ union distinct
+ select ? FROM t1 where a=1 ' ;
+execute stmt1 using @arg00;
+1
+1
+set @arg00='a' ;
+select @arg00 FROM t1 where a=1
+union distinct
+select @arg00 FROM t1 where a=1;
+@arg00
+a
+prepare stmt1 from ' select ? FROM t1 where a=1
+ union distinct
+ select ? FROM t1 where a=1 ';
+execute stmt1 using @arg00, @arg00;
+?
+a
+prepare stmt1 from ' select ?
+ union distinct
+ select ? ';
+execute stmt1 using @arg00, @arg00;
+?
+a
+set @arg00='a' ;
+set @arg01=1 ;
+set @arg02='a' ;
+set @arg03=2 ;
+select @arg00 FROM t1 where a=@arg01
+union distinct
+select @arg02 FROM t1 where a=@arg03;
+@arg00
+a
+prepare stmt1 from ' select ? FROM t1 where a=?
+ union distinct
+ select ? FROM t1 where a=? ' ;
+execute stmt1 using @arg00, @arg01, @arg02, @arg03;
+?
+a
+set @arg00=1 ;
+prepare stmt1 from ' select sum(a) + 200, ? from t1
+union distinct
+select sum(a) + 200, 1 from t1
+group by b ' ;
+execute stmt1 using @arg00;
+sum(a) + 200 ?
+210 1
+204 1
+201 1
+203 1
+202 1
+set @Oporto='Oporto' ;
+set @Lisboa='Lisboa' ;
+set @0=0 ;
+set @1=1 ;
+set @2=2 ;
+set @3=3 ;
+set @4=4 ;
+select @Oporto,@Lisboa,@0,@1,@2,@3,@4 ;
+@Oporto @Lisboa @0 @1 @2 @3 @4
+Oporto Lisboa 0 1 2 3 4
+select sum(a) + 200 as the_sum, @Oporto as the_town from t1
+group by b
+union distinct
+select sum(a) + 200, @Lisboa from t1
+group by b ;
+the_sum the_town
+204 Oporto
+201 Oporto
+203 Oporto
+202 Oporto
+204 Lisboa
+201 Lisboa
+203 Lisboa
+202 Lisboa
+prepare stmt1 from ' select sum(a) + 200 as the_sum, ? as the_town from t1
+ group by b
+ union distinct
+ select sum(a) + 200, ? from t1
+ group by b ' ;
+execute stmt1 using @Oporto, @Lisboa;
+the_sum the_town
+204 Oporto
+201 Oporto
+203 Oporto
+202 Oporto
+204 Lisboa
+201 Lisboa
+203 Lisboa
+202 Lisboa
+select sum(a) + 200 as the_sum, @Oporto as the_town from t1
+where a > @1
+group by b
+union distinct
+select sum(a) + 200, @Lisboa from t1
+where a > @2
+group by b ;
+the_sum the_town
+204 Oporto
+203 Oporto
+202 Oporto
+204 Lisboa
+203 Lisboa
+prepare stmt1 from ' select sum(a) + 200 as the_sum, ? as the_town from t1
+ where a > ?
+ group by b
+ union distinct
+ select sum(a) + 200, ? from t1
+ where a > ?
+ group by b ' ;
+execute stmt1 using @Oporto, @1, @Lisboa, @2;
+the_sum the_town
+204 Oporto
+203 Oporto
+202 Oporto
+204 Lisboa
+203 Lisboa
+select sum(a) + 200 as the_sum, @Oporto as the_town from t1
+where a > @1
+group by b
+having avg(a) > @2
+union distinct
+select sum(a) + 200, @Lisboa from t1
+where a > @2
+group by b
+having avg(a) > @3;
+the_sum the_town
+204 Oporto
+203 Oporto
+204 Lisboa
+prepare stmt1 from ' select sum(a) + 200 as the_sum, ? as the_town from t1
+ where a > ?
+ group by b
+ having avg(a) > ?
+ union distinct
+ select sum(a) + 200, ? from t1
+ where a > ?
+ group by b
+ having avg(a) > ? ';
+execute stmt1 using @Oporto, @1, @2, @Lisboa, @2, @3;
+the_sum the_town
+204 Oporto
+203 Oporto
+204 Lisboa
+test_sequence
+------ explain select tests ------
+prepare stmt1 from ' explain select * from t9 ' ;
+execute stmt1;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def id 8 3 1 N 32929 0 63
+def select_type 253 19 6 N 1 31 8
+def table 253 64 2 Y 0 31 8
+def type 253 10 3 Y 0 31 8
+def possible_keys 253 4096 0 Y 0 31 8
+def key 253 64 0 Y 0 31 8
+def key_len 253 4096 0 Y 0 31 8
+def ref 253 1024 0 Y 0 31 8
+def rows 8 10 1 Y 32928 0 63
+def Extra 253 255 0 N 1 31 8
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t9 ALL NULL NULL NULL NULL 2
+drop table if exists t2 ;
+create table t2 (s varchar(25), fulltext(s)) TRANSACTIONAL= 0
+ENGINE = 'MARIA' ;
+insert into t2 values ('Gravedigger'), ('Greed'),('Hollow Dogs') ;
+commit ;
+prepare stmt1 from ' select s from t2 where match (s) against (?) ' ;
+set @arg00='Dogs' ;
+execute stmt1 using @arg00 ;
+s
+Hollow Dogs
+prepare stmt1 from ' SELECT s FROM t2
+where match (s) against (concat(?,''digger'')) ';
+set @arg00='Grave' ;
+execute stmt1 using @arg00 ;
+s
+Gravedigger
+drop table t2 ;
+test_sequence
+------ delete tests ------
+delete from t1 ;
+insert into t1 values (1,'one');
+insert into t1 values (2,'two');
+insert into t1 values (3,'three');
+insert into t1 values (4,'four');
+commit ;
+delete from t9 ;
+insert into t9
+set c1= 1, c2= 1, c3= 1, c4= 1, c5= 1, c6= 1, c7= 1, c8= 1, c9= 1,
+c10= 1, c11= 1, c12 = 1,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=true, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='one', c32= 'monday';
+insert into t9
+set c1= 9, c2= 9, c3= 9, c4= 9, c5= 9, c6= 9, c7= 9, c8= 9, c9= 9,
+c10= 9, c11= 9, c12 = 9,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=false, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday';
+commit ;
+prepare stmt1 from 'delete from t1 where a=2' ;
+execute stmt1;
+select a,b from t1 where a=2;
+a b
+execute stmt1;
+insert into t1 values(0,NULL);
+set @arg00=NULL;
+prepare stmt1 from 'delete from t1 where b=?' ;
+execute stmt1 using @arg00;
+select a,b from t1 where b is NULL ;
+a b
+0 NULL
+set @arg00='one';
+execute stmt1 using @arg00;
+select a,b from t1 where b=@arg00;
+a b
+prepare stmt1 from 'truncate table t1' ;
+test_sequence
+------ update tests ------
+delete from t1 ;
+insert into t1 values (1,'one');
+insert into t1 values (2,'two');
+insert into t1 values (3,'three');
+insert into t1 values (4,'four');
+commit ;
+delete from t9 ;
+insert into t9
+set c1= 1, c2= 1, c3= 1, c4= 1, c5= 1, c6= 1, c7= 1, c8= 1, c9= 1,
+c10= 1, c11= 1, c12 = 1,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=true, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='one', c32= 'monday';
+insert into t9
+set c1= 9, c2= 9, c3= 9, c4= 9, c5= 9, c6= 9, c7= 9, c8= 9, c9= 9,
+c10= 9, c11= 9, c12 = 9,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=false, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday';
+commit ;
+prepare stmt1 from 'update t1 set b=''a=two'' where a=2' ;
+execute stmt1;
+select a,b from t1 where a=2;
+a b
+2 a=two
+execute stmt1;
+select a,b from t1 where a=2;
+a b
+2 a=two
+set @arg00=NULL;
+prepare stmt1 from 'update t1 set b=? where a=2' ;
+execute stmt1 using @arg00;
+select a,b from t1 where a=2;
+a b
+2 NULL
+set @arg00='two';
+execute stmt1 using @arg00;
+select a,b from t1 where a=2;
+a b
+2 two
+set @arg00=2;
+prepare stmt1 from 'update t1 set b=NULL where a=?' ;
+execute stmt1 using @arg00;
+select a,b from t1 where a=@arg00;
+a b
+2 NULL
+update t1 set b='two' where a=@arg00;
+set @arg00=2000;
+execute stmt1 using @arg00;
+select a,b from t1 where a=@arg00;
+a b
+set @arg00=2;
+set @arg01=22;
+prepare stmt1 from 'update t1 set a=? where a=?' ;
+execute stmt1 using @arg00, @arg00;
+select a,b from t1 where a=@arg00;
+a b
+2 two
+execute stmt1 using @arg01, @arg00;
+select a,b from t1 where a=@arg01;
+a b
+22 two
+execute stmt1 using @arg00, @arg01;
+select a,b from t1 where a=@arg00;
+a b
+2 two
+set @arg00=NULL;
+set @arg01=2;
+execute stmt1 using @arg00, @arg01;
+ERROR 23000: Column 'a' cannot be null
+select a,b from t1 order by a;
+a b
+1 one
+2 two
+3 three
+4 four
+set @arg00=0;
+execute stmt1 using @arg01, @arg00;
+select a,b from t1 order by a;
+a b
+1 one
+2 two
+3 three
+4 four
+set @arg00=23;
+set @arg01='two';
+set @arg02=2;
+set @arg03='two';
+set @arg04=2;
+drop table if exists t2;
+create table t2 as select a,b from t1 ;
+prepare stmt1 from 'update t1 set a=? where b=?
+ and a in (select ? from t2
+ where b = ? or a = ?)';
+execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04 ;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Warnings: 0
+select a,b from t1 where a = @arg00 ;
+a b
+23 two
+prepare stmt1 from 'update t1 set a=? where b=?
+ and a not in (select ? from t2
+ where b = ? or a = ?)';
+execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Warnings: 0
+select a,b from t1 order by a ;
+a b
+1 one
+2 two
+3 three
+4 four
+drop table t2 ;
+create table t2
+(
+a int, b varchar(30),
+primary key(a)
+) engine = 'MARIA' ;
+insert into t2(a,b) select a, b from t1 ;
+prepare stmt1 from 'update t1 set a=? where b=?
+ and a in (select ? from t2
+ where b = ? or a = ?)';
+execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04 ;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Warnings: 0
+select a,b from t1 where a = @arg00 ;
+a b
+23 two
+prepare stmt1 from 'update t1 set a=? where b=?
+ and a not in (select ? from t2
+ where b = ? or a = ?)';
+execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ;
+affected rows: 1
+info: Rows matched: 1 Changed: 1 Warnings: 0
+select a,b from t1 order by a ;
+a b
+1 one
+2 two
+3 three
+4 four
+drop table t2 ;
+set @arg00=1;
+prepare stmt1 from 'update t1 set b=''bla''
+where a=2
+limit 1';
+execute stmt1 ;
+select a,b from t1 where b = 'bla' ;
+a b
+2 bla
+prepare stmt1 from 'update t1 set b=''bla'' where a=2 limit ?';
+execute stmt1 using @arg00;
+test_sequence
+------ insert tests ------
+delete from t1 ;
+insert into t1 values (1,'one');
+insert into t1 values (2,'two');
+insert into t1 values (3,'three');
+insert into t1 values (4,'four');
+commit ;
+delete from t9 ;
+insert into t9
+set c1= 1, c2= 1, c3= 1, c4= 1, c5= 1, c6= 1, c7= 1, c8= 1, c9= 1,
+c10= 1, c11= 1, c12 = 1,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=true, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='one', c32= 'monday';
+insert into t9
+set c1= 9, c2= 9, c3= 9, c4= 9, c5= 9, c6= 9, c7= 9, c8= 9, c9= 9,
+c10= 9, c11= 9, c12 = 9,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=false, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday';
+commit ;
+prepare stmt1 from 'insert into t1 values(5, ''five'' )';
+execute stmt1;
+select a,b from t1 where a = 5;
+a b
+5 five
+set @arg00='six' ;
+prepare stmt1 from 'insert into t1 values(6, ? )';
+execute stmt1 using @arg00;
+select a,b from t1 where b = @arg00;
+a b
+6 six
+execute stmt1 using @arg00;
+ERROR 23000: Duplicate entry '6' for key 'PRIMARY'
+set @arg00=NULL ;
+prepare stmt1 from 'insert into t1 values(0, ? )';
+execute stmt1 using @arg00;
+select a,b from t1 where b is NULL;
+a b
+0 NULL
+set @arg00=8 ;
+set @arg01='eight' ;
+prepare stmt1 from 'insert into t1 values(?, ? )';
+execute stmt1 using @arg00, @arg01 ;
+select a,b from t1 where b = @arg01;
+a b
+8 eight
+set @NULL= null ;
+set @arg00= 'abc' ;
+execute stmt1 using @NULL, @NULL ;
+ERROR 23000: Column 'a' cannot be null
+execute stmt1 using @NULL, @NULL ;
+ERROR 23000: Column 'a' cannot be null
+execute stmt1 using @NULL, @arg00 ;
+ERROR 23000: Column 'a' cannot be null
+execute stmt1 using @NULL, @arg00 ;
+ERROR 23000: Column 'a' cannot be null
+set @arg01= 10000 + 2 ;
+execute stmt1 using @arg01, @arg00 ;
+set @arg01= 10000 + 1 ;
+execute stmt1 using @arg01, @arg00 ;
+select * from t1 where a > 10000 order by a ;
+a b
+10001 abc
+10002 abc
+delete from t1 where a > 10000 ;
+set @arg01= 10000 + 2 ;
+execute stmt1 using @arg01, @NULL ;
+set @arg01= 10000 + 1 ;
+execute stmt1 using @arg01, @NULL ;
+select * from t1 where a > 10000 order by a ;
+a b
+10001 NULL
+10002 NULL
+delete from t1 where a > 10000 ;
+set @arg01= 10000 + 10 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 9 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 8 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 7 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 6 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 5 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 4 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 3 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 2 ;
+execute stmt1 using @arg01, @arg01 ;
+set @arg01= 10000 + 1 ;
+execute stmt1 using @arg01, @arg01 ;
+select * from t1 where a > 10000 order by a ;
+a b
+10001 10001
+10002 10002
+10003 10003
+10004 10004
+10005 10005
+10006 10006
+10007 10007
+10008 10008
+10009 10009
+10010 10010
+delete from t1 where a > 10000 ;
+set @arg00=81 ;
+set @arg01='8-1' ;
+set @arg02=82 ;
+set @arg03='8-2' ;
+prepare stmt1 from 'insert into t1 values(?,?),(?,?)';
+execute stmt1 using @arg00, @arg01, @arg02, @arg03 ;
+select a,b from t1 where a in (@arg00,@arg02) ;
+a b
+81 8-1
+82 8-2
+set @arg00=9 ;
+set @arg01='nine' ;
+prepare stmt1 from 'insert into t1 set a=?, b=? ';
+execute stmt1 using @arg00, @arg01 ;
+select a,b from t1 where a = @arg00 ;
+a b
+9 nine
+set @arg00=6 ;
+set @arg01=1 ;
+prepare stmt1 from 'insert into t1 set a=?, b=''sechs''
+ on duplicate key update a=a + ?, b=concat(b,''modified'') ';
+execute stmt1 using @arg00, @arg01;
+select * from t1 order by a;
+a b
+0 NULL
+1 one
+2 two
+3 three
+4 four
+5 five
+7 sixmodified
+8 eight
+9 nine
+81 8-1
+82 8-2
+set @arg00=81 ;
+set @arg01=1 ;
+execute stmt1 using @arg00, @arg01;
+ERROR 23000: Duplicate entry '82' for key 'PRIMARY'
+drop table if exists t2 ;
+create table t2 (id int auto_increment primary key)
+ENGINE= 'MARIA' ;
+prepare stmt1 from ' select last_insert_id() ' ;
+insert into t2 values (NULL) ;
+execute stmt1 ;
+last_insert_id()
+1
+insert into t2 values (NULL) ;
+execute stmt1 ;
+last_insert_id()
+2
+drop table t2 ;
+set @1000=1000 ;
+set @x1000_2="x1000_2" ;
+set @x1000_3="x1000_3" ;
+set @x1000="x1000" ;
+set @1100=1100 ;
+set @x1100="x1100" ;
+set @100=100 ;
+set @updated="updated" ;
+insert into t1 values(1000,'x1000_1') ;
+insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3)
+on duplicate key update a = a + @100, b = concat(b,@updated) ;
+select a,b from t1 where a >= 1000 order by a ;
+a b
+1000 x1000_3
+1100 x1000_1updated
+delete from t1 where a >= 1000 ;
+insert into t1 values(1000,'x1000_1') ;
+prepare stmt1 from ' insert into t1 values(?,?),(?,?)
+ on duplicate key update a = a + ?, b = concat(b,?) ';
+execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ;
+select a,b from t1 where a >= 1000 order by a ;
+a b
+1000 x1000_3
+1100 x1000_1updated
+delete from t1 where a >= 1000 ;
+insert into t1 values(1000,'x1000_1') ;
+execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ;
+select a,b from t1 where a >= 1000 order by a ;
+a b
+1200 x1000_1updatedupdated
+delete from t1 where a >= 1000 ;
+prepare stmt1 from ' replace into t1 (a,b) select 100, ''hundred'' ';
+execute stmt1;
+execute stmt1;
+execute stmt1;
+test_sequence
+------ multi table tests ------
+delete from t1 ;
+delete from t9 ;
+insert into t1(a,b) values (1, 'one'), (2, 'two'), (3, 'three') ;
+insert into t9 (c1,c21)
+values (1, 'one'), (2, 'two'), (3, 'three') ;
+prepare stmt_delete from " delete t1, t9
+ from t1, t9 where t1.a=t9.c1 and t1.b='updated' ";
+prepare stmt_update from " update t1, t9
+ set t1.b='updated', t9.c21='updated'
+ where t1.a=t9.c1 and t1.a=? ";
+prepare stmt_select1 from " select a, b from t1 order by a" ;
+prepare stmt_select2 from " select c1, c21 from t9 order by c1" ;
+set @arg00= 1 ;
+execute stmt_update using @arg00 ;
+execute stmt_delete ;
+execute stmt_select1 ;
+a b
+2 two
+3 three
+execute stmt_select2 ;
+c1 c21
+2 two
+3 three
+set @arg00= @arg00 + 1 ;
+execute stmt_update using @arg00 ;
+execute stmt_delete ;
+execute stmt_select1 ;
+a b
+3 three
+execute stmt_select2 ;
+c1 c21
+3 three
+set @arg00= @arg00 + 1 ;
+execute stmt_update using @arg00 ;
+execute stmt_delete ;
+execute stmt_select1 ;
+a b
+execute stmt_select2 ;
+c1 c21
+set @arg00= @arg00 + 1 ;
+delete from t1 ;
+insert into t1 values (1,'one');
+insert into t1 values (2,'two');
+insert into t1 values (3,'three');
+insert into t1 values (4,'four');
+commit ;
+delete from t9 ;
+insert into t9
+set c1= 1, c2= 1, c3= 1, c4= 1, c5= 1, c6= 1, c7= 1, c8= 1, c9= 1,
+c10= 1, c11= 1, c12 = 1,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=true, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='one', c32= 'monday';
+insert into t9
+set c1= 9, c2= 9, c3= 9, c4= 9, c5= 9, c6= 9, c7= 9, c8= 9, c9= 9,
+c10= 9, c11= 9, c12 = 9,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=false, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday';
+commit ;
+insert into t1 values(0,NULL) ;
+set @duplicate='duplicate ' ;
+set @1000=1000 ;
+set @5=5 ;
+select a,b from t1 where a < 5 order by a ;
+a b
+0 NULL
+1 one
+2 two
+3 three
+4 four
+insert into t1 select a + @1000, concat(@duplicate,b) from t1
+where a < @5 ;
+affected rows: 5
+info: Records: 5 Duplicates: 0 Warnings: 0
+select a,b from t1 where a >= 1000 order by a ;
+a b
+1000 NULL
+1001 duplicate one
+1002 duplicate two
+1003 duplicate three
+1004 duplicate four
+delete from t1 where a >= 1000 ;
+prepare stmt1 from ' insert into t1 select a + ?, concat(?,b) from t1
+where a < ? ' ;
+execute stmt1 using @1000, @duplicate, @5;
+affected rows: 5
+info: Records: 5 Duplicates: 0 Warnings: 0
+select a,b from t1 where a >= 1000 order by a ;
+a b
+1000 NULL
+1001 duplicate one
+1002 duplicate two
+1003 duplicate three
+1004 duplicate four
+delete from t1 where a >= 1000 ;
+set @1=1 ;
+set @2=2 ;
+set @100=100 ;
+set @float=1.00;
+set @five='five' ;
+drop table if exists t2;
+create table t2 like t1 ;
+insert into t2 (b,a)
+select @duplicate, sum(first.a) from t1 first, t1 second
+where first.a <> @5 and second.b = first.b
+and second.b <> @five
+group by second.b
+having sum(second.a) > @2
+union
+select b, a + @100 from t1
+where (a,b) in ( select sqrt(a+@1)+CAST(@float AS signed),b
+from t1);
+affected rows: 3
+info: Records: 3 Duplicates: 0 Warnings: 0
+select a,b from t2 order by a ;
+a b
+3 duplicate
+4 duplicate
+103 three
+delete from t2 ;
+prepare stmt1 from ' insert into t2 (b,a)
+select ?, sum(first.a)
+ from t1 first, t1 second
+ where first.a <> ? and second.b = first.b and second.b <> ?
+ group by second.b
+ having sum(second.a) > ?
+union
+select b, a + ? from t1
+ where (a,b) in ( select sqrt(a+?)+CAST(? AS signed),b
+ from t1 ) ' ;
+execute stmt1 using @duplicate, @5, @five, @2, @100, @1, @float ;
+affected rows: 3
+info: Records: 3 Duplicates: 0 Warnings: 0
+select a,b from t2 order by a ;
+a b
+3 duplicate
+4 duplicate
+103 three
+drop table t2;
+drop table if exists t5 ;
+set @arg01= 8;
+set @arg02= 8.0;
+set @arg03= 80.00000000000e-1;
+set @arg04= 'abc' ;
+set @arg05= CAST('abc' as binary) ;
+set @arg06= '1991-08-05' ;
+set @arg07= CAST('1991-08-05' as date);
+set @arg08= '1991-08-05 01:01:01' ;
+set @arg09= CAST('1991-08-05 01:01:01' as datetime) ;
+set @arg10= unix_timestamp('1991-01-01 01:01:01');
+set @arg11= YEAR('1991-01-01 01:01:01');
+set @arg12= 8 ;
+set @arg12= NULL ;
+set @arg13= 8.0 ;
+set @arg13= NULL ;
+set @arg14= 'abc';
+set @arg14= NULL ;
+set @arg15= CAST('abc' as binary) ;
+set @arg15= NULL ;
+create table t5 engine = MyISAM as select
+8 as const01, @arg01 as param01,
+8.0 as const02, @arg02 as param02,
+80.00000000000e-1 as const03, @arg03 as param03,
+'abc' as const04, @arg04 as param04,
+CAST('abc' as binary) as const05, @arg05 as param05,
+'1991-08-05' as const06, @arg06 as param06,
+CAST('1991-08-05' as date) as const07, @arg07 as param07,
+'1991-08-05 01:01:01' as const08, @arg08 as param08,
+CAST('1991-08-05 01:01:01' as datetime) as const09, @arg09 as param09,
+unix_timestamp('1991-01-01 01:01:01') as const10, @arg10 as param10,
+YEAR('1991-01-01 01:01:01') as const11, @arg11 as param11,
+NULL as const12, @arg12 as param12,
+@arg13 as param13,
+@arg14 as param14,
+@arg15 as param15;
+show create table t5 ;
+Table Create Table
+t5 CREATE TABLE `t5` (
+ `const01` int(1) NOT NULL DEFAULT '0',
+ `param01` bigint(20) DEFAULT NULL,
+ `const02` decimal(2,1) NOT NULL DEFAULT '0.0',
+ `param02` decimal(65,30) DEFAULT NULL,
+ `const03` double NOT NULL DEFAULT '0',
+ `param03` double DEFAULT NULL,
+ `const04` varchar(3) NOT NULL DEFAULT '',
+ `param04` longtext,
+ `const05` varbinary(3) NOT NULL DEFAULT '',
+ `param05` longblob,
+ `const06` varchar(10) NOT NULL DEFAULT '',
+ `param06` longtext,
+ `const07` date DEFAULT NULL,
+ `param07` longblob,
+ `const08` varchar(19) NOT NULL DEFAULT '',
+ `param08` longtext,
+ `const09` datetime DEFAULT NULL,
+ `param09` longblob,
+ `const10` int(10) NOT NULL DEFAULT '0',
+ `param10` bigint(20) DEFAULT NULL,
+ `const11` int(4) DEFAULT NULL,
+ `param11` bigint(20) DEFAULT NULL,
+ `const12` binary(0) DEFAULT NULL,
+ `param12` bigint(20) DEFAULT NULL,
+ `param13` decimal(65,30) DEFAULT NULL,
+ `param14` longtext,
+ `param15` longblob
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+select * from t5 ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t5 t5 const01 const01 3 1 1 N 32769 0 63
+def test t5 t5 param01 param01 8 20 1 Y 32768 0 63
+def test t5 t5 const02 const02 246 4 3 N 1 1 63
+def test t5 t5 param02 param02 246 67 32 Y 0 30 63
+def test t5 t5 const03 const03 5 17 1 N 32769 31 63
+def test t5 t5 param03 param03 5 23 1 Y 32768 31 63
+def test t5 t5 const04 const04 253 3 3 N 1 0 8
+def test t5 t5 param04 param04 252 4294967295 3 Y 16 0 8
+def test t5 t5 const05 const05 253 3 3 N 129 0 63
+def test t5 t5 param05 param05 252 4294967295 3 Y 144 0 63
+def test t5 t5 const06 const06 253 10 10 N 1 0 8
+def test t5 t5 param06 param06 252 4294967295 10 Y 16 0 8
+def test t5 t5 const07 const07 10 10 10 Y 128 0 63
+def test t5 t5 param07 param07 252 4294967295 10 Y 144 0 63
+def test t5 t5 const08 const08 253 19 19 N 1 0 8
+def test t5 t5 param08 param08 252 4294967295 19 Y 16 0 8
+def test t5 t5 const09 const09 12 19 19 Y 128 0 63
+def test t5 t5 param09 param09 252 4294967295 19 Y 144 0 63
+def test t5 t5 const10 const10 3 10 9 N 32769 0 63
+def test t5 t5 param10 param10 8 20 9 Y 32768 0 63
+def test t5 t5 const11 const11 3 4 4 Y 32768 0 63
+def test t5 t5 param11 param11 8 20 4 Y 32768 0 63
+def test t5 t5 const12 const12 254 0 0 Y 128 0 63
+def test t5 t5 param12 param12 8 20 0 Y 32768 0 63
+def test t5 t5 param13 param13 246 67 0 Y 0 30 63
+def test t5 t5 param14 param14 252 4294967295 0 Y 16 0 8
+def test t5 t5 param15 param15 252 4294967295 0 Y 144 0 63
+const01 8
+param01 8
+const02 8.0
+param02 8.000000000000000000000000000000
+const03 8
+param03 8
+const04 abc
+param04 abc
+const05 abc
+param05 abc
+const06 1991-08-05
+param06 1991-08-05
+const07 1991-08-05
+param07 1991-08-05
+const08 1991-08-05 01:01:01
+param08 1991-08-05 01:01:01
+const09 1991-08-05 01:01:01
+param09 1991-08-05 01:01:01
+const10 662680861
+param10 662680861
+const11 1991
+param11 1991
+const12 NULL
+param12 NULL
+param13 NULL
+param14 NULL
+param15 NULL
+drop table t5 ;
+test_sequence
+------ data type conversion tests ------
+delete from t1 ;
+insert into t1 values (1,'one');
+insert into t1 values (2,'two');
+insert into t1 values (3,'three');
+insert into t1 values (4,'four');
+commit ;
+delete from t9 ;
+insert into t9
+set c1= 1, c2= 1, c3= 1, c4= 1, c5= 1, c6= 1, c7= 1, c8= 1, c9= 1,
+c10= 1, c11= 1, c12 = 1,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=true, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='one', c32= 'monday';
+insert into t9
+set c1= 9, c2= 9, c3= 9, c4= 9, c5= 9, c6= 9, c7= 9, c8= 9, c9= 9,
+c10= 9, c11= 9, c12 = 9,
+c13= '2004-02-29', c14= '2004-02-29 11:11:11', c15= '2004-02-29 11:11:11',
+c16= '11:11:11', c17= '2004',
+c18= 1, c19=false, c20= 'a', c21= '123456789a',
+c22= '123456789a123456789b123456789c', c23= 'tinyblob', c24= 'tinytext',
+c25= 'blob', c26= 'text', c27= 'mediumblob', c28= 'mediumtext',
+c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday';
+commit ;
+insert into t9 set c1= 0, c15= '1991-01-01 01:01:01' ;
+select * from t9 order by c1 ;
+c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32
+0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday
+test_sequence
+------ select @parameter:= column ------
+prepare full_info from "select @arg01, @arg02, @arg03, @arg04,
+ @arg05, @arg06, @arg07, @arg08,
+ @arg09, @arg10, @arg11, @arg12,
+ @arg13, @arg14, @arg15, @arg16,
+ @arg17, @arg18, @arg19, @arg20,
+ @arg21, @arg22, @arg23, @arg24,
+ @arg25, @arg26, @arg27, @arg28,
+ @arg29, @arg30, @arg31, @arg32" ;
+select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
+@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
+@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
+@arg13:= c13, @arg14:= c14, @arg15:= c15, @arg16:= c16,
+@arg17:= c17, @arg18:= c18, @arg19:= c19, @arg20:= c20,
+@arg21:= c21, @arg22:= c22, @arg23:= c23, @arg24:= c24,
+@arg25:= c25, @arg26:= c26, @arg27:= c27, @arg28:= c28,
+@arg29:= c29, @arg30:= c30, @arg31:= c31, @arg32:= c32
+from t9 where c1= 1 ;
+@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 1 Y 32896 0 63
+def @arg03 8 20 1 Y 32896 0 63
+def @arg04 8 20 1 Y 32896 0 63
+def @arg05 8 20 1 Y 32896 0 63
+def @arg06 8 20 1 Y 32896 0 63
+def @arg07 5 23 1 Y 32896 31 63
+def @arg08 5 23 1 Y 32896 31 63
+def @arg09 5 23 1 Y 32896 31 63
+def @arg10 5 23 1 Y 32896 31 63
+def @arg11 246 83 6 Y 128 30 63
+def @arg12 246 83 6 Y 128 30 63
+def @arg13 251 16777216 10 Y 128 31 63
+def @arg14 251 16777216 19 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 8 Y 128 31 63
+def @arg17 8 20 4 Y 32928 0 63
+def @arg18 8 20 1 Y 32896 0 63
+def @arg19 8 20 1 Y 32896 0 63
+def @arg20 251 16777216 1 Y 0 31 8
+def @arg21 251 16777216 10 Y 0 31 8
+def @arg22 251 16777216 30 Y 0 31 8
+def @arg23 251 16777216 8 Y 128 31 63
+def @arg24 251 16777216 8 Y 0 31 8
+def @arg25 251 16777216 4 Y 128 31 63
+def @arg26 251 16777216 4 Y 0 31 8
+def @arg27 251 16777216 10 Y 128 31 63
+def @arg28 251 16777216 10 Y 0 31 8
+def @arg29 251 16777216 8 Y 128 31 63
+def @arg30 251 16777216 8 Y 0 31 8
+def @arg31 251 16777216 3 Y 0 31 8
+def @arg32 251 16777216 6 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
+@arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
+@arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
+@arg13:= c13, @arg14:= c14, @arg15:= c15, @arg16:= c16,
+@arg17:= c17, @arg18:= c18, @arg19:= c19, @arg20:= c20,
+@arg21:= c21, @arg22:= c22, @arg23:= c23, @arg24:= c24,
+@arg25:= c25, @arg26:= c26, @arg27:= c27, @arg28:= c28,
+@arg29:= c29, @arg30:= c30, @arg31:= c31, @arg32:= c32
+from t9 where c1= 0 ;
+@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
+0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 0 Y 32896 0 63
+def @arg03 8 20 0 Y 32896 0 63
+def @arg04 8 20 0 Y 32896 0 63
+def @arg05 8 20 0 Y 32896 0 63
+def @arg06 8 20 0 Y 32896 0 63
+def @arg07 5 23 0 Y 32896 31 63
+def @arg08 5 23 0 Y 32896 31 63
+def @arg09 5 23 0 Y 32896 31 63
+def @arg10 5 23 0 Y 32896 31 63
+def @arg11 246 83 0 Y 128 30 63
+def @arg12 246 83 0 Y 128 30 63
+def @arg13 251 16777216 0 Y 128 31 63
+def @arg14 251 16777216 0 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 0 Y 128 31 63
+def @arg17 8 20 0 Y 32928 0 63
+def @arg18 8 20 0 Y 32896 0 63
+def @arg19 8 20 0 Y 32896 0 63
+def @arg20 251 16777216 0 Y 0 31 8
+def @arg21 251 16777216 0 Y 0 31 8
+def @arg22 251 16777216 0 Y 0 31 8
+def @arg23 251 16777216 0 Y 128 31 63
+def @arg24 251 16777216 0 Y 0 31 8
+def @arg25 251 16777216 0 Y 128 31 63
+def @arg26 251 16777216 0 Y 0 31 8
+def @arg27 251 16777216 0 Y 128 31 63
+def @arg28 251 16777216 0 Y 0 31 8
+def @arg29 251 16777216 0 Y 128 31 63
+def @arg30 251 16777216 0 Y 0 31 8
+def @arg31 251 16777216 0 Y 0 31 8
+def @arg32 251 16777216 0 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+prepare stmt1 from "select
+ @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4,
+ @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8,
+ @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12,
+ @arg13:= c13, @arg14:= c14, @arg15:= c15, @arg16:= c16,
+ @arg17:= c17, @arg18:= c18, @arg19:= c19, @arg20:= c20,
+ @arg21:= c21, @arg22:= c22, @arg23:= c23, @arg24:= c24,
+ @arg25:= c25, @arg26:= c26, @arg27:= c27, @arg28:= c28,
+ @arg29:= c29, @arg30:= c30, @arg31:= c31, @arg32:= c32
+from t9 where c1= ?" ;
+set @my_key= 1 ;
+execute stmt1 using @my_key ;
+@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 1 Y 32896 0 63
+def @arg03 8 20 1 Y 32896 0 63
+def @arg04 8 20 1 Y 32896 0 63
+def @arg05 8 20 1 Y 32896 0 63
+def @arg06 8 20 1 Y 32896 0 63
+def @arg07 5 23 1 Y 32896 31 63
+def @arg08 5 23 1 Y 32896 31 63
+def @arg09 5 23 1 Y 32896 31 63
+def @arg10 5 23 1 Y 32896 31 63
+def @arg11 246 83 6 Y 128 30 63
+def @arg12 246 83 6 Y 128 30 63
+def @arg13 251 16777216 10 Y 128 31 63
+def @arg14 251 16777216 19 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 8 Y 128 31 63
+def @arg17 8 20 4 Y 32928 0 63
+def @arg18 8 20 1 Y 32896 0 63
+def @arg19 8 20 1 Y 32896 0 63
+def @arg20 251 16777216 1 Y 0 31 8
+def @arg21 251 16777216 10 Y 0 31 8
+def @arg22 251 16777216 30 Y 0 31 8
+def @arg23 251 16777216 8 Y 128 31 63
+def @arg24 251 16777216 8 Y 0 31 8
+def @arg25 251 16777216 4 Y 128 31 63
+def @arg26 251 16777216 4 Y 0 31 8
+def @arg27 251 16777216 10 Y 128 31 63
+def @arg28 251 16777216 10 Y 0 31 8
+def @arg29 251 16777216 8 Y 128 31 63
+def @arg30 251 16777216 8 Y 0 31 8
+def @arg31 251 16777216 3 Y 0 31 8
+def @arg32 251 16777216 6 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+set @my_key= 0 ;
+execute stmt1 using @my_key ;
+@arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32
+0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 0 Y 32896 0 63
+def @arg03 8 20 0 Y 32896 0 63
+def @arg04 8 20 0 Y 32896 0 63
+def @arg05 8 20 0 Y 32896 0 63
+def @arg06 8 20 0 Y 32896 0 63
+def @arg07 5 23 0 Y 32896 31 63
+def @arg08 5 23 0 Y 32896 31 63
+def @arg09 5 23 0 Y 32896 31 63
+def @arg10 5 23 0 Y 32896 31 63
+def @arg11 246 83 0 Y 128 30 63
+def @arg12 246 83 0 Y 128 30 63
+def @arg13 251 16777216 0 Y 128 31 63
+def @arg14 251 16777216 0 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 0 Y 128 31 63
+def @arg17 8 20 0 Y 32928 0 63
+def @arg18 8 20 0 Y 32896 0 63
+def @arg19 8 20 0 Y 32896 0 63
+def @arg20 251 16777216 0 Y 0 31 8
+def @arg21 251 16777216 0 Y 0 31 8
+def @arg22 251 16777216 0 Y 0 31 8
+def @arg23 251 16777216 0 Y 128 31 63
+def @arg24 251 16777216 0 Y 0 31 8
+def @arg25 251 16777216 0 Y 128 31 63
+def @arg26 251 16777216 0 Y 0 31 8
+def @arg27 251 16777216 0 Y 128 31 63
+def @arg28 251 16777216 0 Y 0 31 8
+def @arg29 251 16777216 0 Y 128 31 63
+def @arg30 251 16777216 0 Y 0 31 8
+def @arg31 251 16777216 0 Y 0 31 8
+def @arg32 251 16777216 0 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+prepare stmt1 from "select ? := c1 from t9 where c1= 1" ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ':= c1 from t9 where c1= 1' at line 1
+test_sequence
+------ select column, .. into @parm,.. ------
+select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
+c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
+c25, c26, c27, c28, c29, c30, c31, c32
+into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
+@arg09, @arg10, @arg11, @arg12, @arg13, @arg14, @arg15, @arg16,
+@arg17, @arg18, @arg19, @arg20, @arg21, @arg22, @arg23, @arg24,
+@arg25, @arg26, @arg27, @arg28, @arg29, @arg30, @arg31, @arg32
+from t9 where c1= 1 ;
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 1 Y 32896 0 63
+def @arg03 8 20 1 Y 32896 0 63
+def @arg04 8 20 1 Y 32896 0 63
+def @arg05 8 20 1 Y 32896 0 63
+def @arg06 8 20 1 Y 32896 0 63
+def @arg07 5 23 1 Y 32896 31 63
+def @arg08 5 23 1 Y 32896 31 63
+def @arg09 5 23 1 Y 32896 31 63
+def @arg10 5 23 1 Y 32896 31 63
+def @arg11 246 83 6 Y 128 30 63
+def @arg12 246 83 6 Y 128 30 63
+def @arg13 251 16777216 10 Y 128 31 63
+def @arg14 251 16777216 19 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 8 Y 128 31 63
+def @arg17 8 20 4 Y 32928 0 63
+def @arg18 8 20 1 Y 32896 0 63
+def @arg19 8 20 1 Y 32896 0 63
+def @arg20 251 16777216 1 Y 0 31 8
+def @arg21 251 16777216 10 Y 0 31 8
+def @arg22 251 16777216 30 Y 0 31 8
+def @arg23 251 16777216 8 Y 128 31 63
+def @arg24 251 16777216 8 Y 0 31 8
+def @arg25 251 16777216 4 Y 128 31 63
+def @arg26 251 16777216 4 Y 0 31 8
+def @arg27 251 16777216 10 Y 128 31 63
+def @arg28 251 16777216 10 Y 0 31 8
+def @arg29 251 16777216 8 Y 128 31 63
+def @arg30 251 16777216 8 Y 0 31 8
+def @arg31 251 16777216 3 Y 0 31 8
+def @arg32 251 16777216 6 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
+c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
+c25, c26, c27, c28, c29, c30, c31, c32
+into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
+@arg09, @arg10, @arg11, @arg12, @arg13, @arg14, @arg15, @arg16,
+@arg17, @arg18, @arg19, @arg20, @arg21, @arg22, @arg23, @arg24,
+@arg25, @arg26, @arg27, @arg28, @arg29, @arg30, @arg31, @arg32
+from t9 where c1= 0 ;
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 0 Y 32896 0 63
+def @arg03 8 20 0 Y 32896 0 63
+def @arg04 8 20 0 Y 32896 0 63
+def @arg05 8 20 0 Y 32896 0 63
+def @arg06 8 20 0 Y 32896 0 63
+def @arg07 5 23 0 Y 32896 31 63
+def @arg08 5 23 0 Y 32896 31 63
+def @arg09 5 23 0 Y 32896 31 63
+def @arg10 5 23 0 Y 32896 31 63
+def @arg11 246 83 0 Y 128 30 63
+def @arg12 246 83 0 Y 128 30 63
+def @arg13 251 16777216 0 Y 128 31 63
+def @arg14 251 16777216 0 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 0 Y 128 31 63
+def @arg17 8 20 0 Y 32928 0 63
+def @arg18 8 20 0 Y 32896 0 63
+def @arg19 8 20 0 Y 32896 0 63
+def @arg20 251 16777216 0 Y 0 31 8
+def @arg21 251 16777216 0 Y 0 31 8
+def @arg22 251 16777216 0 Y 0 31 8
+def @arg23 251 16777216 0 Y 128 31 63
+def @arg24 251 16777216 0 Y 0 31 8
+def @arg25 251 16777216 0 Y 128 31 63
+def @arg26 251 16777216 0 Y 0 31 8
+def @arg27 251 16777216 0 Y 128 31 63
+def @arg28 251 16777216 0 Y 0 31 8
+def @arg29 251 16777216 0 Y 128 31 63
+def @arg30 251 16777216 0 Y 0 31 8
+def @arg31 251 16777216 0 Y 0 31 8
+def @arg32 251 16777216 0 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+prepare stmt1 from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12,
+ c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24,
+ c25, c26, c27, c28, c29, c30, c31, c32
+into @arg01, @arg02, @arg03, @arg04, @arg05, @arg06, @arg07, @arg08,
+ @arg09, @arg10, @arg11, @arg12, @arg13, @arg14, @arg15, @arg16,
+ @arg17, @arg18, @arg19, @arg20, @arg21, @arg22, @arg23, @arg24,
+ @arg25, @arg26, @arg27, @arg28, @arg29, @arg30, @arg31, @arg32
+from t9 where c1= ?" ;
+set @my_key= 1 ;
+execute stmt1 using @my_key ;
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 1 Y 32896 0 63
+def @arg03 8 20 1 Y 32896 0 63
+def @arg04 8 20 1 Y 32896 0 63
+def @arg05 8 20 1 Y 32896 0 63
+def @arg06 8 20 1 Y 32896 0 63
+def @arg07 5 23 1 Y 32896 31 63
+def @arg08 5 23 1 Y 32896 31 63
+def @arg09 5 23 1 Y 32896 31 63
+def @arg10 5 23 1 Y 32896 31 63
+def @arg11 246 83 6 Y 128 30 63
+def @arg12 246 83 6 Y 128 30 63
+def @arg13 251 16777216 10 Y 128 31 63
+def @arg14 251 16777216 19 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 8 Y 128 31 63
+def @arg17 8 20 4 Y 32928 0 63
+def @arg18 8 20 1 Y 32896 0 63
+def @arg19 8 20 1 Y 32896 0 63
+def @arg20 251 16777216 1 Y 0 31 8
+def @arg21 251 16777216 10 Y 0 31 8
+def @arg22 251 16777216 30 Y 0 31 8
+def @arg23 251 16777216 8 Y 128 31 63
+def @arg24 251 16777216 8 Y 0 31 8
+def @arg25 251 16777216 4 Y 128 31 63
+def @arg26 251 16777216 4 Y 0 31 8
+def @arg27 251 16777216 10 Y 128 31 63
+def @arg28 251 16777216 10 Y 0 31 8
+def @arg29 251 16777216 8 Y 128 31 63
+def @arg30 251 16777216 8 Y 0 31 8
+def @arg31 251 16777216 3 Y 0 31 8
+def @arg32 251 16777216 6 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday
+set @my_key= 0 ;
+execute stmt1 using @my_key ;
+execute full_info ;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def @arg01 8 20 1 Y 32896 0 63
+def @arg02 8 20 0 Y 32896 0 63
+def @arg03 8 20 0 Y 32896 0 63
+def @arg04 8 20 0 Y 32896 0 63
+def @arg05 8 20 0 Y 32896 0 63
+def @arg06 8 20 0 Y 32896 0 63
+def @arg07 5 23 0 Y 32896 31 63
+def @arg08 5 23 0 Y 32896 31 63
+def @arg09 5 23 0 Y 32896 31 63
+def @arg10 5 23 0 Y 32896 31 63
+def @arg11 246 83 0 Y 128 30 63
+def @arg12 246 83 0 Y 128 30 63
+def @arg13 251 16777216 0 Y 128 31 63
+def @arg14 251 16777216 0 Y 128 31 63
+def @arg15 251 16777216 19 Y 128 31 63
+def @arg16 251 16777216 0 Y 128 31 63
+def @arg17 8 20 0 Y 32928 0 63
+def @arg18 8 20 0 Y 32896 0 63
+def @arg19 8 20 0 Y 32896 0 63
+def @arg20 251 16777216 0 Y 0 31 8
+def @arg21 251 16777216 0 Y 0 31 8
+def @arg22 251 16777216 0 Y 0 31 8
+def @arg23 251 16777216 0 Y 128 31 63
+def @arg24 251 16777216 0 Y 0 31 8
+def @arg25 251 16777216 0 Y 128 31 63
+def @arg26 251 16777216 0 Y 0 31 8
+def @arg27 251 16777216 0 Y 128 31 63
+def @arg28 251 16777216 0 Y 0 31 8
+def @arg29 251 16777216 0 Y 128 31 63
+def @arg30 251 16777216 0 Y 0 31 8
+def @arg31 251 16777216 0 Y 0 31 8
+def @arg32 251 16777216 0 Y 0 31 8
+@arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32
+0 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1991-01-01 01:01:01 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+prepare stmt1 from "select c1 into ? from t9 where c1= 1" ;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t9 where c1= 1' at line 1
+test_sequence
+-- insert into numeric columns --
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 ) ;
+set @arg00= 21 ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ) ;
+prepare stmt1 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22 )" ;
+execute stmt1 ;
+set @arg00= 23;
+prepare stmt2 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+execute stmt2 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0,
+30.0, 30.0, 30.0 ) ;
+set @arg00= 31.0 ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ) ;
+prepare stmt1 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( 32.0, 32.0, 32.0, 32.0, 32.0, 32.0, 32.0, 32.0,
+ 32.0, 32.0, 32.0 )" ;
+execute stmt1 ;
+set @arg00= 33.0;
+prepare stmt2 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+execute stmt2 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( '40', '40', '40', '40', '40', '40', '40', '40',
+'40', '40', '40' ) ;
+set @arg00= '41' ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ) ;
+prepare stmt1 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( '42', '42', '42', '42', '42', '42', '42', '42',
+ '42', '42', '42' )" ;
+execute stmt1 ;
+set @arg00= '43';
+prepare stmt2 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+execute stmt2 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( CAST('50' as binary), CAST('50' as binary),
+CAST('50' as binary), CAST('50' as binary), CAST('50' as binary),
+CAST('50' as binary), CAST('50' as binary), CAST('50' as binary),
+CAST('50' as binary), CAST('50' as binary), CAST('50' as binary) ) ;
+set @arg00= CAST('51' as binary) ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ) ;
+prepare stmt1 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( CAST('52' as binary), CAST('52' as binary),
+ CAST('52' as binary), CAST('52' as binary), CAST('52' as binary),
+ CAST('52' as binary), CAST('52' as binary), CAST('52' as binary),
+ CAST('52' as binary), CAST('52' as binary), CAST('52' as binary) )" ;
+execute stmt1 ;
+set @arg00= CAST('53' as binary) ;
+prepare stmt2 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+execute stmt2 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+set @arg00= 2 ;
+set @arg00= NULL ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( 60, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+NULL, NULL, NULL ) ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( 61, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ) ;
+prepare stmt1 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( 62, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL )" ;
+execute stmt1 ;
+prepare stmt2 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( 63, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+execute stmt2 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+set @arg00= 8.0 ;
+set @arg00= NULL ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( 71, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ) ;
+prepare stmt2 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( 73, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+execute stmt2 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+set @arg00= 'abc' ;
+set @arg00= NULL ;
+insert into t9
+( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+( 81, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ) ;
+prepare stmt2 from "insert into t9
+ ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( 83, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+execute stmt2 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12
+from t9 where c1 >= 20
+order by c1 ;
+c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c12
+20 20 20 20 20 20 20 20 20 20 20.0000
+21 21 21 21 21 21 21 21 21 21 21.0000
+22 22 22 22 22 22 22 22 22 22 22.0000
+23 23 23 23 23 23 23 23 23 23 23.0000
+30 30 30 30 30 30 30 30 30 30 30.0000
+31 31 31 31 31 31 31 31 31 31 31.0000
+32 32 32 32 32 32 32 32 32 32 32.0000
+33 33 33 33 33 33 33 33 33 33 33.0000
+40 40 40 40 40 40 40 40 40 40 40.0000
+41 41 41 41 41 41 41 41 41 41 41.0000
+42 42 42 42 42 42 42 42 42 42 42.0000
+43 43 43 43 43 43 43 43 43 43 43.0000
+50 50 50 50 50 50 50 50 50 50 50.0000
+51 51 51 51 51 51 51 51 51 51 51.0000
+52 52 52 52 52 52 52 52 52 52 52.0000
+53 53 53 53 53 53 53 53 53 53 53.0000
+60 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+61 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+62 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+63 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+71 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+73 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+81 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+83 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+test_sequence
+-- select .. where numeric column = .. --
+set @arg00= 20;
+select 'true' as found from t9
+where c1= 20 and c2= 20 and c3= 20 and c4= 20 and c5= 20 and c6= 20 and c7= 20
+and c8= 20 and c9= 20 and c10= 20 and c12= 20;
+found
+true
+select 'true' as found from t9
+where c1= @arg00 and c2= @arg00 and c3= @arg00 and c4= @arg00 and c5= @arg00
+and c6= @arg00 and c7= @arg00 and c8= @arg00 and c9= @arg00 and c10= @arg00
+and c12= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and c2= 20 and c3= 20 and c4= 20 and c5= 20 and c6= 20 and c7= 20
+ and c8= 20 and c9= 20 and c10= 20 and c12= 20 ";
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= ? and c2= ? and c3= ? and c4= ? and c5= ?
+ and c6= ? and c7= ? and c8= ? and c9= ? and c10= ?
+ and c12= ? ";
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+found
+true
+set @arg00= 20.0;
+select 'true' as found from t9
+where c1= 20.0 and c2= 20.0 and c3= 20.0 and c4= 20.0 and c5= 20.0 and c6= 20.0
+and c7= 20.0 and c8= 20.0 and c9= 20.0 and c10= 20.0 and c12= 20.0;
+found
+true
+select 'true' as found from t9
+where c1= @arg00 and c2= @arg00 and c3= @arg00 and c4= @arg00 and c5= @arg00
+and c6= @arg00 and c7= @arg00 and c8= @arg00 and c9= @arg00 and c10= @arg00
+and c12= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20.0 and c2= 20.0 and c3= 20.0 and c4= 20.0 and c5= 20.0 and c6= 20.0
+ and c7= 20.0 and c8= 20.0 and c9= 20.0 and c10= 20.0 and c12= 20.0 ";
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= ? and c2= ? and c3= ? and c4= ? and c5= ?
+ and c6= ? and c7= ? and c8= ? and c9= ? and c10= ?
+ and c12= ? ";
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+found
+true
+select 'true' as found from t9
+where c1= '20' and c2= '20' and c3= '20' and c4= '20' and c5= '20' and c6= '20'
+ and c7= '20' and c8= '20' and c9= '20' and c10= '20' and c12= '20';
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= '20' and c2= '20' and c3= '20' and c4= '20' and c5= '20' and c6= '20'
+ and c7= '20' and c8= '20' and c9= '20' and c10= '20' and c12= '20' ";
+execute stmt1 ;
+found
+true
+set @arg00= '20';
+select 'true' as found from t9
+where c1= @arg00 and c2= @arg00 and c3= @arg00 and c4= @arg00 and c5= @arg00
+and c6= @arg00 and c7= @arg00 and c8= @arg00 and c9= @arg00 and c10= @arg00
+and c12= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= ? and c2= ? and c3= ? and c4= ? and c5= ?
+ and c6= ? and c7= ? and c8= ? and c9= ? and c10= ?
+ and c12= ? ";
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+found
+true
+select 'true' as found from t9
+where c1= CAST('20' as binary) and c2= CAST('20' as binary) and
+c3= CAST('20' as binary) and c4= CAST('20' as binary) and
+c5= CAST('20' as binary) and c6= CAST('20' as binary) and
+c7= CAST('20' as binary) and c8= CAST('20' as binary) and
+c9= CAST('20' as binary) and c10= CAST('20' as binary) and
+c12= CAST('20' as binary);
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= CAST('20' as binary) and c2= CAST('20' as binary) and
+ c3= CAST('20' as binary) and c4= CAST('20' as binary) and
+ c5= CAST('20' as binary) and c6= CAST('20' as binary) and
+ c7= CAST('20' as binary) and c8= CAST('20' as binary) and
+ c9= CAST('20' as binary) and c10= CAST('20' as binary) and
+ c12= CAST('20' as binary) ";
+execute stmt1 ;
+found
+true
+set @arg00= CAST('20' as binary) ;
+select 'true' as found from t9
+where c1= @arg00 and c2= @arg00 and c3= @arg00 and c4= @arg00 and c5= @arg00
+and c6= @arg00 and c7= @arg00 and c8= @arg00 and c9= @arg00 and c10= @arg00
+and c12= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= ? and c2= ? and c3= ? and c4= ? and c5= ?
+ and c6= ? and c7= ? and c8= ? and c9= ? and c10= ?
+ and c12= ? ";
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00 ;
+found
+true
+delete from t9 ;
+test_sequence
+-- some numeric overflow experiments --
+prepare my_insert from "insert into t9
+ ( c21, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12 )
+values
+ ( 'O', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" ;
+prepare my_select from "select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c12
+from t9 where c21 = 'O' ";
+prepare my_delete from "delete from t9 where c21 = 'O' ";
+set @arg00= 9223372036854775807 ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 127
+c2 32767
+c3 8388607
+c4 2147483647
+c5 2147483647
+c6 9223372036854775807
+c7 9.22337e+18
+c8 9.22337203685478e+18
+c9 9.22337203685478e+18
+c10 9.22337203685478e+18
+c12 9999.9999
+execute my_delete ;
+set @arg00= '9223372036854775807' ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 127
+c2 32767
+c3 8388607
+c4 2147483647
+c5 2147483647
+c6 9223372036854775807
+c7 9.22337e+18
+c8 9.22337203685478e+18
+c9 9.22337203685478e+18
+c10 9.22337203685478e+18
+c12 9999.9999
+execute my_delete ;
+set @arg00= -9223372036854775808 ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 -128
+c2 -32768
+c3 -8388608
+c4 -2147483648
+c5 -2147483648
+c6 -9223372036854775808
+c7 -9.22337e+18
+c8 -9.22337203685478e+18
+c9 -9.22337203685478e+18
+c10 -9.22337203685478e+18
+c12 -9999.9999
+execute my_delete ;
+set @arg00= '-9223372036854775808' ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 -128
+c2 -32768
+c3 -8388608
+c4 -2147483648
+c5 -2147483648
+c6 -9223372036854775808
+c7 -9.22337e+18
+c8 -9.22337203685478e+18
+c9 -9.22337203685478e+18
+c10 -9.22337203685478e+18
+c12 -9999.9999
+execute my_delete ;
+set @arg00= 1.11111111111111111111e+50 ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c6' at row 1
+Warning 1264 Out of range value for column 'c7' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 127
+c2 32767
+c3 8388607
+c4 2147483647
+c5 2147483647
+c6 9223372036854775807
+c7 3.40282e+38
+c8 1.11111111111111e+50
+c9 1.11111111111111e+50
+c10 1.11111111111111e+50
+c12 9999.9999
+execute my_delete ;
+set @arg00= '1.11111111111111111111e+50' ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c6' at row 1
+Warning 1264 Out of range value for column 'c7' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 127
+c2 32767
+c3 8388607
+c4 2147483647
+c5 2147483647
+c6 9223372036854775807
+c7 3.40282e+38
+c8 1.11111111111111e+50
+c9 1.11111111111111e+50
+c10 1.11111111111111e+50
+c12 9999.9999
+execute my_delete ;
+set @arg00= -1.11111111111111111111e+50 ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c6' at row 1
+Warning 1264 Out of range value for column 'c7' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 -128
+c2 -32768
+c3 -8388608
+c4 -2147483648
+c5 -2147483648
+c6 -9223372036854775808
+c7 -3.40282e+38
+c8 -1.11111111111111e+50
+c9 -1.11111111111111e+50
+c10 -1.11111111111111e+50
+c12 -9999.9999
+execute my_delete ;
+set @arg00= '-1.11111111111111111111e+50' ;
+execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+Warnings:
+Warning 1264 Out of range value for column 'c1' at row 1
+Warning 1264 Out of range value for column 'c2' at row 1
+Warning 1264 Out of range value for column 'c3' at row 1
+Warning 1264 Out of range value for column 'c4' at row 1
+Warning 1264 Out of range value for column 'c5' at row 1
+Warning 1264 Out of range value for column 'c6' at row 1
+Warning 1264 Out of range value for column 'c7' at row 1
+Warning 1264 Out of range value for column 'c12' at row 1
+execute my_select ;
+c1 -128
+c2 -32768
+c3 -8388608
+c4 -2147483648
+c5 -2147483648
+c6 -9223372036854775808
+c7 -3.40282e+38
+c8 -1.11111111111111e+50
+c9 -1.11111111111111e+50
+c10 -1.11111111111111e+50
+c12 -9999.9999
+execute my_delete ;
+test_sequence
+-- insert into string columns --
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c20' at row 1
+select c1, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30
+from t9 where c1 >= 20
+order by c1 ;
+c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30
+20 2 20 20 20 20 20 20 20 20 20 20
+21 2 21 21 21 21 21 21 21 21 21 21
+22 2 22 22 22 22 22 22 22 22 22 22
+23 2 23 23 23 23 23 23 23 23 23 23
+30 3 30 30 30 30 30 30 30 30 30 30
+31 3 31 31 31 31 31 31 31 31 31 31
+32 3 32 32 32 32 32 32 32 32 32 32
+33 3 33 33 33 33 33 33 33 33 33 33
+40 4 40 40 40 40 40 40 40 40 40 40
+41 4 41 41 41 41 41 41 41 41 41 41
+42 4 42 42 42 42 42 42 42 42 42 42
+43 4 43 43 43 43 43 43 43 43 43 43
+50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0
+51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0
+52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0
+53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0
+54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00
+55 5 55 55 55 55 55 55 55 55 55 55
+56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00
+57 6 57 57 57.00 57.00 57.00 57.00 57.00 57.00 57.00 57.00
+60 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+61 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+62 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+63 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+71 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+73 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+81 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+83 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
+test_sequence
+-- select .. where string column = .. --
+set @arg00= '20';
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr('20',1+length(c20)))= '20' and c21= '20' and
+c22= '20' and c23= '20' and c24= '20' and c25= '20' and c26= '20' and
+c27= '20' and c28= '20' and c29= '20' and c30= '20' ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr(@arg00,1+length(c20)))= @arg00 and
+c21= @arg00 and c22= @arg00 and c23= @arg00 and c25= @arg00 and
+c26= @arg00 and c27= @arg00 and c28= @arg00 and c29= @arg00 and c30= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr('20',1+length(c20)))= '20' and c21= '20' and
+ c22= '20' and c23= '20' and c24= '20' and c25= '20' and c26= '20' and
+ c27= '20' and c28= '20' and c29= '20' and c30= '20'" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr(?,1+length(c20)))= ? and
+ c21= ? and c22= ? and c23= ? and c25= ? and
+ c26= ? and c27= ? and c28= ? and c29= ? and c30= ?" ;
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+found
+true
+set @arg00= CAST('20' as binary);
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr(CAST('20' as binary),1+length(c20)))
+= CAST('20' as binary) and c21= CAST('20' as binary)
+and c22= CAST('20' as binary) and c23= CAST('20' as binary) and
+c24= CAST('20' as binary) and c25= CAST('20' as binary) and
+c26= CAST('20' as binary) and c27= CAST('20' as binary) and
+c28= CAST('20' as binary) and c29= CAST('20' as binary) and
+c30= CAST('20' as binary) ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr(@arg00,1+length(c20))) = @arg00 and
+c21= @arg00 and c22= @arg00 and c23= @arg00 and c25= @arg00 and
+c26= @arg00 and c27= @arg00 and c28= @arg00 and c29= @arg00 and
+c30= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr(CAST('20' as binary),1+length(c20)))
+ = CAST('20' as binary) and c21= CAST('20' as binary)
+ and c22= CAST('20' as binary) and c23= CAST('20' as binary) and
+ c24= CAST('20' as binary) and c25= CAST('20' as binary) and
+ c26= CAST('20' as binary) and c27= CAST('20' as binary) and
+ c28= CAST('20' as binary) and c29= CAST('20' as binary) and
+ c30= CAST('20' as binary)" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr(?,1+length(c20))) = ? and c21= ? and
+ c22= ? and c23= ? and c25= ? and c26= ? and c27= ? and c28= ? and
+ c29= ? and c30= ?";
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+found
+true
+set @arg00= 20;
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr(20,1+length(c20)))= 20 and c21= 20 and
+c22= 20 and c23= 20 and c24= 20 and c25= 20 and c26= 20 and
+c27= 20 and c28= 20 and c29= 20 and c30= 20 ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr(@arg00,1+length(c20)))= @arg00 and
+c21= @arg00 and c22= @arg00 and c23= @arg00 and c25= @arg00 and
+c26= @arg00 and c27= @arg00 and c28= @arg00 and c29= @arg00 and c30= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr(20,1+length(c20)))= 20 and c21= 20 and
+ c22= 20 and c23= 20 and c24= 20 and c25= 20 and c26= 20 and
+ c27= 20 and c28= 20 and c29= 20 and c30= 20" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr(?,1+length(c20)))= ? and
+ c21= ? and c22= ? and c23= ? and c25= ? and
+ c26= ? and c27= ? and c28= ? and c29= ? and c30= ?" ;
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+found
+true
+set @arg00= 20.0;
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr(20.0,1+length(c20)))= 20.0 and c21= 20.0 and
+c22= 20.0 and c23= 20.0 and c24= 20.0 and c25= 20.0 and c26= 20.0 and
+c27= 20.0 and c28= 20.0 and c29= 20.0 and c30= 20.0 ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and concat(c20,substr(@arg00,1+length(c20)))= @arg00 and
+c21= @arg00 and c22= @arg00 and c23= @arg00 and c25= @arg00 and
+c26= @arg00 and c27= @arg00 and c28= @arg00 and c29= @arg00 and c30= @arg00;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr(20.0,1+length(c20)))= 20.0 and c21= 20.0 and
+ c22= 20.0 and c23= 20.0 and c24= 20.0 and c25= 20.0 and c26= 20.0 and
+ c27= 20.0 and c28= 20.0 and c29= 20.0 and c30= 20.0" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and concat(c20,substr(?,1+length(c20)))= ? and
+ c21= ? and c22= ? and c23= ? and c25= ? and
+ c26= ? and c27= ? and c28= ? and c29= ? and c30= ?" ;
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00,
+@arg00, @arg00, @arg00, @arg00, @arg00 ;
+found
+true
+delete from t9 ;
+test_sequence
+-- insert into date/time columns --
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Note 1265 Data truncated for column 'c13' at row 1
+Warning 1265 Data truncated for column 'c17' at row 1
+Warnings:
+Warning 1264 Out of range value for column 'c13' at row 1
+Warning 1264 Out of range value for column 'c14' at row 1
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+Warnings:
+Warning 1264 Out of range value for column 'c13' at row 1
+Warning 1264 Out of range value for column 'c14' at row 1
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+Warnings:
+Warning 1264 Out of range value for column 'c13' at row 1
+Warning 1264 Out of range value for column 'c14' at row 1
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+Warnings:
+Warning 1264 Out of range value for column 'c13' at row 1
+Warning 1264 Out of range value for column 'c14' at row 1
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+Warnings:
+Warning 1265 Data truncated for column 'c15' at row 1
+Warning 1264 Out of range value for column 'c16' at row 1
+Warning 1264 Out of range value for column 'c17' at row 1
+select c1, c13, c14, c15, c16, c17 from t9 order by c1 ;
+c1 c13 c14 c15 c16 c17
+20 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+21 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+22 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+23 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+30 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+31 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+32 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+33 1991-01-01 1991-01-01 01:01:01 1991-01-01 01:01:01 01:01:01 1991
+40 0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+41 0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+42 0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+43 0000-00-00 0000-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+50 2001-00-00 2001-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+51 2010-00-00 2010-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+52 2001-00-00 2001-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+53 2001-00-00 2001-00-00 00:00:00 0000-00-00 00:00:00 838:59:59 0000
+60 NULL NULL 1991-01-01 01:01:01 NULL NULL
+61 NULL NULL 1991-01-01 01:01:01 NULL NULL
+62 NULL NULL 1991-01-01 01:01:01 NULL NULL
+63 NULL NULL 1991-01-01 01:01:01 NULL NULL
+71 NULL NULL 1991-01-01 01:01:01 NULL NULL
+73 NULL NULL 1991-01-01 01:01:01 NULL NULL
+81 NULL NULL 1991-01-01 01:01:01 NULL NULL
+83 NULL NULL 1991-01-01 01:01:01 NULL NULL
+test_sequence
+-- select .. where date/time column = .. --
+set @arg00= '1991-01-01 01:01:01' ;
+select 'true' as found from t9
+where c1= 20 and c13= CAST('1991-01-01 01:01:01' AS DATE) and c14= '1991-01-01 01:01:01' and
+c15= '1991-01-01 01:01:01' and c16= '1991-01-01 01:01:01' and
+c17= '1991-01-01 01:01:01' ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and c13= CAST(@arg00 AS DATE) and c14= @arg00 and c15= @arg00 and c16= @arg00
+and c17= @arg00 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and c13= CAST('1991-01-01 01:01:01' AS DATE) and c14= '1991-01-01 01:01:01' and
+ c15= '1991-01-01 01:01:01' and c16= '1991-01-01 01:01:01' and
+ c17= '1991-01-01 01:01:01'" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and c13= CAST(? AS DATE) and c14= ? and c15= ? and c16= ? and c17= ?" ;
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00 ;
+found
+true
+set @arg00= CAST('1991-01-01 01:01:01' as datetime) ;
+select 'true' as found from t9
+where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
+c14= CAST('1991-01-01 01:01:01' as datetime) and
+c15= CAST('1991-01-01 01:01:01' as datetime) and
+c16= CAST('1991-01-01 01:01:01' as datetime) and
+c17= CAST('1991-01-01 01:01:01' as datetime) ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and c13= CAST(@arg00 AS DATE) and c14= @arg00 and c15= @arg00 and c16= @arg00
+and c17= @arg00 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and c13= CAST('1991-01-01 00:00:00' as datetime) and
+ c14= CAST('1991-01-01 01:01:01' as datetime) and
+ c15= CAST('1991-01-01 01:01:01' as datetime) and
+ c16= CAST('1991-01-01 01:01:01' as datetime) and
+ c17= CAST('1991-01-01 01:01:01' as datetime)" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and c13= CAST(? AS DATE) and c14= ? and c15= ? and c16= ? and c17= ?" ;
+execute stmt1 using @arg00, @arg00, @arg00, @arg00, @arg00 ;
+found
+true
+set @arg00= 1991 ;
+select 'true' as found from t9
+where c1= 20 and c17= 1991 ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and c17= @arg00 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and c17= 1991" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and c17= ?" ;
+execute stmt1 using @arg00 ;
+found
+true
+set @arg00= 1.991e+3 ;
+select 'true' as found from t9
+where c1= 20 and abs(c17 - 1.991e+3) < 0.01 ;
+found
+true
+select 'true' as found from t9
+where c1= 20 and abs(c17 - @arg00) < 0.01 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and abs(c17 - 1.991e+3) < 0.01" ;
+execute stmt1 ;
+found
+true
+prepare stmt1 from "select 'true' as found from t9
+where c1= 20 and abs(c17 - ?) < 0.01" ;
+execute stmt1 using @arg00 ;
+found
+true
+drop table t1, t9;
diff --git a/mysql-test/suite/maria/t/maria-autozerofill.test b/mysql-test/suite/maria/t/maria-autozerofill.test
new file mode 100644
index 00000000000..45eb39fbc21
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-autozerofill.test
@@ -0,0 +1,81 @@
+# Test to verify that auto-zerofilling happens when a table is
+# imported from a different Maria instance
+
+# can't restart in embedded
+--source include/not_embedded.inc
+--source include/have_maria.inc
+
+let $MARIA_LOG=.;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+connect (admin, localhost, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+create table t1(a int) engine=maria;
+insert into t1 values(1);
+flush table t1;
+# Check that table is not zerofilled, not movable
+let $MYSQLD_DATADIR= `select @@datadir`;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/mysqltest/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= <FILE>;
+ print grep(/Status:.*(zerofilled|movable)/, @content);
+ print "create_rename_lsn has non-magic value\n" if grep(/create_rename \([0-9]+/, @content);
+ close FILE;
+EOF
+
+# this will remove control file, so change the uuid of the Maria
+# instance, thus t1 will appear as imported from elsewhere.
+
+-- source include/maria_empty_logs.inc
+
+disable_ps_protocol; # see maria-recover.test
+replace_regex /Table.*t1/t1/ ;
+select * from t1;
+enable_ps_protocol;
+flush table t1;
+
+# Check that table is auto-zerofilled, movable
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/mysqltest/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= <FILE>;
+ print grep(/Status:.*zerofilled/, @content);
+ print "create_rename_lsn has magic value\n" if grep(/create_rename \(0,0x2\)/, @content);
+ close FILE;
+EOF
+
+# this will attach t1 to the current Maria instance
+insert into t1 values(2);
+flush table t1;
+
+# Check that table is not zerofilled, not movable
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/mysqltest/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= <FILE>;
+ print grep(/Status:.*(zerofilled|movable)/, @content);
+ print "create_rename_lsn has non-magic value\n" if grep(/create_rename \([0-9]+/, @content);
+ close FILE;
+EOF
+
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria-big.test b/mysql-test/suite/maria/t/maria-big.test
new file mode 100644
index 00000000000..f6fda2c680d
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-big.test
@@ -0,0 +1,71 @@
+# Test of scenarios potentially too big for --valgrind or --mem
+--source include/have_maria.inc
+--source include/big_test.inc
+
+let $default_max_allowed_packet=`select @@global.max_allowed_packet`;
+set global max_allowed_packet=400000000;
+# need new session to use setting above
+connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection root;
+
+enable_info;
+set storage_engine=maria;
+disable_warnings;
+drop table if exists t1, t2;
+enable_warnings;
+
+#
+# Test generating data with insert select
+# This test case failed once a long time ago
+#
+
+create table t1(a char(3));
+insert into t1 values("abc");
+insert into t1 select "def" from t1;
+insert into t1 select "ghi" from t1;
+insert into t1 select "jkl" from t1;
+insert into t1 select "mno" from t1;
+insert into t1 select "pqr" from t1;
+insert into t1 select "stu" from t1;
+insert into t1 select "vwx" from t1;
+insert into t1 select "yza" from t1;
+insert into t1 select "ceg" from t1;
+insert into t1 select "ikm" from t1;
+insert into t1 select "oqs" from t1;
+select count(*) from t1;
+insert into t1 select "uwy" from t1;
+create table t2 select * from t1;
+select count(*) from t1;
+select count(*) from t2;
+drop table t1, t2;
+
+#
+# Test creating a really big blob (up to 16M)
+#
+
+create table t1 (a int, b longtext);
+insert into t1 values (1,"123456789012345678901234567890"),(2,"09876543210987654321");
+
+let $loop=23;
+while ($loop)
+{
+ update t1 set b=CONCAT(b,b);
+ dec $loop;
+}
+select a,length(b) from t1;
+check table t1;
+let $loop=22;
+while ($loop)
+{
+ update t1 set b=mid(b,1,length(b)/2);
+ dec $loop;
+}
+select a,length(b) from t1;
+check table t1;
+
+drop table t1;
+--disable_result_log
+--disable_query_log
+eval set global max_allowed_packet=$default_max_allowed_packet;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria-big2.test b/mysql-test/suite/maria/t/maria-big2.test
new file mode 100644
index 00000000000..5fe3fcad8c1
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-big2.test
@@ -0,0 +1,4077 @@
+--source include/have_maria.inc
+--source include/big_test.inc
+
+# Test for an index corruption in BUG#37276
+# (CHECK TABLE said Invalid key block position: 15731098820608 key
+# block size: 8192 file_length: 425984)
+
+create table t2(id int,a varchar(255),b varchar(255),key(a))engine=maria row_format=dynamic transactional=0;
+
+disable_query_log;
+insert into t2(a,b) values ('zmysnptvgzljpaumbdhrzkmbhefugcyhncbl','urecietrsfhgusavxffpdszrfcpdqbwxzvygsuwammwunjhpxanvozwnngnnjbwfenjgosaixpccjyviiutzpxkwiecuprltzrpxvkrjnjqgsneniewbagpvwelajvnckbbkqpaicxor')
+;
+insert into t2(a,b) values ('nprjbpepkpioqioubaxtymmgyufmionvudufnnzihrwkthrqjcclnhrvicoaliqeapuqxoibiqvxtiynkrheonsptqzsowjvmnkvrlskkyfcunawzdeeerrsxqcdcqctokryvhqbluwskwslrgqxrvrsidhuiwwrovethsvkrdjpdbbxqjmnjzqmsixjshqxcbjmwqergwgnqatulyeninhjggywkqtxxlvf','chwranxljzxppqwbkulphhliulhwrllumvzyqdnfyatmzvqjkhzcaf')
+;
+insert into t2(a,b) values ('ksywfvqlgesjcftgoppnwlmufozyyfnymzohlfyqjlopthvnrpkujixzzwnhkdhmkfnqildzluof','hczcokmxfbdlldqvkkzimzsdglfmjvhdmsoicyjgwanzyaoyuuozdoakczuskd')
+;
+insert into t2(a,b) values ('bjrtmdnuhjoixyftmuawakriyxmvpfvhqzeauqvaypkvewaulrgiefugeiswjzsxyghpzmwrwmfenmepscxxwlotzeeasiycoxsudpygepcjzoqfeekhznetyrgicysuccongpiabzywqmdeickthx','fnebnkbujavmqijdykcylcoytvfusafcluobyrkvbzmhdeufurpdtobpxmhnevsbetyfhdoytywmwadohogyyfvagyfyckqyibumuewzjrhedxxvazlqnwpvqsvbjbndxpymabxcqmzuympvlmctanhhfbvzwrojcmukwlobtse')
+;
+insert into t2(a,b) values ('jnywoptbaspdhhdpkqviuaalaqbwybwqcgrmnxljcvzemeqpcrsutwgoazdjerqpsevngwarxcqshdvhygqawdzmjbzbtrwfteisirvhdhotznbhlfrnroaplguldtkcraurggrociqmzhlxbthcjanxvompdcbnxutjuckfrnicakhuebykukpqjtzwazcogelvmkcabbavomzktoysamurxiffwpwgai','lbjbrfjplgrnaooyonstnlnzentdgwbmfpzouvlbkdkvnjvlpajqserpfgenvhevqzepjpqkdfhoqgsvvilbrnlkhukthtyjkiairtledhcsrqzohwkupzoisyywilaakhxjtgrmzpjhgznkyb')
+;
+insert into t2(a,b) values ('jiehmdrwatvsnfhwyvnsyjfknoymolcvfbtvrqxdxpighrxkrpvoledozzedanqjslhbqqllvpknzmsucstpqisandbhsezeavkpmrddluiupllgerqumnbabcmbivgznxrchzp','surfhwluxtrcbnwxrmsqmuensbdipocqarzxntttp')
+;
+insert into t2(a,b) values ('lpafdimerwxsaqbdppxenxmsxtlaguxzphuupwsmqtkkzedtblvmteyseaggyzlssmprjkjpafjgxelqbqnhfyjjhizhjtnbdloawselvssntasuddmgnjehmuhruanqwlgstfuwrtukwkfdu','jjwpeduzaqdbaiatvztoacbejtcksurlcdjcqznptvjewagcjafccnpoksouwhhdawvlawmqmpzo')
+;
+insert into t2(a,b) values ('twxehpvvjacqiwiuporwsmglshlhurbpibfijwvwhqhhzjwpncoqyhvyhkrfpsjdvebxsozvvgpimvguipgofpkzthjdzghurbxvzxhunzm','hrehpyzysnymtrbjewyycyievmewnupuuteemqtchjsynbfzavxwcdmgsmwurwtituhftdaggkdkdqqtwkzbzvtjuowqpmhhxmqstdyjtqeiumxtqslodbiasurcvdciohwcavpawisyxibuoabseefqqckwsygtkhwazckqsvuzyc')
+;
+insert into t2(a,b) values ('sgdabrytzkpntgfewoypd','rcurfochhpvodkadhkbgyqwjdoapnxcnaiufgiecjdwmjbyjjagbfnjvhhfcyxoblfkhposwqkkcwocjtogwewvhumy')
+;
+insert into t2(a,b) values ('kwlajwkjlszwxboyzgmhjcpwzgrjwmytrlrjxpvlsdqmlzvebzbuwswsqralodrdjjnievxfhsuaxxjhrncjedbhftgdvabvftozbyqewlvc','gqzcpfwcpwuxqtmmkkblxmlawsynjoprwybbcnvwuvnigmlyqzdnjccfutrqfsdohrvqlbfubyqdcwlwhbbstyaxinqfljnkbadxthgiapmffxrfjbdtyneubmxbltmvkdveegecrudfkficrjtpopellyvxmbefumrnpkpzylh')
+;
+insert into t2(a,b) values ('wnhjmihxckbpvqtlwglgqsdkqxjrxqtkjtgotnbubkogkpjsjybqedvnooertrnrbirgqbvkafcwcgnpncvmhiftutafdqgpzbnbssvgkurfmvyqflamilezcjdbmujxpcfkaztmgpesqfjugcseudbdtliydfdbayxcreaomtdhqaewabgwwk','nyogdjkywvffeajmcesrsuotqewnfzlxvcrkdxtjzgbrskxyqmpkxvgnkooekmdcuktvlpehkelvthehxhrqvozwgnelkfvnfesq')
+;
+insert into t2(a,b) values ('dfmkfkeozotpuxiqqlgjsvpmpybziveccikvyaqeilotlqiqkkqjlogmxhrfvd','ochocjndyrlljvzeubtlhg')
+;
+insert into t2(a,b) values ('rypxylmtdxeryjjwrbdpicafhtbfhkbkjwakzgdqanxjuaaemmirnvafaesmwggqqzyefhqjujhwuaanqmjawiekyjxphvuctfjjuqvshcljuntskhxqumgvhdgkzuyjdogtmzuymuevykstgxcxcyvlcshdexnuowrojkdbbrfworbvopqtkysvfxsapygiqvdumkduyiiurciqpouabqcaiuuvnqhjiooncmgvn','sstfdleepklhamtxypqafyvpwcmidskepryjijpvcoihpknwhnldrpuriajeqocmuzipmorlunvorlefpvnnunrutd')
+;
+insert into t2(a,b) values ('jsuxigcbgvfbjqucabymbnefheseqpqdldlioi','wjdfgmmxkdnakptmrndeczbgxuwrqjqjzsznntropydhknqncajiywdhsvtlyyoldbbbuotevitucaenzgrrdlolaizyztbazoucveotyu')
+;
+insert into t2(a,b) values ('gabpgcxlbypjqcnpbuzjyilzopydljxukpqoqlgy','iykwuexkqfthegjkxfcrkgpzqgeewidzcaqrxunp')
+;
+insert into t2(a,b) values ('ibvarcshuuenadysxxuyhuypfmfpuprsalyydwagdomirozbzpkjgzujqslyupgavoohwqtzsmvclrvkamilvgptwbdykdqtltbsfnvjlnckvathwkprnlkumhzhjms','upnekemimhiqak')
+;
+insert into t2(a,b) values ('lfrilnjookfdlhtenclfxsgkvagqcepihnwguzhsfvvwenusegklxcivv','bekmtotnfrcpeanuqrqhofcoqhtjyybznywomcwvhrfrslxeivbztlfwaszyejcocyvwtlyyrlyarfbfdhvccltwffijmuhfdpxjuepxdunkuzuyursgyltjrekllsnzmbwvrutrzzukmxqdpvpioefjdkrwsustrejtxtpzrazolyrlexwzdeepavieywvodryrmqcy')
+;
+insert into t2(a,b) values ('ombvijmetpmmoxkqlxrcqtbdvjvsoqurgmcwppykghtipbeuifwamdsiaasiitekplptlxwlbfrfsn','rovjrnacpjvbwifxhtxwjfsbpgismlzlrqrpjfuzifwjbffrnewtufowtxkk')
+;
+insert into t2(a,b) values ('kddilxmakstrhlyechbzggballwlconupbgfvbdgyufxnkqwfkxbpdajtwemcrmnouzaqyjawuavdyydnhmbgfmljdpooqqgcgbbacyvzcrrqysonyumbfpaghewktbosicspbaustvmsfkhzdesszhlappwskxubqnxkdcbpmtfagcetdtvolkobnrkjcoovwsehysdqfwzytymcphsmawaabdjgrkjwtwcbfrdmyzrywyozqafcku','qomrbsznhfqrcukrhxdfmqqvxhuyqlqwzfbsrroezwjsrlhcdpcdohbqjgycbvhtkwpfufyqgfzsgslorcbzmumiybnfhknvgzpvitgdfrtgceiascbqykqhywiyumgvqobsntcfoqsediownvnkmgldytikcuoojjobirieomsshctmvamlmtvebjxkvhjedaxsqncudtepjejc')
+;
+insert into t2(a,b) values ('hjstavdokkigktwceznkeafclbiodmzbasbzzcikpmjsiszaxkibrweprsbcehhudpleibmuxfhcvjqqhlxakbqfmxtekauriyadavzbgtktrdkifnkwpyjdxysnqkkxftkmmecbwncakckkiubwwulxcksknscnyqptvhqdfzlgbxghmvidjffpngwznoiphkd','yunijixchnattpuijiehoyflshczaookvbgapapbfijosxebyzgibqvhwyhuoavswjjewkjzrjbtldnavfujgqzohcybgxnrqsrelpcawvpnyfoprwhroxiwmykenelijrdfwmzwriinmjivrxleblgyaqtiteqbmjlxppbrwsaaxjsasraqhydoqvbqyzuvhcsyekvr')
+;
+insert into t2(a,b) values ('tlzbqiudcvfkesojvdbjtvffwdljjaczarnouaptfyltqnzpxhjtuhq','lbjwhjkrumccesllztrmlmrvvqmdbixrnotxocabpvguokllabcgariunevfddiapwmghyzkttqqzjojmdznoziqpaydyqusxutogwlokhdpwlqtmyvcqvhppliclirffcoytmmzxilrshjvixhhebgluluvupzvfhxrcnrikvhkqjffkbdkfgcbuxxexxpjwsdzgwippdgkhwobajjtkjklicxghbhxxabdh')
+;
+insert into t2(a,b) values ('nicgdwxrplangjvzeqgiyhusqovdbkuiituckqfhpgswywhrsezihlvnqwbiqgkiffctbpqxevohbkzefswqjchuqnevahcveptpgzboovbofubirniskgksmzcqynzmfztxssalqkufuiogwskgbvppj','tsutokdeslqsnkgomlgkxssytcbcsllnjxnprscbypslsgcwcljeiscrntahmddeh')
+;
+insert into t2(a,b) values ('mjnsswoknxspdxfrjftdogbhqhih','yfwgvixdtskxkudaidzbhvrlkjcazaumyavazzbrblqzugmwzhurdhedspnkngikstkdmeqwtqkdasbydhfwduhreynysaxwyyikuyowshnsprcevgcjdpklsnabwvdfkvikfkkrbhah')
+;
+insert into t2(a,b) values ('foyvwgsgltcohqhztrkkbtbketysfazorssyfhimkhmuwlwvdivmbptjnkrsqbpgmszrmfdqvebvfrkxeoueskugrqrxmvsyaazlbfqzwuotdquofezqskzpbhyopzehdnijhmgyiuzhtwtpu','hvxjshhqprycpzuqavcuxrtqafzluxlqajnjkytjneooqvxspayoijmjbblxuefuubakryxjtvgilqsbbbmdtvrxlytfftwssvkfwyifnsyitafjnmxtglafqcczbzatajowsrqcxqrsbjmhbrupkzcuiqmlaxoiycchtvspvzqazrpvndwgorgrgklbitrfgeimysh')
+;
+insert into t2(a,b) values ('zbsjnsxdgzmozoyjxkmwohjooldzmhpealkiifhbcfanxlyqusxcduuusrekhqqtnrblnfmpbmwrzgbvlhdegrqnwdrzjlbafhvvpxgvecmcktcisn','pvgoukxzmczdmapmfyitvehyqozsxgviwsgcbwxdtzwigmwlhfxbavkytcrqcxuzrfevszcixuucbxjmklfrneevhxjbwmsc')
+;
+insert into t2(a,b) values ('xkdivmtvtuebaswqljsqdtelldogpyvmrdqzkyyvsieshmmsxzfqcnicqtxupktmjihnqayrd','iioboeuzvulmkynfmgszefomfnvdjrnpwwahbcwvmvzblbocbllplyxcpepbcfyzmewqxhjswauficsiovvvdwildjevqcptgpajnpkajkmluhargkxjyhpljfcufihblatvosutrznfiaqxcaervtlbvyolanfqurattux')
+;
+insert into t2(a,b) values ('keaxeuoynqakckyjwpogcrxvcghddhyqzboomnqvhncbvwtykwujqouiwybgcujeqdwihvkxhguiutrkhmbwtxejpfzecefuygpqptyqzrxpspxwjnrriivmqtdbxf','xnbfqjalxqytpcszamlziawjsgpcfeuuxsvhbxkirhtjjuwtxmrxffoul')
+;
+insert into t2(a,b) values ('rbvxdcdvlvgkxkxuazpjdpvzpckdatjwbmwalk','tqxpwcwgzyimdornulqzsovahlbhapdxmspnxnrvieranwyfsgdkypwrhwkharorycfxljgvjkxmjwtetykfocslhygakojleoxsmtesjcbojplxhhvccsnayf')
+;
+insert into t2(a,b) values ('defoefcnibtlvveqejajymelmdtwihylibxemvqulnayjmfsgfrtmwgqxitblefhxfwkrdaelvjomtjiwtzdonvwgdxqpjdochgfyhaltrbozo','gkhneodxrtsdznqkglkjuftemkmsxaguxrytirbzcgwnrdwrciogluxwplrwwunjamypemohfhhvwutxcfguezhahuqnwkywshclgonejtpasqsuxd')
+;
+insert into t2(a,b) values ('lroflhynuixzajezdvvxmdkpnyulllmjiromcswlzysqdorhzagwdgcunhrjbgwipnrixnqjsvzuavqecpjweeqieeuormkjdnfkzldifoe','rlotwkogclgmcdxoryyctrkcqbuvcumsiiduvvhasstzgaknklyvaqmxjagebxtjwktsomiqbohtmqyjsbln')
+;
+insert into t2(a,b) values ('yqvmvoyzedxjbckbzdfljpabwhqqwnfsbwwmgvwmkoeieyoffglvnuklqkfjhvmxfprnpfswbotejsqrcwqaejsiygkfrcogkdkiekvhvtplqhwwmpzjsyuvazctwiyryjupztcqffoioablwswphadkrzfpmqhgwbnnctujefubwdzirwmwkwppcnxgpxwybtkdziulsgvggnbqlartup','duivylinsfcoglbjnicrrjrsomxobjsivxqlvauxyroqtompbmyqunjroupcgsbdipeozqegaacaolxeajrvzhmchperlgxnguj')
+;
+insert into t2(a,b) values ('bgkwsevokukjfquznicdfptzbjvgqcjdubguimyqjsuvokoyavnohmtyfhcjjwhtwbxhureqeoiiiwgwaympktdazqqylqxcbrwnrctxajbbwbsxpbkwkdhbvxzobelrjbheasrfoytzhtzynqovrunbkijwihntumcxrcgbsxtsdwwfvukerxzsqvpijspjvoqbtyoposywzvkasjocbsnibkvtikhulesqpuexa','zmwqxkoqgjljflhruxxlmqptwxxtzbkjlviyzfqillfoedwp')
+;
+insert into t2(a,b) values ('ekgmdmfgjjkejnaarywesztkcosevcdagxzmjylquxlqdmnznmgwcbmvsjxbwbsnzksltxreqrxkdvmitmymbgtirdvgkwplijkdbtnilptxbngbbyjzglvzrwlsuwipiualzbohpbrruoaxzlkssbudwcomoublcfxjmvm','e')
+;
+insert into t2(a,b) values ('vejftyvubhckejyqrziwptvifevxvbnvidoghcefijvqhvibrwkievqejlsdogfabolysgzhppzxmeplbgkhvhiqllcckrctxvzaqisppniufvminyjjeaztarawbuftzymxuxocmsttmdjpglodltxpqxrghroabykhwjjzobvshphbgyrpjoaxpqmrlxsvngojqqcxscrprpcbipfuazphanoigqlvybkxgybxhieuxdjhltunuwptoy','obioejkuojdjpdlrporgmcsevytcghiqwknhulrkidwmsjyyyaaqqonejaqpnmpyolnpqvtndnsridvpxmppzcvhwgssvvwkewwztqdxbynbfixppdmgamxwzfldquiltjxcnvemizprvhogyrrnirnftftvhsapuxrpyjjcveyggxrirkpckknlslatpneokcoalixkkzqwtwufkqiz')
+;
+insert into t2(a,b) values ('vyetyjkrlkkyldabaepffgclwhtilgdymptmpjkpxuwicb','hhxtaqqrvficihjouiippbidrhqdwjgrryiebvdbdcwrxpuro')
+;
+insert into t2(a,b) values ('vfuvtscajrdbgauxgeivcjgjckxlzfegipjnvgijhohipphkkctbtvzcusamaxeavbhckwovbdnvnkvbgrsxofgofkjggvpbctbubturktonlfsimygdojuakhejtdfmegadkvphdyomngrdwwkhszyyjfrlmztwmvtsykqezbectmexilpiknoljnriybkj','myroyvrlhvtiaaupvwbfwvuqxbwjbdwxctrrhzjjsiwwlcqzbrcqkxikiayniefyblozagskjhttgybpkvgkxyabwojzukgmrqidrmbanyevtigbzthysndeuejgpgaxvlbfakvcosvkcngeksrpxyhtjjtmxcloqsnpykvtbpzxjamjsnqxnibeqohbrfroyyezbgczjuirttnaoftuqbe')
+;
+insert into t2(a,b) values ('fsjukikgfyackytmjqhwbwtu','wbvgu')
+;
+insert into t2(a,b) values ('myfwnxrgufyeawiejjhmwhqmdhlvwzbcoldonglzcktkeczswutwbiunmlxsipbbngtxcuxllrosruiumttpzmkubnanvnxmwcqkjczilppobqypbciwmjokfltcgjjg','sjlohxotohbvrtoggrojhdkyduqcfwjvobqhzjnufkifkbnmeolnxczybkouggqfdzfwandzuvvbbvqer')
+;
+insert into t2(a,b) values ('zxfsyhpvuxvjnvunlrgljbkflxlnncgheqxpvmxtzwqpaksclkkttrkecjtoxnzjvgnydpqijglkhsmnlwgextznpmxptomcduzzosstlmxuhepwoejffjaddnvwovhibyjskqreohanjvsmzqjykeuusvoopqhpaanumgmfdjuiwfokuusxavtyhvkitgiqvznafueedqhodzpdwfxbfqqshpanktobohbmnnvmwfrnonyvtuoxm','rtmpgoqwxeztunmlhdxpwycintirufogkqahrvfstcrakjlwtarngatmrahzpuemrdichkedtgfyuogtntcgdvvyeagjpxjpsxcldzhql')
+;
+insert into t2(a,b) values ('jsaavpyvimymcylbbkpvuvbiednqoacawgtvlrqshqvlmxnimlgjjbxmrvzorxhatdvpcxwzluyallgksobppsmfcmzexlbepoemysncbhddwykqpwnzrqxlaggrfyogxpvvgoucsexqnvgxjmmcmlhrryaxepdgdmaojvhrimaigshrjtqqpxrupctcompukadprjhwqccniovqketdoudzfpzohflulxihzexunzziklbxiyztfusixoqu','pmlxucqbqzvrmqjbfgjmrgxdrkxyknyudhcbtvpjujgghknyrwihgkytfsgmwaetmkwjabbmycsupoppqb')
+;
+insert into t2(a,b) values ('dkzsjsnkxqejuxexilojxeuegrofqmhoykybyngzfemcubrfgyjkhljgdlijvfnlwwchfkbubdbgoguuuvzwukiglwzrcxtknkgzawrncjslxjqigtevqdecgdyfxqhlzwcvvpoyclsnfkhrzpxnjaysnkjsqsxetulqnrlncbloewskllyapdfhcoqaxtxyibzlfbsevxopnerxq','uvpbhitqa')
+;
+insert into t2(a,b) values ('nhjiesnghleztzemqtjblpvfeglkqhllzbrgdhsjatiixodrdzmqdkrqioiihaebmflwqvmplyemnvipwyzbzkfmespzkdppqltdqhtshyyjkpaygdoqlrllnpdxdqaenoagyqwaythyykwruqfsvuwpvhglfsocjkxfmnsbwhlsfrnyetyqqdnhzyvjzdhrwvgbgxxycyvcob','apexxgipieptyzvqhlshvtyip')
+;
+insert into t2(a,b) values ('jpkbaceyekwxrpgtfhspphhnicshnyvuopyuwoiruxivcotjlfgipqgedfikcgkchlbgcirpnzvbpllfgdkebjzuoxwbluqqkbwnhyitknbpveczvizynrvbhkyvnrpkrubwkrzruhgohtyhecroynidrqeqehsovjvopmldrm','czonlpwyrthldtprwuqudccznipssgtlpuysjmrwlcnryhpnkispgkkxbrkleutgaqcmricadsqfhrugegqnyswgzqlbylwedtfvnudquyethvoovvatfrfaehawuwsvidcejbejsehexmwraxtopbtowuistywmfgsaglulurtfzjwsqjnawzlwjgezzgmfioghmqb')
+;
+insert into t2(a,b) values ('ewfraakwxnlmjahbjcjubsxgynqwzqttxqrcusbehbmfxbvqpjdrussuqsdflezxueurjcuraaurthvqtasrvimzdzxeaholtipsslemugj','mxrnpwhivpohqbpdeaxvjlvblsahscpyvqvngkqb')
+;
+insert into t2(a,b) values ('thobsbkrqvccbfzzovmnxozttfgrovqunhhjqsgjvodyqizusfccmyyrdjaivmxgwufpdvvjeejldlhyhwwvsmhijlorxoofcpwmgfljkvedefxroncslgqcbtseibjnkpqqhaqiaiectrvyvmtlbo','qcjmipjpryzcpeiygwuwvxlpselprydwkpdevivuwvisbcrjrsjbedmd')
+;
+insert into t2(a,b) values ('dwyzcvhyrvdewhmnxsitbclnuvbkqtfsckivburwvptkyefqyiegsgymkvqhzhyurtotnprwwijsgxlcalmeteqrftkdympkdzvzqbofdaoxlrvvnigudyseftnybmqmwkwaavegsdn','doyzfleshppxzkyumachzqnxyshvncyxxsatyvizhsydiktnklgzxcnwqklzkjzteuwkzjzhnrfyyplvyowswrxcumxlyuamfntmxmxnrmxkpodqmhmupunlpupyuejwnvqdbpnsntxveaoggcnnlgbdamwrdwwncqgjfhjwtswfbcqzfbxoqjmfpczcuhqsueljuljbgkzkimmabsryosuwo')
+;
+insert into t2(a,b) values ('pblyvuvofzffwwsrfbklolrnlhsfdyhxzchpzzzwwoqjxbphgobdpnwelgtvcvthanczadqjwvhdhvnwuchaqtfhzinehevcasqaexyoatldkyhghybitlwolwavqopbbqrlsmhnlxdaqxvfdxrvwchocrzqvomkdfayqhaardmidfewvhg','prqrrpkhvgygctehnfyaztghqdikdftkgheciobjdtdkmjuieexutvtuybcoyyjrxhjfzcsvrqwdyvxsvnqrxsnlnmrqdkloueynjrhuvspjrgisbkynavygbqmykdbkfubuupqeduvyxrviflauscqjtnaskkmqzavkolnwfm')
+;
+insert into t2(a,b) values ('icmimgfbyrsmedcqyhisoaxzvlvvovvdnaeziufuaarxmqlfwjwxdnrequxscubrlhqzkfhszstzjdintghapilfwejmaxdwthpwjouuaxegwhuydzpnsmi','ylboswfdnwmpxwohohxodcasecuaxv')
+;
+insert into t2(a,b) values ('egcapszbzfbrefjjsrkhoresjigkxmrlgufyxuttgnqzslftrhwqsvmntfxalwvqmrzivxqbgqsqlyevussstqxtbhnqfcrbftfzxjlbxwrdbvryeleygpttsgusileshrxvqkguttyuwjvhsobenqszoyjmspaaxprqxdmqfzlrwuyqqwsqjidxrxhrmufggpplcpmvujuzejtyejbdqzzhioydcwoopxgeycwcbxwyzghwdrwjzzrr','mkubfcywgqtshmlnycsnvmilvpxsznmvwftatrblhewzghbhkfdyramzargvgmxxgdhbyxboozzqydjtvaxsctjupwkqunbeobdnqxucenegmmjruqtxinpqklvtbtrnpmshwvrnqptyqegkueyigrviyumcblyoimomkfuaikrjuhqrspcjmkpzpykqvjivkmlfqeplookhffxuapipgstjtdyvettmeoyuwglckfadpp')
+;
+insert into t2(a,b) values ('mrckaklfkglubyebqpafkspyplkmvruhebuckdtcdnowztpmtgulygkxihrbcdcaehnllmmknqsqnmggsznhkqqsujpvlixhtyqctzblqoeqxsndpujqmffpiglhnkkqmblwyygbdrgpnhqzjshlndsuqojuoldejkiskbxqxjbtlnezrobhkegjzglzufujvkvyewdgqvmpplcrdgrrviguovedrgndletvtsunxuaxfghkk','vlyoaavfbmelmsgnorvwpxfntbgs')
+;
+insert into t2(a,b) values ('wbxcctpxlimdzjacxozokqkvhopfqiixyxazefwtocnerpjfhykvgetgkxvcuvcstvshbupfsohijmsjcibgbfpaspiizdtqoibaqwgwqmyrflpakviohhaqkhaztmizvshzxiov','wtyxutjgelzzxwzsljzfjxbyihhfrqikvxzdfmtmuowfdprzetrmsdtypscszxxpjsnxzwyyymywlevguwgzmquhgcqdalhuhfmsnajervzjcvetpiyhfajyuvvzcilcndgixqumfyrvhggwictfwt')
+;
+insert into t2(a,b) values ('xsaqyiatfekqtvszrtxicnevpdojvybfrnvpjvcmxziuduieepbxtvimdwdrjvjbkmvsxaaiugiyltidzrmnxmxybfrqvq','kxyvnpraemyxtgasjfvzsmnglhhcguelvvlmbqaajtnjxgtosocsclpqmlazidtdmqkeubquuvwmqgptyjwmlkvdnlpfwibhfjdarrqnzeujhyxwxjlvkqstymohotzxrscylwhnjbwnmxuvctgjlxnvifvmsnkponlvlqpeotquwdnglsiwseebzcrkvekehyvoifejodnixpt')
+;
+insert into t2(a,b) values ('kekrsppfttswinapcx','gnjctybcwiayylbncmjekaphjovnpbxrbikzhbhzjmwrblefavonziwsbgdjraoopgvazwfnoymwdyyddkwrppxuoyyyduugegdttxpjbrdjaofrue')
+;
+insert into t2(a,b) values ('pvmbfnlotohvuvifuyw','qlqqydvwxwsqvgkxogrgiqdgtuecsvtbyjjdfdliadlzsvtebhacgqkmjwkwpzqwrjzngbfcgfbph')
+;
+insert into t2(a,b) values ('xpynoseezzpihrwmstkrhgajhzsplkaeanjfjefhxnpvewzqjvurdcgmnxhptwzfghacclfvehysvuqmbiuigsumbtxtkfwsgrctnhurownqonzmfdopylwtwxthysxdkczdtiqtoxrqxggpsgubouwtctroikgtgivchbunosdcsshfefenpyplfbkehinfbnntvbqktfydwwhrdmrkatvhmxjwvffptftjoxuydfjnkicxz','tfflpavzgmsordzegefklmgabrphdnefiznkpnmtt')
+;
+insert into t2(a,b) values ('hmnhoiubidhhdassmjcdpzmlteowratszjyxurwksrkdnbthbvuqtgyvbsrydqlgweefnhmdivebmhtmu','sxozlsztptbkxvpwmcpeuddwllmalzomrdamrfsudxmfhydthxvqnunugcpzrwwnggxgoahlddgiwbmokavlfgwdvgrtlznsoxzqssdqeptmuyfiubfcejaficuetjyftpaxfvujmopapgzqmqjoltngoouiqsfubjgiosroujfbripmpuxwvnfslltiwrvvjvpiqmczrdpzkfcgghndmrfvzjvd')
+;
+insert into t2(a,b) values ('ealydgaxacyvhctnvhryhnykfseocaazmrhuulbjpwddkownjokxilayptmqkebtqsxnvoemv','dkxmehtoevdeyjcnqpbbwyvtxwmlahazqufdfrtutlqcwpoqiummqctskgordorjjwkwlkmhfsknmxuffovtsjtiurahclyihmlcazjjgbjgkq')
+;
+insert into t2(a,b) values ('fpnsneiubpijbwlvbsrnzhzartsrlledozptvbysytudkoquoggpmtomejzmdpwlsvnqxizdnhwfcsdjwpeqhayjtaxuhgjuqfhxojvvdagyckaivecc','efmsihawbupqlistisosxieytkzetcnksmtfdvugdb')
+;
+insert into t2(a,b) values ('qdaggfznphkbqvmpdszpaezuzndgfecgevntaw','oacpcnmbkcliltotdwnaicmexaomxlquqbfkewkemcozjiwmvvwzupowqgqwrjjyqcoovhqrvvydcsugjctedvgfizfqluwmmqfyxkabouoyjhvckvkfzonwnyrfvqvdyivjshinfzaxztcvcjbqsudxoartvhvuktdtggdndcarffjtyrztjpagogiigirzwudmkffckgoqlpbcvicuuzwstvabipubdnoloa')
+;
+insert into t2(a,b) values ('rthwbylrfummakapmsjaxmlocovuawgrcbkxanprvgwuohqvqeoiyvjdnprnklgnvbjkxymyjkegrucjclmzgxgequvemxthbgulijcyqrsguzswlvgymjahtqxbrcbbogxsosmsetktgawcegkzigtvakmnzquxryhckdehy','iltggezqkntbuwxgfnijdpmthoxyhsnxdcucdmktoytsnof')
+;
+insert into t2(a,b) values ('fqblmlahrjwqxmoxexkybhgehexrqlmufsnqfwqqhqfwqviebcgxykmzehfucvhzulucwirostgeehifkgrfsayo','owjxurunnbpcg')
+;
+insert into t2(a,b) values ('rkexhpoorsyaqpyixsanbpluwlcexyuumlhokbzwqivracapclkodxjlpamuzfhgnmfwimznpnbkfedeyhjmbcqvcydxnyjzzolkkioblxwncnysjkpgekswbgfofxszqoihjpzayttpenjczvysmf','yrlgyxcvwitxgcpusklwbkzqpizcjjjlylcxpadmclnissetoqvipgzrnywvtjtxhcegnasmeofhyhobeekmzfmhfygxuggjsszzjjoylziozesqdkmcwcykdkswowlmxqbjpwlcshortgmnvbxtutarkyynjzvggmkghgmzaxpr')
+;
+insert into t2(a,b) values ('svfbjdncgrcxrtorgmbzypkhfrezkhrmhkkiczgjrmovkqikbvwemetmfbynnuqvllezuxgiugtvvfhokrbygovqdnwkkvyfbrmonbfzydwixferkeizwclwmzyhvdajaivgrgvxfftgmlaktjrjclzilfvgnyqkxhtvtmnnmymfnyoqbojazhbjmxqvoyiwafkggsehfwixqrmtdvxslbjepch','ciruypenhzwoqfhwsmpzceztlnflikvswqwhqgwcdcxdgxkafodmnskmgjfwolezsrzhvtrznqxljcytvqjsqmxqyyftjkyletccagxbnjrhyuadfkpyijyjpiexovvmrzmnrkhopxoxynlbhyrambvdxygxqyloibksnpatnt')
+;
+insert into t2(a,b) values ('vvcyhevinspeamkqpjiavtzdtzcbzurajqvxjwhdbpvwjlqjywkfqgqcheyxonbbpkmmeewypxrzrykgstblwcyazcpjmnqcxnzpeuyjrhpnlqrvwjimpuvadhgximbjxcdfmvjnutsvwmrzbnronwkdlixqakrxevqgmuyyxpheckoghyexnpgyc','pcqgqhttzpprkatzmbvgtvmuwzofstdvthtdnwedryslqjnnpjyymyrebkjqmtak')
+;
+insert into t2(a,b) values ('gydrqhksuqhzmwkqwfawlfltvdzzwwixljlmzoiulksnasepssnrbldqwoqcxyyiuzjzklqzplwnafxyprtwpczyouxpuztkbxhreunbyzsdaspkzywjhozcwpcdikoswenkmkutxctximtevqfqabxbvfrwtbvlwwwwgjricytjpdkkbtmnzlkhsmhgmn','hbiicydsxsosqmvgtuwhcpkpqmtxfaazvjhtmncuneyootnjobirtruhazropozclhgdibgzvznecxcotsjfndfqvcjnlunnhzljidikbkuedvcajjnioudjkusellswgmwjdfaiihuqfedmcoqygnoocecxbdjlfvd')
+;
+insert into t2(a,b) values ('dmifgzfcenobthbauraymmjgikncffwycirryscbddxskfgbdiohdxhmzqabcspaltriyztuwbswqpkzpevczgnftcqsddacmjaeadhlyyolwdtzvxgtavdviflupughrwmyxsakhwddinnrftqjzvmwireedjexnuyftmalhoobtwyrhwrtuzzzxhib','cawby')
+;
+insert into t2(a,b) values ('blqodjzdgdgfzdhhjhcgjrdfeckdpnxhqlakqstbvvnmnrmodxidemefbjdxstpfoaakycgnmngugehmeydmcmtwxnqjzkqjilsvxzncdkdzqapjohsohfpoatapvuqdceijgllrkagsczdenfsbmdfqi','hggjkhmdntuasypifwnpnkdflwgzxyyvvuxtayazraqjghlhqygihmdqvrhgblruyxlpgoawacvjugvhjcyspqpikzuivekwjqasjgnwwlivmtfmthryxroxvsamnmqcytmfqrvlarziwseljsvpendvqtzdputovkhsceybuuidzgswhumyvpcsvmksjbejpsvkfabmjlxxpyhonxmx')
+;
+insert into t2(a,b) values ('ynogqrwqpeoawnrpaxuzwidzqntpfhzvgearrwlvgirecspfkslaxidtygwidpseuzbejtitvvqsuihskstmeuhpexazhuhenikjgtnkfy','tqvrkxujadmocknlxdohylllinhgjxaosusfsqwpntrutynqgcpbudeganjdarueixzdtlzxdzdquotbfqfsrnjbklqsktchbnaxszsxfkscmxscfxjjyxfgqvzphjqhuwawwrzdjwnknwgcqhqmxqwbqkaulzejvklltkvqvurlhknlagruoxtpxeknryiopfnsslwhwnufmjqfioynvlzn')
+;
+insert into t2(a,b) values ('ucshubzzhfaftlimmolxbvzfdqdzgcuyxukiigkftmcugsrvrcqddhvyducrygrlmbdtysohyvsrrpuudzxgqyclsnmbfqvwndyybkzlcalzikiegztjmhewpadhbk','pvylqtkkpayopvejjryjtzvnseglsjsiojcvelsapjoshrteenzqweoo')
+;
+insert into t2(a,b) values ('qdouvziqvtegtyrruadlkvvedttpkvu','ttsnizhumfkswzmubdjvxywzezafzjzassaxbowqxceqsfovcepol')
+;
+insert into t2(a,b) values ('xfxgimmkyzffcnrchhlehirhqrmytcdxqxbhzsxhxqxsumrcbkwjqugcrmbjeyrjbyeiddcgxbfdbkhisotxqeixziollmysfpfnrwwqnnydpmopaqlzciphlzccblmhfdkqtnvlvvomkekedrpnhwenxxlchzdbtowwxcistfcbjq','clkdpyobridpwwfuaczfuctmxztxeynwypburmzhjualvskxk')
+;
+insert into t2(a,b) values ('yiypfrabhxcvggjfv','yyowanosvllnvfwjsjogtzfdkutmmpoagxsggyldkndwogwyeucxwuznuwaufsnchgpmicpwgudfxkywsgg')
+;
+insert into t2(a,b) values ('vuyimxsnomdfdxcejiqnaaodugkgdqlajvqwqyxbahxpcegdeaycypwuunqmyjmvzwsbuamueudezwzl','ynehszmvlbvgeeyodqausbrvcxvalrqnebrnicvlkdyjkbstvigjqrjwgmznzsivqjedvntrstmbkhhuxvhyibqcqujzdbaocfskklgaqhaunufmgayjlqejzucendifnigmpnoqygtubtegyvoircrrzjrbkbqgkrfdujorogsgcuqxpztdifjucjpuyiusstctpnobuxnewljwwb')
+;
+insert into t2(a,b) values ('bfqmcdjcezujvpmnyvrxhabopirryvpuozyobkhktoiuuavqhtdqprjqyqgenjiicxfzkeelifyyxzyeqidlsgqgtgokleewemdehqdkqrsdjetvahaoqwwzuigbfgkuptuquueksgzdggcfzgnqlaoccqedjxuqgwebnqtvpkrwiy','rvpgqdmzoydslpvaetqchouthpf')
+;
+insert into t2(a,b) values ('fckudzfoxniycgoxouuxwrgjjpgzzbxjlwtvvjqfhqnyekadmmhbtpxgxciazphjfhlnhkrheovcbowjzggkxukdhmuvtbqlvfjiheatflfshbuvpwtmrqaeoetfgmnfwuwdutnyvknjdhejazdgtvdxqwotcwtzvnwwvyrykeuaripbbbdlsqresklsnhnpjv','wdkkaznoaqwtizwwwnmfxoxyzjcswsvzyhplhvxskqv')
+;
+insert into t2(a,b) values ('zmmsfgtohkezydedgpkgipknjcgsdplesahqtfndqynhtrgjnryyicwogzmkoufvgveatkevdceaiahjgigxcoqjemjvfwdijonsyiazttnebcbcpilumezlancnkbtwqctegjvotuqzqenseoueapwqnqurbsvqcrpvnhpstrsnkykyizuphdbytbmxubbvtiinjtibddfrpuetujtouefturfmnwbxstjkefuxmmlnbxxbbry','uvztrqfjbetlhuenuyyxlkpnf')
+;
+insert into t2(a,b) values ('fuaswyekqqamyuxpkhcmxvvvxbbsarcsigvpyxjgeapjqvuqsajdstbzahvncgicwiumaxqkzzzdvolcoeacnmuifjolokkdduiolmluwcywinildlmistngiwdalwxwamdfmyefvrvkgnuyuycdattmegnojjdtoisjsmbdmpihivxtewxhlhtbtijtjkkourerkgmylaclfkxa','dprqubycyrseljpxpgnaqnpokhnhlnxagrnfyosblmyqdqngdnfotwsctkmgpdixowkfybxvifsrmggrxpgwksfmdtluhhxzqfuctcsmluxqqipxlhwhfcqlyscxykamnxhmwhukgnkhwsdcuvuokfugoxszwaaevkarpzvbxmjbvvgnevltqzlrcmoblrueektklrchfrdvydd')
+;
+insert into t2(a,b) values ('bqfxwhsxamfrhgazltosszwbwhumigalr','t')
+;
+insert into t2(a,b) values ('kuzjyqajqxulcxfesbdkwfrojtqxsybtvnabtnckpytjsdklfblitkzkqknzhyalaflpgoyyl','tuphtlbkbvrswaayipljysqptzmwkqjrqalzdfjvfhiverbarscjzeimytzvgpgfxtlhpvsoeqynmhudioxeudhekqrmunkglnipkuvnqieiuszpnvhrhmdieneh')
+;
+insert into t2(a,b) values ('uoyzyswsqqlfxekywlietngzllzstpcvyhpcaowumdljtqmcwediwczkxaztsniewhzpajojsrnvouwkpmbcpyryzwegpmrqmiipcrcraqxahvxamhkbxthdidmqsprbvqkaamraqypffhmjpnqrfqtqlimasxzmlwnavlqcpoymsbwbcpjsbsavrvfbwvbtsbhlwdsulzaqtygynhqauzwulq','ztbqxisphkgkyoxivnqlnjcphqonwfqdmwbdzgflxhkwurzeawxoxqotepqsfnqcmrywfhonfwaequvaxsdsebgmlemdooaivoucdkqbsnohqpcgstcjxwgjjtbcvreijxugsiagpktuajltilczoifwjvzyomlonmewhhlqecxyzvlffahwicykuitxcwfyytbbigspvbledrisjupuhd')
+;
+insert into t2(a,b) values ('bwoyjrxcttbqfbsjulkwnetvjuzfnlecqthvkivopamqgbhxkzmcnfbdcnrrtbtzfdxftxiypwytbj','abpazmguywqmpyxekmiftswizkixrzelqzsiclrifkgge')
+;
+insert into t2(a,b) values ('svxtldrlwxjkcnvudgryijieleupteomlacwlarbstosiqsitvtfuunwpgranwsqkfgzvznlmeuapzdarnktrayoohsdjnkayojjidmsvleresplolopsohfmcmzlarmdmkobvykkstbltiwjrzrrpefwnluerlminwpwgqvxaicvnkfvdynsosfklwiwyvrnhwnoapusqcxg','zxtuzaroodfbmjpktpezbtrnxssjzfsrnmcevmfvbmlcifvffrhwjporfysmqdkpudblbxuyrkzjheaxpfdjhlglrvvfpgdcxlmryckvsknnlgiyusmouccmcningnjlhmbphcvookdooormzumklqhrzxeevxlqzefri')
+;
+insert into t2(a,b) values ('nctlizynxwzmfjklbxuqqrhwvmofofzuidrakayakxynznyszojtdnxgrjvwxooihqhvxzybddtwrdrbsafwacdcrpzhxzcioepwnkgtmugsyamhszalawqvvgfbwysflidaaljwtcrlz','qhcqmzcagcigtadstxwurdwyxflvpighkplcaqzkhosnskkobeziqfkiuixbdzkyvvnsz')
+;
+insert into t2(a,b) values ('eahunxdobnqhdffoqqdqtolvcgveseyoegvpnocvsepnavjduwjhibkboyfzxlskxdtqixqyvuuktvtpivbtgrbpashgzoqtunijrgdearkputjgocmgwatrsfhjfqrtsnmhdthhfqebgksqecssigebseczenbmrmxkxejtyixejeymeu','vnrccvzdtaefzcoadqhbfeffijokoczmkeqacnqkwzkizimbtqjfmwmsxnuhwlyffwhzxtayovkwwnojpaardvhehrabhxdomjuclhvxvtkdfoixwmuetuklqwdnztxwaenxykczvmnucmjqermpivvxquhdyafldbffkwchcqlwldjfcwsqqwypd')
+;
+insert into t2(a,b) values ('mqtjlrakcjzbnmdtdqipwofjzjeiwucicqbdqxvsawhzmfgapedckjxullbuxjqfbpqkbvdovgmvqvizwleiodwynogcqjlbwzebtapioyjyjdxobphfuxftbftbpfowcwnwkdqcgpibgwwcbzkosagduoathkkotgdaqkxmucjzzifzwdrhqeeixotwrzkzl','zyotklwtlucazdmhvqncsjhlpxjmhuymskfrnzkyiycqjvummwrjbcgopqyymuzishzhebuuffynhtgftfjmweuvhhsrjumvdngsgrmefvboczjbksfjbqsduvomcidxlyyqozumcebnuireniudhoclycquxkibqhnlmwwlkaguwxsbkjeudgtxzxyjjqadwuujzlvc')
+;
+insert into t2(a,b) values ('xmdhmdierirejsghsaozgrwispltmblxiwcntypihbbwqqkhtpsilozzomzfrlqpomcckrgiwbdbqwrnsymikxlfbbpojqlapyqacnyjtsiteqemaijpmlpuofgxefsomcahvstopxivczjhufevlomtwzrggcspyenqlcosszqimzyuyekmzywnfhbdqdijnirfoftpafkojqlwqhptfacdogzqmwwsgaebpvjualxdcr','tuqyniufkyvlbhfyfxeeeyhszktrjbhmlbnkzzbdibdshiddfddenzmtuugrliqotezaziacojiwzpwtizwtopvxivhqjjuqddjubbzuosrxqxujezzbjpyibrdtnbmznifhspjffrbirkyphvwvkwcvbckwytmrqymshkmovirwqrjdqltesbfuckfenayowiwpqhb')
+;
+insert into t2(a,b) values ('trxsrckwrspsblttlbkjaxgxgezjmkrkdplmmfrmbuvxrjfslmvjhztoizmbcpjkushaprrbbofalaxetozppfhhmmhlxjksacngjxhkdlabnuzqxqufeurbqituqcusqbrwtfyuzpdgojjqcfalzierdsusuxebinladiaujdsrwsicukdpesiufwitdoxzuoiyirqmqbheyegznwwfdzurwypfikimsbiiuybpydmhxtzhdqgrjppdirh','yfdilydvjsaxkgdagestueyiybmrcptrragzcvhkdvossbyjibmcwtgihttrvcaofkhonumfpqfdcsvrreyzupyrgljwfdovqqdseyzropugglgrzwrzvefjjwmpetovvakpiryyahcpqbmzxmnvfvfmozukbswccvobhmbulcfzzcgpqrypafthchmbwgfruodfvjgihwg')
+;
+insert into t2(a,b) values ('iqqstjobazpkthyodmqjnkpxgsmwnkuqqiymjlibpuuzxfkxjntxcfmqbsmxgdvdjqohstjzwmpdjiwswvuexvozzamdldctenttmediiklkppfutsntzqcaayqeoennwmxrjwrvjftgayxdteiuvpkmigzlhy','efkfmdjhojxsqrykyzvzsiwgwufysygbjorrbxungqlwttfvldkttjkoujsnsruminviwjlrfsjlcwryvfrpiunmmetlapgrrdwwdmuusgzzoznsfvcibcjrpxoejbweuxewwdesietdprvcmpaqiwirqodhficiomscrbkplekuekuqmhtn')
+;
+insert into t2(a,b) values ('fcmcdgpkvsuhfjsehgcjtstuhmsbstfldvnjkciqjxeoqpzdngwbsbldojbetsy','xywkrikvieiukywbnexbgehffefqirtyhotqckwfmugsponiziqbdqfkmkkwerbnldwmgpxtijjkreipfiartlbqgvrgbjywovbtwdihcbwjttvlxdjagefhcxvgoxfyvlanzjv')
+;
+insert into t2(a,b) values ('spwhzbcfoouwtnjdfggkivpfwkpfyedkopfkdcaaupzaneecwfelkgnqnsqgtbzqvf','yaujvantoohglopsbfjlmcghwnglolaefbeoxojsxekjaolfrtptmplfquigovnvtbqgqekwfnjetsafzufizlrmmkrnputvpnhjlmpqpzykmhiooignfedkfbkjlytkdfpecvsxudutholizpwntsyutoubqdvksoitdetdmricgjhnutexzijstqiwsdhunnxbgzxoodnhnykdkwlobaynqzekzrukfejmxaqdeloj')
+;
+insert into t2(a,b) values ('hruacwmfwgjodtqdjqghwxqijxreqtgnevxyasavmglmcqckofhbacwydondtctrdzrykmryzcyrbbqw','xhvatxqxqrprbtljbslnlomjnneixhhglnaernxjkmjdmbzrvscfibkrsndauvbhhwiclbzckkffsyeemwvahrfykupfbtbrpcurnlacsitzdrrawdroqjuvfxokqiacemwcavntksnmmqhgwdvwnyigphuyahpzcsjnhluzggpkaclakojcqwimxpyctmltjlphcwmkulzyc')
+;
+insert into t2(a,b) values ('nriybelvcqptwkabnlhwosvqvteageqoxfrexzhhtyqngllyeltarqapzecxqqenvquqvziploxcmnugwwvlhsbeheoplmzydyalswlkqpibyxnkcdqiryspnzonocoaoycgpisnhhcioiwmjbbgegkgqboftmfhwnbvpanshocimsno','mkyfrizgbmwchfulnachowizwxddbcaoihawhfqhxugyezcpzlpewqudqyvpvgzjygebimoifdnuvtfqoqmsoqwnsbpznlmsknanpuwjrsgalrwwvupkhxbmnaamvjihzcmmarmodripimlneqkncexrfhaculwxhgsemwjfuejqgrgwnvhiroudwuqwdwjciaqnokifbuydtwcjasosqdfoommrwkfavkugylmzenuasdeeyjzaoduh')
+;
+insert into t2(a,b) values ('mawmzwjzcgxnuaniqwlnlshbdpproawxkynzcdaahowptdkxcyyrbskqajlmitpynyjyinorgreayfaaxfyfbzayapztnvnevrrpyqxqsaevutxwbsawakcvuiuxbpsvafcz','baeocefkesunzmdqdhbrhdwobzrxpmlvcksxwcmtqdrzjlwumvmlnmbbcqhkhvbzoqcdvcnolbnfzzbyxdkgidcxtbblwntwfrzhmpvnauaalhqryuvqfozmmeocnkllyzzfvpnsnnbwkplbrvtzsntagnsxftfvobscwonyzmvbdgfearrhjwuqjelbdosjzgxdectlqayehhwotwqozzyotklwtlucazdmhv')
+;
+insert into t2(a,b) values ('rzvbbujhodbnsdovrywgjhomelxzmvvnqdfjooehetrblmxorqqsxhefuksmizgy','wnlnpupfivutycbfcaduovwykmtshoogxebqlctzwxhcpoxwdiqkdwikkvixpnqfts')
+;
+insert into t2(a,b) values ('gwnosuvdeuwpzpbzqttiaikfibzmylatbwgjdiubilxcdmeooaoikpnsrxwjativkouqfwooqzyujkdydcfaeacrnopstjolceoozrpslwphvaaypzlctjvaaixkinyexqbjrvedzavoagluivwyspgh','jcffpzrjwshcbvvlbeioqcxdefrzsqglbzhytqsffjdlxsyjkgshdsoraktiqqguahxjvxsgeunjdlzyrztavchyrhlkvvyqfqpypzdouqfjwfmvbtiaqyagnqe')
+;
+insert into t2(a,b) values ('fjlzdiveelnqqfdctwgavcdpgypnsatuejrfjscpvwcbbqgtwymfarxmolgjiyiflcamtyxwfsqdfjyejrfwjzzyvjmemlewbiefrilawsqusjepjzrjimbrtzzdkactwckysklssjmahyfzzmdyqgwzuhngffwxxaeneowofkujijypefpu','xkbjmxdivsjgzktchmzxktzipbuvphuqprrnswahipocnomxyuvzlxnodeoufjdgacuwyrcwrpkwrmhbawalketuitknvwamsxysohamalzgjojcjlrliksasfaiuiobvlwhdiallddaqqolntwtdathodomgrjyxkmdufzzpbzyfjdgkabfktuzvbvaklwywcsjexahimplxojpmhuttngrxx')
+;
+insert into t2(a,b) values ('tvenqoqlrhjwduirjoyvutinhzkwrigzrmztggjxclccrqrmrsfxvmqxthbgirozulgwvpglnpbzgnkjfwmdovvjbpqsattoojqusivooyptzcnudkdbjknqodnbwhgzkpsgtt','saeglasokfhauwzvuserrvynzqhojpquahknoujfmuzbuuxzyyumcqkbubbfguhklhcivqmzimmfguuzlxbsirifbyziwrijzmfimrjhetulnqjvxtuiywbpqq')
+;
+insert into t2(a,b) values ('znlbyynbnykohocphhhhfnzoqwxwabuvwgmfrknqhqurlwdnmnhcodobjnfhpbktxkpuzfvorfdyestyciegujpcsfjdwveckqueqdudedosohsdownsjbzkowaylgcwamiigcyywikkwcduwhnfnbwtgynfintlkudrppdqsfxqvtkejqmfgttkngkpqrgjzxdulajzoxxefffitlpumvapenqhxzeekkxlyvh','xcmenwibtsvqfqembquzwjkitktvbwggstvkyforfnyynftmlajoizddbxwgqancixskongjycksbpjxndvsjndhmlpzvpxnujbepyehuvphvijpruimbxziglyfphjxnawdsbmrhfdtxqtmbmtngdqensqezeugfexezvslraqboajulgvtlwrqhguftjyjackctedagkcofomgv')
+;
+insert into t2(a,b) values ('hvtckkhgpxvhfjhbshdpqsxincspyikbtonzpotrootgwghbcvilkliigeknepgcmxhpwuzlzlrscslfuyefpduohpjybolszjbhvkzwhyfmisazsjeudefdijvttsudmnwxawthcubpwupnxwkddjcwgahlpyjrxqqwwakkiwjqybxvkxfxmhutoyqrcxebcfrpqwhhdeoe','iowiugyvolhwnq')
+;
+insert into t2(a,b) values ('tgichubxsdhxjxgmmxgbeiirhblebybpvheirjpcjtaodygbwsmxhpkrbvvgacnqjluymhxzudhuvpwoykycrhnypj','flbarsulhhgewqhergzjflfpitsewmhefiyucrxyxeghbypuglmudtpwbuiojhcahbwtlljnzmzwcrvam')
+;
+insert into t2(a,b) values ('impberfrjshcuwydodmuiivbmgygz','kiqfxtundzbnizmjagzvcvoijnyyxqoouizzmzsselcjxqqhzdofgsfaxmyxvmsbcbdbuslxkbdfvxdnaqxsf')
+;
+insert into t2(a,b) values ('alojrnelnxctgcszroimrowghd','axqnngfyckbhnxr')
+;
+insert into t2(a,b) values ('kwwqkpeboglhhudtixqkukno','tnsbyfuuhzellikkzxkbxfhcllgiwaolzvebvsvjqmme')
+;
+insert into t2(a,b) values ('oahkluoksgeufpoittypiivvwtkqtajbxrabvgfgxdxtdxqbetccdrtvlrpujgrpecibjvvoshoykrwbhubmmodhdookaxrwkxpbejwxzqgskdamxcqubqudpuck','slnzwpuuvcwsvuedcsekkutuwlrfdthgrvgxyifztcdggtradnvvwztjgvnanuellnvojfjaggvmrowzrzdgznbcnvlwzjnyabkbpkxgvhqeydsetfazmoloomnbiuehtuqzhjcxbtmfvkcioywcyowcdtvuxfkywenkretmhhjgbhogaefjartkfxrwemckncredfiotraputjemjjusbefboktfeckgizub')
+;
+insert into t2(a,b) values ('hpeenpjjobevpitiuirrprkswueklwjojczqewdncqdspkccevttpbntzujilnytsaqivunrgjeauqglblbdprknuonpbsvpgpejxmaxflbgmfkdvpwxlerdfvhxjlsummlgfnokhlbvakybqznnljszmmfkfjdxwnsgfqtzsvupqmzdfferuvjytvgkdocxovgtpzcmvlaeysadrvncwjkftugbzajeua','kbjlherbkfhnkenfqceawdhwavovijjmsxlhuqfdwdjjdnbtsshjsoillysxpnejbnnzzuozpzkqpxkpvkainksfjjxfnqtjfxoumtytkchgxujdwpvvfwoxdisctvoiwxnxgttcvxrgnjpbmdjaxgxvzb')
+;
+insert into t2(a,b) values ('rnylknebgmjibhdtegktssdhvg','honjbssfiatwzglkjxweqyh')
+;
+insert into t2(a,b) values ('iklbyzrmekrfkpswhazdnebxtrfnphdnmlnlxekcterckhvoetxvoipmupvmbpuaynghjqjpwezofjnhcjsxpbpkfgetifaiudrzudbeygnaburpyrswycubliauajscphgmeayyfuzzmwwljiokxmgqrezwnhuvixlsbyauiletysjbfvtvmkrcujwjgesysgufvwaejruqemmlcobgbdypgtixvcbrryheffjiueh','flrirzliokbavvjbhzxncfpbmsxqxscjiyqbfqrrnuznmyhscqrjgtorwluyagynanyesrtveelzfnnsaezlcmslpzwuhnnsfunubzlpngrgpwlkymixstysrgvfertjdicxepqfecxruydhwidtjwuzvrgssmbrlidtvumyikuukyfuufzfqjlbqzkruuglczcjcztfwipftoyuwarlbulimzqoeuaknby')
+;
+insert into t2(a,b) values ('qlfkuevdlpqcjokqmetsqfankftyfnlambeaphlfydvflnzbdxxcxwiuycdhbepoovuallquduqylbkyjkrsnofbcyejdiyytkhfiucxtdwhsspusistdsttfrjbvygqazdzjpwcemjrbyvppcrjbnprhwyiv','azncxjldlleexughehvyzedpbuxdrxtsgqidtsjozsgieifzryrjinmajcggigoytmdthkganfwamtkdattxfprqzklwkhviczxqjqkjskiogmkyseruwec')
+;
+insert into t2(a,b) values ('nyqmjqdqsmlimxgsjbbdpkuvugirwrbisqmpepsaambqoadclcaiigftymtxmumbytbknslxsepgxmkdrthdseuckzpblmzdxbysidvgnkstjoiypwnpteguyqogexhbmvyzrijfmimlzmodfuitnxncimcntdkfmqjybvuguxlpoytjsok','cirwmgzhlsqsmqzjezmdcbdzpouvaegcpwzxinwwinqxnpyjnovltrwqijmxirrktrmoxbfeyuupoxvmwopvdfllfbqjzfqkhijnxhlsnxzhilkllenivjqutqf')
+;
+insert into t2(a,b) values ('','dmbohsefqsoytnhftrpegreclswnasflgmlfzvsxcqbtftiypqnlohkrbrvjsthpmxhrqiklqcnrlclosidtglccsqgnttfsmwngiegjddacminpqptpjuppmomevgdbrhxtcgsawfnkbwxczifznutkwxxiqyguczuoqmwredqkqqreqrurovucswdzyvxeyvwbspc')
+;
+insert into t2(a,b) values ('lnizhubpsvxvkquymmktemsaeliiokrlbrmmamtdzovcavikljlnernjpyorgaviwzwxiwgrngohvbdklldlreiosedcubqkwxeqpjtdcvbgzkmsncpthdgbyxyokivekbjqdgvvkdgdtjhtqhdlyhwfcnlkfomrjiouautjckraqoqiggtvytlnbqqafnukearrqmdrvpfwuhokgvsdpozsmcjwvitzefmntsziii','sulxfwltnncrtzqtjytnhehqvdcmuqrgujbhlwfctbwizlfllzrlxbrggrzhbmipusnepfs')
+;
+insert into t2(a,b) values ('blxklppmwdvsi','rvumugnfehowssmwiozjzktpezsdubbdzbqetymdliujypzdjqcjqomwcnncjohdefjuawqffdidxqjqipgzatavavbyyxojcunewfszaffkckzvkzaafhjognornebgfqcrxcrxknhgeqofvblqiurlnaghmnpqxmapeplgtdjlwkqnnnawcrifrhjcfrekiidqfeqnwmojokkspbgcdbdohcpkvjhlqowuccajlcocftedxgk')
+;
+insert into t2(a,b) values ('gfubtqhtacbovleqlnahljpkrurdyqsfsuiowezdywduecovupswdanhywigdsllewuqczzxgdxyyqihmezpwvjzgfuoxqjlqfscopapnywwoxsdawfgmjfalfgzyozvzdofewfjnjupuqjvotncyxyelyajsiyrnyqaazhpsqntmadfkzgsvpodwmfrksxrssblicztntgjtsdmmhonkmcjwntekchhzulfavsrlbdb','hgwwwqtewfztwuikwplrgjirmbqfmetvycndqttchczgbwezjcgozthkiecbdvyvxddsbomssibazxllsbrtdqcksqmdglzpgdinpzfrlvud')
+;
+insert into t2(a,b) values ('yoepuwsxxuvugrcjvprphsddmeiwijiaulirvhtklqlnlrhuzwjktxgkvbmairmvtinzuwmmmukipyqdkmsldhxsvubygatpjhepecpozsimhscbvmiqxzzyujsowqdqwrmifbljsqqccvpproqlstsqclbokearipgjbwasfcahnwpumaklbodhddcudagamfbufjhukqolz','kytmtjwicfxnkfebvaougzkzfbkzniyhgjutiewidytuyacuzitekxinsscbacfslowgmkvlurwykkelkxukzwhislfudibfcyhocbbmzmzmrlwkspzbnzxpbvsbgkrhhwfvjwccwwmv')
+;
+insert into t2(a,b) values ('e','najibopnluxeflvvcybkzhjatnitx')
+;
+insert into t2(a,b) values ('puyomskntsykpmzgvoprmrousybxzetpwgmhhzrjpkvjxoaolixemqeicixyduqynwbvzf','ivnvpwghtvcoxbfqsezoobqtyibldqlozlsmfdkolbuktfdbvrrkhkcivjozoexdadbgldzcltdkamwdlilqadmbxqtuyluhrqumpezaqncqmyjjjngaxdsmtxibyzxiidubnhyrklydbfhlyleckstpljpeamsilm')
+;
+insert into t2(a,b) values ('fzwptigailcxgbwxozspjkgkljwc','heztqwhdlqvagxriyqstvrpdidxnmhxphnjhabpdftqwgmgbdhpwmsfeayrulqxtsiosvaesklsdfrugclznzjxlfugkftikcpsqrrbtndlvzachzadyrdxvuatjkjaoscmokfaonlikbqiosxmtnbtqborlrzasrzflkmmjamfamjpdqfalrme')
+;
+insert into t2(a,b) values ('ahxyrrwpgjjmmhmtjvgyhmahmvbywocjjrdezjiuujindeofehxbnqizplrvbcuieuqofydxmxnwrzmtzoxrmfkuqvrntrcrgvhlykiyvfnrhuzowuzfnrkakeyxzsgfgwvqmvzbfzbzxwzosbmaelqicunwuphgigsfxsgbxdytjmzewchrohwrqdyjhpjllgbdxycgodrqcqsadazpsjuzkuwbawqo','ucjwwmhwoytypfoelmguquwrqvqtjghomieqxcdzkdjjy')
+;
+insert into t2(a,b) values ('fsoprnwhkleyxqswncdapbgjyosvsmbucatfnlqyunjvplfilywajyuwzzsxsneubvabqiqzesnrwqywbyjltjrupbxzosgwraepgoavazirhvfdobpvcevkdjcn','rcaougplrlmcfmxsdpppliqaujuzqdnekdwdakzjklsviswfxjgunjkxnakrkplvlesqzlaqyvrfrwwmgyxmbciqoloftsmyhhupgqjbzwzmycbiiiqvmingtymkbicegdblakeqpskabzqcnjsyihhvirgogqscagpguktbqttpxltvrffpsamcxdtrxfzvrlcxugbzsaotqgr')
+;
+insert into t2(a,b) values ('nlupvqjkcjtrluvnnooirjppesqkkzhdobestoagkdwrzpfacjgrlvwpvnosgcwktea','iamsnifyeiwfncyldbegjfcpsukotwtylagrqhuzpqftzumpfjorrilhmkjybbzniliymkonodpndfhrzaxynkyoygwftaijkfwzoupmuatyltzibwepfsd')
+;
+insert into t2(a,b) values ('lkjyrlvyuynwkbqyxijanjlvwnqldrdqbeycyynoentyjmtksmtgytl','yduefprtlccsdmjratlvkgbbhkwiqzfwxkikzazudjugsahbcfjjolvqxpnbpttxrslatfxngtvrighcwswouhzpgirxahkbmvxyomvjkyvnrpagkuqbazzazvuwiggjmwawemcujatxwfwniqvkeouofmvznpaiqrshewbsvgucslwqhufhexycvtmtazqfvlngxvqxttfkpsvvhvcrcyhazwadqsaloacxoyosintj')
+;
+insert into t2(a,b) values ('vuizstxywefmqposqxcfirtqaaeifwhbeixanjzyslevpbbrrimgtndtrwlncmqhtfvpzlpnedufbqqbuhxqhzaduiuutotgvjqthrodcuglqhorhrzlxperigmlmputwscapdhekcaniaaohcu','kiibcbadtacamkvodjpogr')
+;
+insert into t2(a,b) values ('ypjywtdgzzgpfokxbaseihtajczxpisunyisqywcuwededpxgkndcnfjxiguhqehvyex','ehwvweauqaujmxsjpyvjulnjxvcwbyiflpcalehbdknfbajvqursiifzohwpsckentsfdhtmrxyjpejqeeblavacrmhcfvcfqvixkbxtsoiehxljqgqajmitoipedjcmyzxvecjdtqwawduaambpsjluuwm')
+;
+insert into t2(a,b) values ('cqqzysfepjdhjvestihzxrektradrsdsrhamiflhfzaiihwafusohjzmhqxnfzqksinzduymdkfbwxqpcumvmjtmkuskbycavxs','izerxqiulgjdjijjruhxwjabkviflpkcrxjpzdkmormjcbarbimqklpgexlptkftwvzxzggpbvsihmfwmanktfuwupavdjocnpafdehrwdqoxytrrppncmfovpdpyuxtioxqgupgyfadllhjpeusqqbutooippgubcywdugdvzwmwzzbxayfabxxklzglugiebzorpxwnirmkhraapwpgy')
+;
+insert into t2(a,b) values ('grpccgspqszrujxuewaupemuvpwiishvgqndbeluwlzaoccupsemuldmfsbfhvdjecrhvzvizxqoixkyszujlhxrmwwfkzlkvvekzatrfjoyszlolohjvvxtlovjigolmtxrjvwhdmvvdvsbz','liqhxscqwjxvsswmbjkuyksdowscihejylgxwcmkhvubljnkdbgutimhrpvvajsisxdezcthhchygyssericxqgfqwipeyiwcdmtrjumfphirujfzqxzrcuwmmmwwyfvhgyegyldnrkiitaaresvthblkncsthhgrsmscjvpdahonzgwebnjjtwdubrmiflyienvcipxebmposzdwjzcmolfexkmzwhshbtcexnifhacfjokmpserbmv')
+;
+insert into t2(a,b) values ('oyedlfczpsbtztnqcevepvhibysyvbjwaaoqcvydjzldpkdrbkldabghkdjxgziovrpsxpytumlgdnlbirlrbulsegqmxqywanbidvdzlycnkftvxwpokmwexmxzkmtvkoa','vwoykfckvnljdyywvqcbmgvdthpagcjmtdgtjqhkfyzwdpbeooqvayzlzgxnfwgyegwstbavpmctcnqzmmyqzebeaucsehvkhafrudbbvqlfcjvyeuewvypyvgohbiubvujndzvbymkfpkusjwgwipjgnyqtuasihduwgopamenebgvaylrkv')
+;
+insert into t2(a,b) values ('eodtaibynbyenplwwocsdpnthwwrgsqoxdvvvvkmlivbpxbgnswxhegrlmlbcij','lzkxlueqrimbmrrtseedysicbeozbtobfpetwgtwwakgyhusonnfednsmyekjzxbwonswdxzyjq')
+;
+insert into t2(a,b) values ('vubcgwazsjbgkjswikuitbephswvcrwxmoweaxtklspvmnuxh','kbloephufxltnz')
+;
+insert into t2(a,b) values ('qifrbozmvwcrkjygnjqhkfimezljiiiwahmskpqebzkfpygbxymmntwoointxxysqpbklgxjrfhmvjaqiobskkuliyvfpjzloeczourzfkdmihelinmkjjiuuebbxesybbwpydfnkpbscftpmhlminemoob','cjlrpfxtprwlyzyygnaybiivmfkokejabpnrtyelypxegmusrlhkofvhzonqsgskkzwkzxwabhhphknmefxxafsusfpxprotmycuo')
+;
+insert into t2(a,b) values ('kwhobfzqpwqqzejsqakbepdhhjmbkmgerokaaaqjnzltvlitekqirrhcofdgobnypigxuqikesneefkjzpcjgbf','khpuplzihdfciyurhawbietcloelaguwfhjmzqkwkvnfgmwzkhdvreujuamgqyujmpkbeibabeefdidglvdbsteaxktj')
+;
+insert into t2(a,b) values ('irydmytltxeasseiyandzxhkityxjcttwynsdirgofpszuzfdkgifi','zcgdqvjidrxblktjsccrhitrdpgyxhbfdmnvqmcxszihcnxousmjpixwxucgjeyyabzbmxumebgdevtdpwrymk')
+;
+insert into t2(a,b) values ('pbiaofngkszoysuunqgunxzvkeponptanrckmsyllbkohnpjmzudilbqolmnjycxkvmgyzaaipazyhjldvbl','dfpyabbibdbpngrqpctpliskfngxojzkkufzuoxvanfexqsjfrtgpmcldzlfrrrpbchqhgscvhxqlewdjsnzzzvemjvjychwsbazracuqbuckggxcvupsgudoadqibofaev')
+;
+insert into t2(a,b) values ('mwbtjflzepsaibwtxpbjnmevqzlftfcipehmymbmngivzeftrpkkfyuemypjnurrpyoicbefblhxxvogfxazmxgowxesclvfaqnkweyhtjgiryhlvciklyk','jozvgxagibpifznhfdjdzvjnxczkudvcwgshphzppuixgvhvatwgnairmvpngeaoqqdpasctfwykdwuuhappsotbcbwgnvzcdogibogtgbanfinxpykvvyzbhgtrhohkogfbropxwruapxbbct')
+;
+insert into t2(a,b) values ('cz','oqhwozbpflcghusyrvaxhjmicdjeymzdhllyiehaaxdnrnxnglrvlhmvxpuxyuekqzvkmztktglqiycvcofbiqrzgywcwbugtnxmlhirsowuxyouriyfhz')
+;
+insert into t2(a,b) values ('aemktfxhitwyumgooulopzswuuorqywnwjxmjaypxlaowxquohfwplcfynjqfkoiegqbxnlfkwrvqebdkxbfxcgnddvozqhmgrwxbdnfvsvvhgmfmquzywmyxajnkrumkglnjnkjcxwirjnlwajlfsgzgmzshwzcvbsauhooxmlare','ppbkzwcwjywcylmkdicbrlnlbydbktzbpeoyvhyxbqqhqefgfgbbogedcthysphrzauklfwazfwzsdqulzhiadjloplmrbpgmroaolykldcixzjkczomlavrqkootmobeohehdccsfotfydrjxt')
+;
+insert into t2(a,b) values ('nddojndnydazzwtqhtswoxezuvjyzkvnoqvwmepaqqffrlhhimoggbiomnzhqvoyliqogvmltvdbmmvcilokeblojdizhwubsirvknniduydrjxszwaeufkotjyerqohzsjmmfvmgjwvfoaffoaedysjcplogispwqpftwkpehwfgbxmrxiovhrgwbolbxbwwatuaynnrtcntyenpbxjheopfhcbhmorltvnzlhfnxwtbwalcuc','ymypxakjirvthvulqacvwmallualuslaraadpsucqshtzfrprayiqfgcpiasenideimxcmpuopkztjftpcphwoxtaoytqhjkgpdhlphmvuslocruvcychmfveecoiuvhdkdcdmatfqicpbdlztlpyfqkjoxssvocjbclpibkqnfqmlyehqqjtgxbhpxepamqeibtkmiiegwgk')
+;
+insert into t2(a,b) values ('xfnhuxylhmkilwwzwvjxlmfhporecdtxelmmgobwruwsjxtgdmrkufsbzygzereyntbvbznpwvhoqldizqhjasfrxwiriymwcufjj','qxiizsfukdrwmfeiojtgoxidfqcfizuhguwjualxczkdx')
+;
+insert into t2(a,b) values ('twbacchjlzcygsucfffvzjlphadbldugepeheuixiyvnqsvadfbyabdugbummdylzgojaqkaejcddszldnyhtslbshehsnepbyxvmalvqnifxmffxhezddyzudnzsvzrpzrxaiggptippgjfgpdmeycqmgwzkgxnqsizulhwmrgofqhysvrnkttgzekmoaslekeeuemdvdpafw','hjktkqwgqhrfscjlkthgujzwgmyvpglyrhrrdlgjskzrdrtrhssanzobhpdzferlgyhsdjmtbjsgarwqaooqsqqjiywpzozilcxtobkknnkpqubxsjpzhueqqbddkydxszddniftxnysslgqcwoxhjiyvzibjjdnbcehxkpeizzmczpmdoqvlimuvjngmjkiasrymbocwoyzpwfbprpkikow')
+;
+insert into t2(a,b) values ('udyokieunripfujainalyyctkqsiodhndeqbwhax','ediuoihohfgpbeultxziiwvuvyaaavkrtyvqhtpqlhhapgfrhpgsudouqeihieeqozbivfpwyszorpbvujghumenozjsltcakqykrxqedggrqudrniuogbtgwxkxslpawhzrxwejnusiasppjtcfqzs')
+;
+insert into t2(a,b) values ('skqqecndvymlcarfklvxsotlqvexycrldfiahnhymncofymcnjhnspnvklvlcgxkrcqlej','forqzcxbhksuvjvzewhntrrrrfsjvwwtvydutwdjumncllwabtbacizleyisneisfxcjturdwhswuwkktiwcuqmxuzmjaszaemrqqijczcwhgqzhwadrbkqentmszbczxthbfcziiisvrubxolaeflruuzpraodxmslmaarognpkjvcpfwcnzhhcumjwdgptejunnpnrjaaljtbawgr')
+;
+insert into t2(a,b) values ('vwnwpabrzrkivfdcyufwuujgvvzeiakgjqdyccbzgcjhyulcpiztwvbpyecmbbryzmhatdpujslwgupufdiahkampeifrzxnxxteozzkagsbbjmdfqoiemgukrvlfvlbkbpriadvtpiesgqqxcdhrreiwxsqsicpkkr','dxjxjvnfkjsumjrsgghsnvyrdckmkocgldtdebvcmhmtd')
+;
+insert into t2(a,b) values ('ywmlakyhnkdrysoxlcarfulcukundkksxhavdwnrjqfjajhf','dxtlchszzmrqlrxnozporetsftgghyqlneblbyxiiacvomyvkibfrjgkkxuuuhahxjihocrofqvwudbfjbzukwbrbhqronfzpvphzohinoglvjwcynzrtahwphktxmwjqewwwyppxlgphcrzdinaliyggrroihtstgjhkmjtolggmisknlerehdesstvnkudiexfnpvrnuhtvovutzrvyrbtoqoohopyhaesqnfgjcjzcxcun')
+;
+insert into t2(a,b) values ('pmadrjszzseuqjnqeveqhekrlmnhjkihmvvydbnwcpaqjcpdfajgofwpilgbxjcegorvzctesvaglqjhxppwjfymztzsrqgnbqfuogrmemmmoxsldfhhbsemrjllvjmrwsdbqsoeaxcjfyfpjuzzaexmhyjqiltbwxbfpmukbpuiwvurugnmdgsndmukdsexpmzvcogqidabmlispsargwrsqoa','dybkcejdogpzxpjhzsspotwlpyboukljhdrkycovrasxbgkvfblcwhlmqpgtbyzwncpucfjnlfwuujicbcenzlcvvynowsrxojachiqzzrafllvcjfnlfkhpertnkjfpguyiphxgnpfhjezkfidvslwihkmbzztufdrapxkslkgmrjrntfxxtiv')
+;
+insert into t2(a,b) values ('twibbgkqhyrmvkmfrtygn','eyxekjlwzwipenilqcovbxtphsydvpisbhdqgtdmwqzyxnpreyyoffdmohvyerizvagthqbuopqtlrgixalcwucrnmjflcbszpxzrgrlmjlqgbcurmhzjgjxklrvvcivlrckxlemfztgvlcgfqiorguzffzeputtsczfbojyyqelpgnmtmajhzakexphjnryvoqthounqmscvbvqtexgjfebatjaiz')
+;
+insert into t2(a,b) values ('tmnusjnkog','muskvkgdacwgrfkcwqgkltvsxihtqukumumcxiojdmwinseqwampcdkrhzfltswdchvzgpisphapkdtviholjirimcydwjjswheewibnscamvkrtyfziypdtgpopeeowxjbnduytveimnit')
+;
+insert into t2(a,b) values ('akyxhmxyyeiusiyfvaotmnflgumwkfcexeehoucmclqtrnfwesvycdxzoeryiwwlcekqjslfpmspwfkcawjzpafjiwllxggzbnckweqqpyncqqctycfgegkgsskjrysmkqrksfgxcmquhdcvoxqfuqppdykmqwsvfzntsjyzstfnznpiegkjnyovmigdnwuljxjxkiyhtllcjpfnuhqwtgqbpakckhbnchyrdbhsracruhmkabkkahan','chzodzygubueuvddsokak')
+;
+insert into t2(a,b) values ('igqyjkaqbleqomovlikveytokxkfzukifyzojyagoitzppvfmiyrgkkarxcvlenhjgwefsstyaa','')
+;
+insert into t2(a,b) values ('yxznfzydexdcqpixqgjfemasrrskdrhzwwxwgxpbwycxanyvsmntirfucgswtgowkndgjkhzaiqemrqgpenjcqcwbitisvneplluezllzdtnoequvkjuzcrnpnrscxdftacilhefitpmycarvovlsujflpnvqekfbotqvvsuydhnyfwzwwhglrnqlvmnfvf','shtuuxqadsnqsrsbvwmgsthvfwrfurdxbahaqxtrfublrwrraqhmnswxmtnvoquzmgdzhoqojlnfyrylbykigagrxyrdcgtgyfwtkvhlwehtnjppwhdctxppokxyyxsridztzzwstznhegsyyitbriltyufvyzuhtkokvezdpqkyrhgopdlxujvwskvrtrlmvjevqclsewverntazojdaedxbaotnynkvbglgsqmjwpkohku')
+;
+insert into t2(a,b) values ('wmjhxdloxkxnqklisbliiqqgmcnnjhchcgnhqljucvzuxpohdmtghjrewhrehqizkpmewykagyhotpalpzwjxhrjjxxduktbpfsvdqnbcgwnozstvfcnycuomcqdndudzrkzdlzfkeindopwureeosopmzijwshn','btdsyyuukapifwlvwqpxgshgzwyjwvibqsghsqputdeztmyvolxcmxncjzjnatavnyketesyuaudd')
+;
+insert into t2(a,b) values ('vgttrycouaklrpepnricjglagpilzytmsarmzuynkhvhhmr','msupnpmilcescpsmnymtdjbowiygbvpxkshsluiarzommstyhwtpkcqxgcbfyncgiuzpoxjvrmmjiisuvnihfvugyixhwqrdfahm')
+;
+insert into t2(a,b) values ('itipjbodbsdjdkeppwlbcofxhingvkrlbztownxnshdyltuwvqzyewaikrvkrsdeiswgihjargckmghlgtmlfgxhovexiyjbhsoiuypsmbyxhahtqslaximlvxocfibkjluiwylckxymmkambbvggmgretxrshlxphoouhkzcoztduqlxzafhictghuznvlkxmimnmgiqnsknkufthbjgxoaipgnyezffvla','dwahscwdskvvzszibuhfltpxnabhabdovzfjtsfxlxfyketygshpizoynyvngbafwtjwjjsldysbjvktwuxjyedzvfbuwolhednrwtwnnzevbawxzbcgwdtmiepztayjbphlnxfxsxdwgpzufsdqjsxvqdlholltxmmxypzgurcmveguwugboxutgkxtarbmwnflyzdsjzqpxhnbxyxqeefmhshpocpya')
+;
+insert into t2(a,b) values ('qipzmusgqfbtgexuscjgpck','pnkjazbaxizanwuddctyolccxlcidwcczvvjgskenxwjsuljgdwevpcgmsaquocwehn')
+;
+insert into t2(a,b) values ('voxvxbathmjinzsygpoxglthkkswmdnhjvibznsutlxqrmb','quyxmxgvrqflybqxvmlaiasdvreusuphjgroimbasiuiwmiwcyhdijckvwqyqatifdgkpiccsovemoyzywtnlurshnpawrqgdqouejwxhhsp')
+;
+insert into t2(a,b) values ('yua','dsoclprpghhxhralpkmqjytdzkespgwpwbpftetitmfwqrqldyoxouuywvdvkbvdahclwkubfjnnhiqjhzwbelzthbuyhmkwblqxdcngzsqearwvvoumdjpjvxzmcfumvabhemshycekjrwlk')
+;
+insert into t2(a,b) values ('ddjwtwfptafmfagvhnxagrrfoptuvruxkdfbumfkuzmjugvfaqtsjzwluilohefcqonwngqdykbwqbowsxkhdmsfzpydyiestmytyoexgjuqrxgiauihenhbvnrtmxzcimdkspljloehocdsuaxxxanamsieylntover','kewxixilaqrqqitflchvtbnyjsmvcgabiacfcyfmnjywfmqglwufpxauaarawdcqoaeezwcajnumxaznorozpacckgpxfxkpyoqjfbylrfqehdrmxutspshsafsxktwrxwdcnbcnfegqdlvjqmsosdvdhkeupvhvgtjrtgsaslvtheymkrznuqi')
+;
+insert into t2(a,b) values ('osztqvaxzppoutywvrxerybabsbchhuxomgcwznervgbtcujluzxsedaurgijbqpuzbcjtqpaewxjgfhwgaxrpshlhjxvtdesyuxjcn','jkqpwhkozqygqtpfcdyuqyt')
+;
+insert into t2(a,b) values ('lgvlxdvvxymeonwixzpqqodeaqwadkuzshjqjkwusn','qwayhkhuoxaxilttberlladgyxrdcxqsm')
+;
+insert into t2(a,b) values ('nsibkkfvjddrqexhzjruhnnvbmeruyyrimmsksvozvlsahwaiqflfdazylnitzosfevovhio','ebrqkekuvnwsmgksyvwmsuvturinklovqwldzuicjfmrwgbtsuzbimqnnbteqlctsqxbltsdotjqqqwqkmdsqnidvrbrtehprhitzkincnjftovgqyebzgrbzpgncjyqpsqsrdhzwgnkvpclzummiituclhrcbzjcefuczaionkzzcvoxsztzvosxyobeizzstadc')
+;
+insert into t2(a,b) values ('gjwjayvlsezezolmchusxhtbnpwrdzcoiaudbjlfgmaucctbhgfmkfpcvizlhimixphkhlhphxnadevnaamhsiiiopfaryjdezfqfqpvpistiforwbnijmhnwrhasonikrmbfcgkqlbctzqtawqjffklmblknwvq','ueuqwbvgsalzonnwxphxdkamvnjzamjcvyougnchmnhhwpkenhlctqb')
+;
+insert into t2(a,b) values ('txjuurkexjigobkmmqhijvemabmbxngwqyoyojogwjgvdoylwjhwbbszhsskugfdaupyliozxydjlvsmtpyjdumwkredvuenlrjhwcxlmvirqcggspyksaejfzbmknaebcqmwesejilqjouqnyn','sibcyvjmuszqtzgqtfigakgtvzyibckmjepigmlkctxiyyvjjyevddmwqttgqymkgysavwepvgyzgduxybogpkuypeggyxxybqa')
+;
+insert into t2(a,b) values ('nijdmluhblcxdsmamfdvfiqwbahxdcmxtsrrmbzuxmvawohawkcafcwtuavxdnbfwdlctdtrpmyfejcmlahbkmdtbbgafqntmwabxjoqaji','hnwxwxvpcgwvmlfwwpdkpnhcmhxynsgtipqxxmdtjzxwvgfdwxyjuspayillgnjhkyuvnzftawhudwxkogwfdshxlxyzostudfhspckoluqdkqusbbngfqtyqlaktfkwmpfbzcbgsbttkqowaiiyzycmxtslqemiynyqsuhmvacfahycbnebeakpbeslxeiqeiskqahiihtiitryqnohdsrlnxacmdcrgogyhepjmnumyzsc')
+;
+insert into t2(a,b) values ('nupdjlafwfvuuvruxkyjxpmupihzgspkaybijztkeukgzzkrxmd','lrvgnmpagwhpyuoioeixvmxhmrynnaxpcjxtbsirqerzzggrklkxcfdeisfbyjpkikadvrweolewwqavotzkvzaneqmfafzaszwfndyiqlutjwucbsolxddxkhuexiqzhcggelytdkrddumteebabfdaqysqapklgkzltuoecfwjwljkkxnmzrxpbkpsxonrnyrtakbtqprymewmillggyvqdzjymjhrvidxkxzpixoxi')
+;
+insert into t2(a,b) values ('ggrvkblgwdrimsspqyyhdksnystjzsschbrqlckp','zibdirxzfakwsp')
+;
+insert into t2(a,b) values ('ilqndqriaiaqvrfbqoupcyrmrzrjnjibvxdoclcfhesxugqfgctzsoqfrqxchcdfqpcnfwgefauzhlmpyrlhwzutdkblqzklqyxfopihcqjzkhujfhmwbmucxnkfggcnzzyorlxgycnlzmplwtnbnfeqetaxbnufgkytfhomisoyz','nliqmirwomytoicyggxcmdpspkydqmshgkwjfafgvsznudgcdrmhzdfiomorfdhjbmxasooboziiterelxamqonrmbuhkuvwqnhbpuvvcjvyaguixvrwnjgyqazgkphbrkmacnjtpvjhkmiteuryshaupspqmflqmtaoujtqqfkjrywlslmjmcghesdlwfihjxffrrggcszsrtusttu')
+;
+insert into t2(a,b) values ('qztjgxzgvwvzjvotooopkeaeutkrjtgjiihmmhkhymekeihryjuunbhtzrbyjrmzyoftmneitdnkbvutiiealgedbdnsvjjipqqnibgphytiwykvimifbcygwckdny','ufqjhwsxcmymgejrcvrmqxwjqnimsyynpclwjlabwzptovodbaojwzhgqwodawlyrgkagrqykpoumuugjqevfdnnwzohbarjsfnvmzgcjexckrflhowhistogggsyy')
+;
+insert into t2(a,b) values ('iavpzhsanndttrtpytkombsleugwvnfaqauowohdulmtbmzfebifrajgaxlecmxarblpawkovmwiuqdpjhylrcpzqrmlpxpdkeubonpfsqteyopwdvivipxfbqlyszohdkoynlhgxotwcyqysdtxtiidfbwnnztbyqnornxsyspdqycunqhrkqddwybrddxtgkcumiqlrwovbzjvkanbyhrmt','cextqaydpounamwualcwssxeikouklsbhgotakueditvzhriswuvehqqepxmlboywjkhqgpzakklhhytlothgpuhtwkmhtrpomzynaplkdmvpzeqqaej')
+;
+insert into t2(a,b) values ('ffahnirdoahaijiyutbopyntobhuffzrgylvyjmjxunsvwhjghaupjoaxiboxzpoezoyntgoupcdfilxhejcgghsnnbgyyyxjpglnxgthlxucipzbpfwoimbggonjtkkgyjtvlataoavanriskrjgokrlxjuwrjxl','ylcgtzonttvohqbujvjszlaackuvkdlgrhlinz')
+;
+insert into t2(a,b) values ('ikxqhprfcpsuxtqszlvsgyjmzhwh','zdrhmxnkerxbkhvrapogwzotazysmemlsommpyjlxwwrmjzjquaoskdzdrqwsbcomtclciqxneulgcuxxudttbtgbsyuivcmtahtvqziazvvlsdzssjuuusqiigjtaunkesdtrocassigjydhvfaoselypppuwaikxqppvpjbxhlupnimxcjgdgynyklznfbbatvylta')
+;
+insert into t2(a,b) values ('awodkjplxijipoilexmmhabbxfvmvozbybb','b')
+;
+insert into t2(a,b) values ('yxvajiuamdmibjoinxxsukmfnqr','jtplqbyppmjhcifxpbsvnoyliocktoavoxnbpgarfnddufcnphmxmarapfnwpufvczwrnvexpveddzrcsprogwroyldkqs')
+;
+insert into t2(a,b) values ('ovybygaunqjbpmxpjxxgvqiqfsftmbfgxudddddliadarreugccuqpgohsdxqyhixnqmwriapoxjjhkdhswcwzcsybefrcrytykn','dnplstwjwpdy')
+;
+insert into t2(a,b) values ('oobehpqmtxzjafvdrjaqgsakbktunqnyjrigtsbmfuophkhbwqxqorkfaiuoitusktxdjcqheceruxdtfpbvqmkswipphwnqmcsuegndplnhsjopwfmfoqxjfiszbyqxvuvxjgcxmbybzwhszxdddcfjryzqvdgnvsdpypuwijbmcer','xzpbqwnghxpotsqzhirsdhzizgrfqhcmomfyvzuedeiwirbyaewpcntonriohfp')
+;
+insert into t2(a,b) values ('fjygfiucdptidcggonebwhrfgrywvmopxtlxbccxjsjrchhgcqbjhfyutbuvepsgxpssy','onvzbnozmwwmzvgkbmkwypfvjtvduxrzanamyxldxbwralvfusznnbewxukngzyepegnmuigusktktypimfdiwxeftzm')
+;
+insert into t2(a,b) values ('kldkytukgonpqwcriafmvwzcxxkitstyikzugdqfffzjmnbakgeyjkrviifsexgbwxxpgheillmfucmpxytgikssfzmfphkfqvfqgqxtewjfhhqimcefukpjpsmcohdwlmaccnxyhvuczlerfmylfbdhnkbs','ulquufcjctfmyhboaqnyypigtqzkertqtyapssebdfimsknjukvrjpntsglpjlepepootirouxnmzhreyuawpxznxuknogilopzzplvpewnqwgwdsfklotrvdmizlvpzygyehahhbfjtboervsgmuaiwpvsbrqkeqnmffblulqsnqpxtqtaisjogxwmljj')
+;
+insert into t2(a,b) values ('nqsbcaysevdixaomruefrzyeieshzpqfdrekiamgbzkhystbufyuhetjxxjyexwbgbmbnfsuwmvsgclkuckqmvvhltqlsqeusqiarsmmwatpoauyeqnwcouiaafzrvdpqrhsjipgsxljokpxtaiksfywfzzifkhesxgyzdzqrupawliisejrurxydlhrwfuethwpljkdswkkemdpwszxgdtnnonq','bvmisutdkqizzmgrbwfxdoyjujmfmsukrgxmtinqhqihywvnfihqzjrbwdusxkeymxxiejoinydcjnwrlkvgluqxngrjzdfxsedjcmfeduevplnfiumosskrpryogilnxjrlhwynbljzqye')
+;
+insert into t2(a,b) values ('qzdobhokwiaobcttojgyokbvnjlbbhtqvcaxcewjiblspivodmpmfhkitzvdczdwwdwugakchcofoisaqodfzjcrsplbdqvauotxobbxpjmhzljnxrfphjqtampwnlfoncmwbcvmtasgwamyjdjzsazvtjqipxlnyklftulijocfqxbfyyhspyukxyqkumltbeoylpkordukqgamoppyzrlfqtzmnizpwysiishrmzicrreajdzqgcm','wmixrzvstfpnkwhmvdrnmwbfwcghmnmgndieefvqjpaesimgneqwbddlsbyyccpawdsqcwrwlymavmfccgznumubqakujrkuqddgznlamwxfxxvstybilkqjpiwljgnrsffkprzdgwxsgutljmjbmbkh')
+;
+insert into t2(a,b) values ('yqwnmfhwqzoegftuaaiexpmytmupvynriduixsjvovonyeuktgpialashgyctgamhzqlspybucopxpdsmleiwtxfgmvatbgisbcfbzdvhqccxwijgygwnrdwycltifihatqhaoayybjmmccdfzumbfvjkcfpugkbkxecphllmbsvokchwywb','tlqbfffciwhwtufrocpujyvtkbxufvy')
+;
+insert into t2(a,b) values ('vynqvxuctindspvonbqzsxbqqtddqosgvhflfcxggjmvlktvreltbywdpolcafzyvwnqerklyeuvkorhkynkumaqgjvhxdxfmpjhqwbyaulihcldgmuwffdkqxewkvjfhzfgipbiilajdiobqeuekjdhwtmkvhiwunqrlmixrctialorlghmsafpqycspefvzuwuvjftumgwyonoy','ninppuiofpuycdbgtmnqappezvqyejererdefepdidlwumdkhduhrzzspmugpiqwllrjupciotkbspeobjacztpvsqxqvefmiihvwqvoclxzzrlsagsjpqdhsdkmbdunhzmzyflvtlxxcweazccjvlasexcuaqudiszohfwzyikmhjzjkaprefowxoizkspvewcwhoqzdcrihuqtfyqjjdxiktlggurm')
+;
+insert into t2(a,b) values ('mzxydsmxzoypulreilhsfzdqurnisjpotyasqzwzjfzjhefhhnuepzbavzzodatwpbkngjkvobhpqmdnnzaxxqqwugtlkaykxlxduefsadcnodvvdyqqphdsytemmbnybeazwlazrrfwdhjkfkrskvnffcfuxiayxzcuqvgcg','kejboweghqhxhzvumxhpuxznistgruwpyfwxnjwqidnajqskkontnlhuuffxrha')
+;
+insert into t2(a,b) values ('yingdtzzqclwwtewrhkfcggwxghjfhtfopcqzygbdvwcpimnwvkxpdgakbgboynaijvahjcdmjakmuwnogouxshzrqfcsngsoosrmwiuaowtvjxlbcpbxrlrndqthvobvenleapgtnnxmvsuxxwzmlvwohjoylwisbgqagidxe','klqvbxouayjcsyqhdnyapdntk')
+;
+insert into t2(a,b) values ('reajqquqosazgcnwvdgybbcdztojjqyygvdvncmwrcjftelvibsznmybzruovaifqqinwgyyzqfsodwjpvqdsctykszsylxhbrymowqrycijwceikxliyasndvcmpyukimqqpbumxufhrmpaohgalmz','ygwblacbpjathwizciyymwnkbweitrostbffpdvumxysxyfecfuvaevzxvmsxttbuzdxfuhorcffubetugazhwxticgjbonsxivyslelgmpbviofhvulvgipskslooippsqcrapot')
+;
+insert into t2(a,b) values ('dvrhbzaicheozmsguhafxqujzmazzdtlzzqmlz','qifmjhzypozqgrfbroodsejklruyyvfwuwaivpupirvcvttdzouaytpqukpnzazubctdpgt')
+;
+insert into t2(a,b) values ('gxaawjrpidmgirnxtzjbbvbwmwjbxgbcjjfbirmkizchbhkdkrsrtwiogbqmftjr','jyp')
+;
+insert into t2(a,b) values ('kvdnxxuwmctqdinessryybbcfwpfjtdfvrzsapfyuflroapobxufcveooqmjnrqlmbdzsziwxjirs','npoczljvalbzglcncntudgeadzkkebqkroivcmzoiaoqgwiihzdz')
+;
+insert into t2(a,b) values ('lfynxdifyntgrimbvoeykdcstbwgggthkhvxrgkuohztomzycumjtdppungpemalenlygznrtspbiygnxuqpylyjntqigvyktywcjfmufrwtumjhuacdrzcswjkqzqqschqwvxclhrhbiqjszkqxqo','vudcnriwdcgtxhqxocdjhgfdwjocrrzzoxzgwwbukrrzytyozwjw')
+;
+insert into t2(a,b) values ('syhssmhkwqiqlgugmtsmkbbkrlkhohgtoijxnxekqvvwewumzebywcrjtvseuuudjpolbrhzydfoidwjmywbqdstqrczkygyjjxbhgdsqrbqqynrlrpmzqutxbodnceraeszvywfoodwpfyiypfrab','bvshjmesfbqvmgviehbnpnavossuklqdxwopqvjjgubcuujuhcpgvemuwvwwpnwhlfjteutivnvfhzinvx')
+;
+insert into t2(a,b) values ('unfiqirmolqdjfrcmjaywodsisyeeblujfozelxgcalvwamlraknehrkixnqegmpengtzhnyweagrlojcbybiwcszfghnbilriwygwjpsjvohhulrloswdgdigxszyl','iruhcdcwllbstusatwuzhudtliioxqeiihqnbojhhtxcplmmgpbespnjkgissqbtcebsutgbwyhmdhweyehzvhwhbujdfnmbgcnrnryxbnclxqopkdcetehbzgashskhxresslnhvgfqvtgimmmypxshxqyryctyrcdtnqcptzphbopnkjxlvwajagpodihxlpbuqjtlreqcqaevhlitbmotrizatbsqux')
+;
+insert into t2(a,b) values ('lhxbkoynxiphvea','ekklnudnrswchoksemoatvqicaiwbnyqabofmbksdxbmnmayfhpcjmlijcwvttrufvsybxcqasjdzlbyvlrpvmqyyoaqauidhaezrrrfcatsyrphugkyunsaxjqmzyjh')
+;
+insert into t2(a,b) values ('mgagxkdosuiebasmuwvknmbgrmzsqcwlg','bnwygrerimoklvnjhysaswwedgerenlpmlgcyneexwqcaaaehmf')
+;
+insert into t2(a,b) values ('rqahjenqvtjegbcmteovoaijrhfvqvxestiqkqgvydwbqkrlwgsjypvywcyunzknftskoggdntpatvfbbfgqetcavtifkflmfmsdyoojjwsunqcxryoakkxkextbpnbamnlomwzdaaccbpxnfcjwvxeoyggehjjvbwhrywaefkzlpaphj','dzzietlbkvgsvohfqxgbmzbtedqerhsvutwbavbnhdiqlokgxemvdpdsenzwwqynkfovpzemjmahzyyplljfxjhyscfxpkpvrxzhnidlwqyrhyfokxyjnmmlfjbhtqqzfrkilwwlbvnpctin')
+;
+insert into t2(a,b) values ('vvyucorjbthoalfebbcdrogsyukskfwvvwxhzotjfrqtpigtjvtuyrlkomziodkthliqdkbqjepusoigmhyeqvnvrkevhzzlmjeqvojoxbzolnfnkzczhequiwdlzrfazdhsdvgqxxoovjooqdpmdouxszfrdbpzijhngunmktlfynnvqkittdxddwieamysohtkn','gbzmpuwuxlpyjmojaxxlsxupliflkhbaacmmfwtxsrpujjtkrqygfqidvgtvpbaaeaqyydohpyuhtzkbywllamwgfpznjcfvdwpvhbfvfilhrfjwcmywvdrlooonkaenyrkxbwawulaooehirfpikubhddntplmmsztccsxsebr')
+;
+insert into t2(a,b) values ('khvwigbovbneoasizapvzjcztagmztpsvaiiufhwdtyupgjyvyjmgihxwyvdcf','tdjlcnctspiiosmqwwafhpkghizambnuguetdukeefwsyzffzmdgmhmmrrogehfslkqlowwbqsijjizzzwhcpiobezivyrfgjsvshnlgsgwvtaqzihlffsofkidaopdknawqerepzjrvfyfuk')
+;
+insert into t2(a,b) values ('hoemhpapeknqobvfmscxtuegpauyivvdtbyphflhdpzulyztuobidrdhbksglqtslhfdpfefzhtndzpxhfhkoyoxeidvhyqsjihwrkiigjpxaqyryfflhcxghjhvbvoivmzpicqdtvuknwjoozfclarfcpdiafcdkwbeseplmtgvmilamnddmotuzsrqfsrqrlhemsrfidjiamwwovttxwtvkjx','qaujxzwknatperpypymorurhxgqukvzyqorvgmtwacnwyk')
+;
+insert into t2(a,b) values ('unqgjiindkvwdsimcjmfaufxsmfcvziuufdsjeqffabptwnwcizrdpnoonccdafksddlwzfwvpyemojmykokcegijnqqwrigbqptahkfkltwcqfewpyanimztrxfmxwfehdyszprsdkxpocdcihhtunkegzwjsxrh','ilhplctucizywzyqkevatnpziwqemgupvgllixyo')
+;
+insert into t2(a,b) values ('yknwhfbytgtlfwcjbpcklaggezlzdlrvbgcabmrzwaehxrzchajwwoqgqzadpfzgvebhzdqsjafvqepublivvymgrctbjkgrzokpmekkgyjazxyelrvidb','aneaxmfiphxmciawcgguflliqioktvgujmugdbvhmobmombglpcovognqidqbwdilifofqctxoalpawsxytlxtypyptzxwvwpgxbvtrsoyegauipeve')
+;
+insert into t2(a,b) values ('ihxshnmdsgsjedxxekiiccmqhrlsyhxpmwybowqporeucstszpjnqifneckqthodcvbpgkcpezcofblvihuklpygjgalqdfgsqnhbihgcgwlqjpxeplzvuxywdmjzktsxtngffjwhbumqelxxnkwovyoaitesuowrlvtkyyixcthrnibmlcfsrac','lxysnfvqkraujisfjsxprpjjcltidnomrzgmlxjukiohvzmydgdgrpelsoxipaiczbsteysjfjeruitydnlodqbzadnozjsikuijolhifbytxxoneyedgextgfnzhewgkogoxynpquzvhalwsxjmyo')
+;
+insert into t2(a,b) values ('wmrexbcyrqrdwiqj','nuxrtzcpzhftntrlaybiqnpeagzugi')
+;
+insert into t2(a,b) values ('ialpebonrobrifdmdrdchtkhzmnxlvxotvhhvbeuumtiseprfosnfcnrqvdgkokphnipwhvamgdkkdbhdvzrcqhxdidfiahbsisuxuppcerqrkbnnvrmbdgnkqvhbyvemgrnhbrhfl','wghlxfzsafancyrlprlpuvokifrglkkabyzdxmfesezietisiupltirkqqyxyhyocshsrwbakwopdcgwawyfrenlmwqvvfovilstvddvdnxjtfip')
+;
+insert into t2(a,b) values ('rbjdkrowdqjfqcfiykloopumkymuktgrwduactaltirwwpcrtkgiennxzpvzykpkukhyytenazjnbivzlkwyatiymwgixm','htgzlzlsgpzjeqnkhsiwxomkrnvtlctdbclpmfglszwrasrpuapaivavgboxgegkqaeeygklojpzcrpwzdebvlrhmpdfylg')
+;
+insert into t2(a,b) values ('bliqdnhnaicnyybrfpzhxnksagomkpkgwnhioowpnbvhlezwmekxtfkxzrhbqxdwsnpqnclvgefpriyynezekgsuxqrwjscbmdmydpiwhbhsysumgkwnkquxrskbubydamcitndvcnholmmlklijdvwxbhtmkxnuryosfuoqsfvomxktasnaflvamenywezbghjg','pjeautxforktxkjrcxjqbtzohhkcbvtmyhkhksfdyyswmlcqfldg')
+;
+insert into t2(a,b) values ('unpoumftfnjejptqtxirpcnzoywksisvgrmghvbxqydyenjcvpdbpdddgjcmwlugizoywgnkjywgksgwttbvwuzwmwblehhwn','wxzbkbwzsulelgpetrudd')
+;
+insert into t2(a,b) values ('zzciujbulwutbkeuhzvhfcpfjadkbqhejmzdfdvdvmnskuxqgveoezxbrgwahwynsquztrnqlocqvcbbydpsavlsyqqprwuqqgpyikccsxillnmsjsxtjuwsgkoitommimfyqysglbznsgfscvjoahvebyqpnvrmxdbqwugmexboszgdmvnkfydj','nfeommnhvhoguhhvjedyakuhbncbgteh')
+;
+insert into t2(a,b) values ('afokewuyiplkgguacqtsnmnqapqdlgzizeygmkeawrkbnyfhwsgulyiveuwohazndfrgtmesmmlzjcypdwbdoejk','trhqizvlghetxyzghvqovffybnokjeentfplcpazsbrgrzspnwzjzlgdpfyntcjqpclwnttynwefhmyakbsgbpawvvtxnfozgfjeagjsbybjozsaojfnghwvvxgsqflveraoauwnofzbjdzfoyrfkxjwaejjbwkyobikdfopazwgjymfgzntcihcibsxesrshxqxjuzpxzsqkgtowfssxyavvroqetclfuxkrvjsvbhdysccggwfywrnhxsnnr')
+;
+insert into t2(a,b) values ('qqcqmrsnlb','fislnfstwhgzfnmthvnzxcbybkaxnmsrvsgseyhdodakltvolwhdsbhprylsjzkhhflaciwbxqaipqqqhfkxyhulaiulngofyyydjkkxucibwvlelzhnoomdptvavxsehawqwshtheqbfdmagyhvexsgzyxfiqodudpxkwucajnumivfnvfdshccmhlegwouqojynaebrohndyyowuqdzpuoq')
+;
+insert into t2(a,b) values ('nosyxgaflqxtxkyilawoczuttufzvprcxbmgqxfoclzvsaqsoarvouzwupofscxwrtcwmilbtpufvstlttcnikddpjcrbtwpnqeroxkqdutjxmamlemxzhuyynnrfazshhgkmcqsdbufluwjaozmrcxltwctthjrrwlxirxdlymnwmjyhmhthhbcorhvjciggkslthipxsovxsruzjowitgnphoaatvykdtvfq','qsnrtryflqtsmqnclrhvudcvkkeonggtdotynbmpenbvrzmhtzgtaloxxqbaurnqcqoannyoxqiuaqmqnnindpxekihfeweyljwcnrttnswriwwtkfdatmuozgdojnwfmhveluoaisraesqopcxxssqcuqptkmovjnbvdxnrevrxtibperohrqqafsfygynkjakcckfuslsrtgvazb')
+;
+insert into t2(a,b) values ('azlwnzmnhjzztsjvxnsqcnsazzbrgfvoozewyfhgyveojucozcszfduwwguyuzfkxsppkdtufpppwmushkwglwgrftcasrjprrjcpwiequupbyheasrcsypkakurdlbdfcjnrneexwqjgowrdcqbdolqjnxfkuinscofhxxyxmflapyfxvpcnfcjqtgrnwwjuylditdbspsaqqzsswloixdxlkeenkcklmhjtexcgjslwlmuzbtp','kumytpjqmqhxifchbjfqokxotxqkwwvqemoqasmaeccojnixdwgeogmmglbexgaefkadsgfxlkmngxldccgujvxhhyyoupoxnmuugjxhrknxqul')
+;
+insert into t2(a,b) values ('cribfhniwlgggbfvzttefkgxxvbcxkidwrznbitlpatgigdfkweuwdnxnhlyywjhxwymrurzbtmlmquuqetvveolcpqyeicuzaakktsfzdtyaejqypjvqhgkjrweatwgthvbqimolasaiuyzxcdggjmandzmiesyxukjmjzreoqdwhxwppfythbntjzmmkuxertncpkwwtglvilhckdeizefexspmc','nglahqxvbironynlrdhegbrlbwgekhrmtgkfwyqhkeqgjqjwyffxzheaooycvaibxdqunagnvnjimuqjoxcukihsrhhutuyoxiswbpvlhmkrqnyoujnrkbcvepymwadsfufejddnmbuuwupzlhdkmfkahzcgxrhsstzmsilyyr')
+;
+insert into t2(a,b) values ('flhztprigxrexvkwskirtsylakijlasbjclarmpfchgtmrqfhdjtfbxqwjgopnjrlmsnfojjbmkppwcrprmqhgxtupohlaotgdsjdslulfyyfkjqpnxwaquyhjebjujfjsafxqtmdcghlsvtemxhhyqjhddpzeofjtzxazjkwihrhxglduqqjblfuyrvpqveiiq','kzutfehlwwtnmsdcgtjkxkpbfasirnlmnguisxueagzehivsntflrpjfrgmsjlyzmbfucbzhpacbplfovxtqcmizafhalnuadvvcivkrhyjzvelxjwsnocgrgzqvbepuluhsqbmvqzgistflzeudnctsgskdpwrhyzhimnqvzbxmbaageiyhkzvgpraqgfhgprylgjcgwrxvylkhdsdpaclqybapolbvlxsx')
+;
+insert into t2(a,b) values ('cqydiqbkohqmkoebdugmsorosclblvmvzdklzmtwvcbnuowlqzqyafjbbnzqonxoqbvvtebhnftochkjdwsfprssjlkjgfokfpbtilbrcunpbclwjlkjadfsbbvszcddxhzdyrxusifsxiblwhkbincopemzflsgvwddwojwlhbdgfkbjapncsxqbkgdeqtylffecvjeejibprmqvqirhcvnwfhqphckjeqsgifngjnsrsfronmls','aqkgohyeyppomqvzsrmsrrudeffwlvzvpgxgvatnczzifrsbuxccpv')
+;
+insert into t2(a,b) values ('lcyioudaiauuzdehouczmaxjjxbnidiymzumolpfqcqhocvcphgozbklmadfoalumwlpqixbugncjhrdmtemymcgfeuygzhwwmbqaihshwxmshenmjwvyuqzdukkyvwsxptjdgqtxbfaeikvxixbadmpamqyjthiimhpm','h')
+;
+insert into t2(a,b) values ('hizgvldbqsctlpjswwupqycstprnndzlaqszutzebhagcvhxtfomncnwxhqqtaoghjtfhopmtkvgsewogvsvbaoyphapcbylntgminqjbspfbbbstxhkueowupdtglryjdsbfliybjeyduefprtlccsdmjratlvkgbbhkwiqzfwxkikzazudjugsahbcfjjolvqxpnbpttxrslatfxng','zqzyrzeagutsziefoiesfktojdseaklrbaaxorbzspdgnlvfpcqetjyvqhbjweiikehjsmqgcrmltgdtmxoqtowtpsjgrvtswibybezequjsjnqzpduczzlwakv')
+;
+insert into t2(a,b) values ('hxdegqtykqtwkgewuiyztbjvqotaljwsazjuvmlsbkmheapubxrhoaoepgrgdjscjphqsxldluxnawgwborwwswtbjgntvqqfubmhtpwixlegjibxagemprbdfgpugrbaqfgywgxvyaahxyogiteatzjwerkqgasoo','ljopphjxxvsackexbdbbfcqiqzwltdquzzxwgdxjsexxgwxujxmaretaehwkpkavjjtvmalnkeiixhanqydeuomvjpkdapecfjbyxkypmdqxdsnzzylldnxzmcnvitnkgfdzjisxihfrxowfhlqpeqpubwxwkittubljqpsvxojgklrsxtmdatmrft')
+;
+insert into t2(a,b) values ('uzukvvgrgqnfwynorfgqhbsisdykhevvmigafqijtfkgpgzexmdnszrqetzrmqbitrjvgigrogophhzsrjgubhpdlvgwdrxqzpegjbfrrjvdpxbgbnycdkmkyzuqvzxzkkwhxcctvpeybbxbfnoikacshjqiqzsnsrslnofycainlvavxuewtffpdxgljvowsf','acupqsjsambbkgfkysvfumclefhxaqflgfgfsfukuvnwoewwgkhtcffvvwoyovcvjinadedhcbrkuqnqppcjjaelftdcdnqkthxzwqiexpbjefzomwuinctklksrtwoltqomrfydeezjdovqwxayqiyr')
+;
+insert into t2(a,b) values ('usgptbetfvikdbclqlesumgfjuatzmwaskixpsirvogwqe','xzthrtipqzbkifxazfcnjktrfzopqfbmdvifsdbkqvsnrygaujnsxrvsanesecyiemjrfuhcdkntinqwhpgbmztqwtfxbprxeekwethakoklbzykylfhekwamkxskwpxniphmraauqbletlhonifripqxffuwoyfjmvvinhgnakdivwxykldzmvwljymzitkqotbamznxkihcagfztacabjlwuosskxuauuoeapmavxwoffaki')
+;
+insert into t2(a,b) values ('mqagngqqmzgefdbhrjuwatkcrhncbemxudgbwcvnwwcgxvzkuohpcdcllrwfhuu','uqsqbvrugoszarxksemizwtlpsqcnhlmuuilmouhyxxzuqpasrsqngxmyczjqraesscluprmnnvvruiczxojuycizyrmgjskxeiipbulybkaczaqedrkfmdmmfyniwvzt')
+;
+insert into t2(a,b) values ('swpmkcothijhqbkqwlmnpqmmsopinbtpa','wqkkwpjbhsfmqnrsctjjggyuegbtqaqtlivzrvemjqrvnqlrwdxxfvzhnwsbxwkdaugqhpznnecfuzpxhhfqefcvomwmoeadrmfxpellmbirppkfmdcvcweedemgtwrdlerigpwtfppfkxnavwovzruijxjhyfcqzrldydffkfzov')
+;
+insert into t2(a,b) values ('efyrdfswtenpwigfpudctcbcqptitgrpjrlgltnmlarqacnwoixhdgusyoxkxsgqzzfildbnritasntlowjqoajbqpdfdlmophmiznydcytpwclypxeiunsfethknkzpuycocfwgnwjforbtzffiywussfqrnojpikohwvukqbeloczmcwrxezhvnoevwnsyoeejwipkekfilqfrzlzyqafyzzgzzjqatjvnd','wtenwxnulpczxcfjryknxnpwouxmfysvcyxycrdtphubagoprxqaguoituydxyarczpqwwnuavuydcvl')
+;
+insert into t2(a,b) values ('vhqfpvmgegpzkvcwsboqhnlvzkikxfsqkmvidevuqvtcfaabhenizpfkdxdijmbmecaacufvinnicvjgdsfntxodfcesapebczfpbssxfgpuonsenvlafhoqrbvjbdas','wrvtrzuunuywgsnustzjwllmwyoumuwzszlmdulmagbtfvzhbxpamahlfnjkcdrmzplqssqvbcbzxepqkzdqthsnrqtmbcvuhulmrbospdsgfhruxioeyhqrwyagfkjgnkgacwbxhhvdblszafsdsqcud')
+;
+insert into t2(a,b) values ('xnjnaadkxpavahbfuyefsqktbdxorivczqegmkaaumzfdbnehrenltcynayccsgvhxnzkjgwnfhfrulbeqaduxnqxcwtfxcratdyzdnenxvehqansjmdnrdpvjmmohqelamrinfwkypdgnrmcuqkxkg','etiqgmcrncmokjjdnxfstluvrvfpoq')
+;
+insert into t2(a,b) values ('krsarycdqmktpnzlpbspzeihtmtepnfrethkyqosfraspuwwzrogcnrcwwdcyskjpsxfzkxuzbhouviwlwpzqmiietpxeaehvrczyaihfgdrvzpdbcppanmtjxkypgyptzwjbovfowrkqoqofqgqsjznumwyywnuqqtudmdothodhjrbbtwparjescyhmlcgpuxsdycatkcgvezjoltfbctblykojmoakkebvfzsilzbrqdtlqyficuivfqg','hhvqapaffmwfnwzhtkfcnuxbnstjbtvmpnumiljtuwntcgnubfizwyyqoiqdncifdmamuweeikfkzxcuzvsseyljabheahwxtcmxlqbihjemzzqtlpkstipolraorqteywvbgrpghibrssxujcdprgmwaliscbxnfxgkvdyzfobggengayekngpbyxuumgiataijufjxgrdrclmzlqfzadfgpxzzjyyag')
+;
+insert into t2(a,b) values ('rlitusvecictblncpyogljzmopjirioilvdzdsgceireomtfryvkgzwhvvbcxjyxjmayoyhfvtatlctsafcennrehewolyytzsvufgirfavoxmfqtzjahobqggpzdjcvfokyfxpkjhkpqgciofuh','nxhdzpqpfowpjinceaysbbhryzswmkknstgmtwkyuoxcqjanhffbdlhajyoeyecosqfsjpeppmlekqehnjwpknbouqrspwicgiwhpbovpqwibszwzvrgmobmrjncpksahrlahigqo')
+;
+insert into t2(a,b) values ('svnhilkxknhopueysxyanwhfbskdomccawsmckyeghghbokfjrzkquyqsfditikkrspbsdnqpwgijrjnfhkqxzxcepplctxfgzosxzyoxinxuqojynztmzrepufwwlgmedfegviqipssq','mlzqmeczvrsrtjrdidfqxiyfboyqovlqkpdkyqpdlgjfqxqlgoumxkztqclgldforyvspjqbhueltocejfykwwzhtubtbtmsmtczlgfagedzakkyctqihwsaemzjcpreivxnyfssqcvjmcgcrsdliwubsnmyp')
+;
+insert into t2(a,b) values ('yorvsakefkujluvmjdtthdhlexavqqtbtnokzcjomiidryzcfbaachcrcngubmbqbluhdsegjajdogrvioxozorevflavujgtkznaskulvbidmzlzqxauvexcfwwiivjapcliiujly','wvyblgmnmjtelyrqhlqkbjhwmjuumiectlzgadlociiybovjxkqduabteuvvmiawzqhpsedcjbaciepmikdjmgccruzneestfyecnzbqugjsoskkchyxcclimamfdvgcpvdaszfxzbhvnljeiwpucbtvgzoizxjaldhpyhthxucfnuferncenzhcaejlcrbtifmunagtalmgkwptbsfirpommjlokulxwrkanumryxlewvccqpmibfb')
+;
+insert into t2(a,b) values ('emhikxjhnoikmlhfzkjkzpbjcekormxtbhzpswydkizhfvaspfvdtghtfhqutcgtjewn','obmxnhngsyaihtnhtffmbfqhyyuvcpnbklzidrnjfhjenmisouszhfnahenwicnerrbjeqecpkbcrdiuoerovkixcokmxlyvhmaekhfftjpwjznetdkdubftoqguyuuscejbltfcbxqtqlhunjnjudqtrukwwknbowpmhqgiphpbioemuirzlnbjzxjqthlxsqitenwqgfemxzukhqntteotjosfusypozroqfgcqmu')
+;
+insert into t2(a,b) values ('polwumvfvzrghnxgxktghjmbylsofocwrutabfbptmxxsdexqwjzlbeso','nzycgcfsaqbzdwri')
+;
+insert into t2(a,b) values ('xuyzjxqqvruhvakgdiebvddhniljzhisixyhygvuruxrknrhhgqvrqisbxmgujnjqdtajrbybnbvmhtwrkdxrpcuxgzctzcvzsfzreuaydyxquhaxvuefnqnehhqkhwttxzqegjqloqdlrxbvxniuliidfonsbsquoeiwzvfegdbufshvicqqel','ablfyyouzmkmbsizkncdzllecbynknmqjlgffjzizghganqnxkmuwuzqkcbgoelwbnayfdexdxyuhnxuzfafedwqvhuml')
+;
+insert into t2(a,b) values ('wrdqclhggzyfdsurhdswuvvqhhfpafrkbrtvdwibmwseytzvrrzcnxvzjeoybllroecdtuastlgtlmikymifvksbsisxvhjijkvqcirtyslustrcjikjjxbxejvbbxjhxxyudaskhrlbwyfcxajajlcy','ngktqnflzhtkacyidfacpjasvqoqkttwuuahonmbjsvaoyosipmwmvhczzhutjbzifgyvshljbgsygzulkzbqwemnfkyexnyhhazyfcfoodhlqdpezcfwfzymcvtijewlrtnnjjbafrpwojyigshvwggsanhggmoljdufvkcvwzdmbtblereigtxndjfgsqfsiulrgfippchgabyldhcfsrnyxusakzueebanptbhlcfewhihy')
+;
+insert into t2(a,b) values ('coudonliadigcechvvydpvijlenlvdbnzjjnmwnijbqhphlsnfdrbdizmddhthrzskerzdptgduiqzqktwodmwnslfbzyaedobtpdkghpvxgmfokujxpwansnyskibacfknguczaagtzlzrfbvgutwfgnsipfypjnibcazmpuzzbpwbvtiaqxdizeofsdgwytfzdwaqjurxatsfeuqdsfdgr','hjdnuhnidtvuxzplfmymqbpvbvsmhxnreiberdchrzevqbgrkzixfbzvtegylwgtdftgpsfqrsagquificonnjcktcfqhqnluytysbiuthraznwidrdzbqijdlvxvxosvmajnivyaqfvwwopaizjmgzha')
+;
+insert into t2(a,b) values ('vicvwhwmasxxbiskmsdgeysvtkogkznnntzgfbqwbjkawcyemkbgmatjvqbkxgiqoxjagwzwekfjwznicreuuybvddljyzkebazwdggxedvvjcfjhmxiwqokxybxydvopmbsiatvxtrixnmusbhxpjmpdcanhmjjwextcokptjgeulsrtddjpgjffhyjfcgaugiubshlrwxxonvxfbxfswnndemvzpyecuvtsjwlsbfjv','xebrgmzefctwgnhibllppeezipjxhqtyxhpbwclvipsycnnrdrbieljjlfh')
+;
+insert into t2(a,b) values ('tmlajfvdetpcvyzuemhcalvicrrfhhiombzhvypfzjhuowfdxcxrjqprgovtdsbgxaofrtdugdnkdwapywbklzcwcgzmwwgiccu','yohueknbasceukklluvpdwnktxcaaahnmtlooblcummmubxzjktraaaikokxvpuittvvrzjwujsgxpouqdfykvdasxsvnigqgvqkisagzwqazqxrmomaitcxhamqujsigicjifftaejtukawepijmdewkmrcsixswywuykyrmrdfjiuxzcvwzdgbkdzdyfbe')
+;
+insert into t2(a,b) values ('atnriunmessqalsdyxjjelnogfqeiscklnjshvzpegybujbkzxvevjhbzbrjpoawxqvmthmckmtyjvbyfupfaxgkdrssubuvjbn','tnvyejdqhdypuyirpxcwclorzbntadkhxjyasqvbnxabxmlojfnrtnyfsrhsvljztxiirarjiknikutphphwcsevzqvqzzknttsgfisceexssflctxdlblcxccjrsyamlywbfraetfqrojxwirftnakxbqygtfrmykulhivuprqldwx')
+;
+insert into t2(a,b) values ('npufoukvlooojmauvimftxxrrnyvftuhnykovxxhlnpltvmabtcglhldznthgbrxwikmjmzvvhvnntsnpnifaoeotdkkradhogklwhettmjgetfvdbomgxmnckkzkvoypkzxldkfbnkhsyxvjt','modlpcolixxmkddlcuqeezeoevqbilanmdmcieqewjortxubxithfommihxdwztanrxamgkxutttehaejikpfgsxtvxgyftjvjgdhtnfzcxmeahzilakojnlbpltspvhrjutddjfqsyatlinlyobluotctzaswangaerxfpfvcyzvgbqbiqjcjsqs')
+;
+insert into t2(a,b) values ('tfmiutkorbziqynexeuqzyxmeopwtdfsereiditxxyrhezwyteygpauubgzmhqkfzormancknqodkfkwfvymyhdfbgwoqatmpxcdukdyiehcaefzeabwtbiopkbwthavmtpfibxauvrahzjjhryqqmawmtwcirbyftrapiliytndhoaglryndxuqgsqgtfgodhgtiyzrivxlhnccetmhjsyvdrqtymxpaufiffepqyzmnb','mmvyiwgajlfpktyaybslvobubasiahsalmgfowthvbouwhizozdihfotyuwhybgwmnjoidqnehuxagdtggfdcginsnafzyxvzjmcujjibyazubrlsgksrlufrkukrkmslpqfiwnhkifiaydezedaaszyseqkpwclhlggg')
+;
+insert into t2(a,b) values ('uxtpzhtbnhsjkbirmdlgfmsvwly','ngkqjsktnezcizmrkpirbwspyynijlyipgqhqkfodpttmmxwszwestglodybsydayhx')
+;
+insert into t2(a,b) values ('xoxtoxqtagaypkarhvfzhcakescjhftwafvmgfbjswkhbdctrztmzgpckyhaugkwruiqwdolkjmvcsksubjlbfpscoriebdqrq','xwtxovoqpwqzsrmpqpkgigepbimjvhdryvpiycrycqwjtjexzyajefufsylvvsotgkbjjytdvxqkmtijhhwfjneorlmpelkmqfqrzbnjxnfmdqyuollvrmkebdgxrkxghlarcqktocducvnziymrfhfumccveiektnyeltycgubloahfflyjxkdglcloxhjkqbeucswsyjrtypcplpmcbnjuylicbzlnaalopse')
+;
+insert into t2(a,b) values ('','gqsnqohdsjfvinyqzqztijyuixmzhw')
+;
+insert into t2(a,b) values ('xejrlbnemgtunrosxzpanyoxfqazaxjutiizqtlxwk','pefnbbtuflkmgabqymojaifhh')
+;
+insert into t2(a,b) values ('gdvlmgdazleuplnszqzeegdjugktwfhgmllgbfnkgtrbffbgaeyoffeykgtrexohbhrokophrztcnxzdeivfxjakigisdewxnqujhjlnrxbgdhluwyxkjqzddhaixhnirrlokbskjjsblthkewgc','pkzxiydpicpsyvvxvndswgoebujhjpyfsoqjmmecwrsvmrsdmnmrxrocfwmkkbrsgstcvmoflsystlursnhhoibwdjtiazmjdkktxyjtjdztfjkjrqoxfgbgmyxubiyhpdiycqtgcvtcxtjxipapqzffaaxvhlzbbrpbsotuoqgcufomshnxjltohuocmgrknp')
+;
+insert into t2(a,b) values ('ijiioofhrsbdshxljlibbexozplywoxjauaffbmnlcfpzpjlysntciuwgjzsourhhgqxrlxxifdhwdqumvttchdgfdjzclhhqnozuaqbcxtfwribqikkgkhfdlkaskfgduijbnkwtdqtwejkfescwnnrxgeqrmapmbnndkef','mrdtlxqdqitkmhhwcevyzullwvcjlmmiplxhsodgkbbabrgdosngaazlrztyscldiztisccxkfzgojxjobmzhfmtqpdwengeisvpoywrntgbsauvshugumaqkecgyxvcyhdohazanlphxsrjfdomeuwjryvmnugkqayvbsijgkfpzpsqpiqysjpjaxjx')
+;
+insert into t2(a,b) values ('pdmdutlrugfcibaofgizkqsyromvckwtizuqljrftdfhcunyvonguceqddaoqydzvgdehjybkoejffkfvscgffqkdffrgljqrjmbiasggqtsjhvwrqjytiecidqqbyjhzpghyvlnlgvmhwtwuhhevohgaazfxrxcrrjkknquqarsymcwnqcqmkzjwwzeqsqycgnsbsklfqqhgwzqinqmgwj','jdrhfyhqctrqnnxegllhbfoofvqzxiargcriflszkktcjuhfrhshypxuhbijtvkzfhkgzwlgfajvfsgmwhpyfxjmwyldabwitrfevgswsgwhflefxqpjfpkwudbxucxifcdojqdzvxxigbvzlswkxpsqmijneqzzfsrgxxkuyetybyjnhkjtdczlprpjaaywcqeepbxeerpcplosfrgttaxnmnqwvkkjnmskqgcnomwdbbothighsscdvzkyk')
+;
+insert into t2(a,b) values ('utthalytxhspqjbtasduejdirpmgampeecjbnpvlkffzoxiamtwyoxnepcukqtiaovvkmwczzmxlmumcftzsz','cxkgdldcrtqjjfuabwaukembtrvdgavilpgxptvaxcjrcplhkqfcudsrmsfzfsnclfpgys')
+;
+insert into t2(a,b) values ('gnowecifoxitiejgjnovwuiskvinftyeahomoycbifcbpmkhkfhkynvslhplvaqliddvyticftouqdifvwtsbbmwdlonqoyxzqinqoqoooudbodcwuraajumjzkinbqiaanloxwjiwqgnacoenuvsnnukeaqzvvcgqpbdoqdb','vaoybpdeijxvfqsaedbuuxdclvgjvkhbxvwfcshcxbrruvdhqpysjvhjhhuogrfzpjddfoesrneswlqinquajfoqewidlnznkbujrudloazskvpogliekymrujixvzehaznnvrcyyklrygau')
+;
+insert into t2(a,b) values ('autevpvsfgwimjproasdrdfrktqctfzedmupieysanzzahexlvyyqgbmnmaeyrxawevgkjpottebjfomqreeoeltlefggjfjaewzmwduafpththckcxqabcpjtxbjhprlslhzpjuidimypxdrjvlicszneydotjzktctuppmloirrtueqfalbapqqwejokjrlpvxqovyxmsdiofqnojdfholejhohinrubcaugopwpuauxjslzjrjcl','woxcappkcqewxqtpblbsosulehybjfnaphw')
+;
+insert into t2(a,b) values ('ohcgvhanbkpzshnmwtcuykkhbihlgbgxzyjknerxwxmwkzmxpqowvybxndcdckcrkinundslazljrigazzcscxmuwdgfneuatwgfbegosmipfuknjnmvfyufow','rumeehbxgdigbdgwhmutlsfsjxuzlsiltjjwkudpyrplagxyzjwjrrrdbvnqojlkcegsxdgkrauhgclvqrocckvpozqsowblctozfcpzjtwcpwrsasyfmfrzxnmhls')
+;
+insert into t2(a,b) values ('sflwwnhkwaaagqrzihrdlsbvopwtheqmccklvqvuktbwqjdtuimytjfubewfpjtfpyeudawoegnzwjugbbqgnadrkirtkpprqwzdrwypqwdmlbatrrpiwyvch','yqybmwictpgotkahwtdjojdoasuyscihhpjxxmzvliputymiogibusqywxhxrffvqpwdpadaevupxcdbjghwvsmwegivxozphsufqrearjjpgqduqdxjehvzjqysgywrnkhugbovrsyfycoavijrbpthnntizylrt')
+;
+insert into t2(a,b) values ('jgzyenckcmiohmyfsxnbkvatbrowedkzowajkfxspkyxehdgtyhlcegjnnphsxva','uasuvxwrjeimbugbssurrnpzryezcfkoryiaslfbihyiicumhoomppxwdgtmvulbmikwgdeabqyguwzjkzezpemhkjxykwpycvuuhtcdeuxcorupthyhxqubefepmckoadoxrjnwilvhenfadksiigprvvskohcwcjppkyckivhprjoftvpacfwvwjztwssjrfhcmqkqlqccfqqlyidlehom')
+;
+insert into t2(a,b) values ('jqhxyertenvbugpvguxyhahmperqqvnmosdzewmgcbkmlikeplmuqfvwldeiogpljbiuex','hdrpnjtuwxvpjdznqhkngjlkjkcnghgvvxrjnnbarmahgazbbjcdzcjnhnwvioiysxmdxxlfqwqdhwurwcprgfoktsvvgdmqyzxmloeqsyawxhguxsgctxsxypwbgzirpzvgymqcpasmgnbfmzbmpbelwhdzuyhpsjetivsp')
+;
+insert into t2(a,b) values ('hlpzfolltuzozpefnllatwejxyuqmtierpwdjxtzlwpurstumiivjdpgdgxlulxguekuenthfibauolnjmwzwapbrnxmcnjejsgvzrfctqyjvdabrbeihvhvbwpylbbejlzefrrtpnnlqxqtdwfjfnofipxrhfgfsiygcjnmfyzljpvlbuwusdoybpdeyugeubmecphkjiheardywahqyuhbczkyprhbqciottlmpsansefn','rehpahxzghnscligoiegdgremyayecjuup')
+;
+insert into t2(a,b) values ('pxxkkemkckdcippppgdxthvvmwvxnzbaigbhiuyutgptgbheujokyrlfenmzyaytpugijvtdcbovaudijoehlgnsotncsltlxxqkmvsdhyxgkincdrfmqjxsmubefzcstohrhlqgo','orbkfsxudnmvatknvtdislmgbuldnbnyfqxxfqnplhxvchyoxgkkxfoejblkishramkkhdsqeaypxjocqfycverocoogsrqouakzdprpfjvplczrwdoniykevnxxhzxpu')
+;
+insert into t2(a,b) values ('leczoozxtyoizmxcspouuinsmponahjkepxkxncvdpnytgnbrsfgjkluwrcqlenovobddipppdmdmkgnykpf','ujpxdeohdhgqjzcspwdbiqzxu')
+;
+insert into t2(a,b) values ('vhltmxepxwraancxjwlvrkpshmiwwiuvbgbxpwmfcncintbfyutoezxvmznnlqkoewizhsdeqjexlyabiccgtabjzxlbpbjcpsrxbbecqfxgkwuppjmctmlnrvijsavksotlnwokctoipebot','kiliacakbpsfsfgqoajkudvntohyxvarvhretdhwijxrmtyhrhrodguyywxagltakxfqhviudvhbypcrbeswhkuruwwzwkmhjlnvuzuheiwbqpjucxmbbpbefznq')
+;
+insert into t2(a,b) values ('cmnpoukrzijfsadbcwsomavlyjkzhsztitjpurdovbxvzbiwzrntkwvslhruwlgyalllayorlfidjphhohadzjmyxpqpstacofcrqrpjpxvqfmtlpdpeypbqlaccygnxjikevdygqcwdqcnyhwqfslsstdrjewmkridcruyurypeoertebfhyfzrstcuhurvpsaavyeuakfgzabovzsvriihrjylgwgwihefos','daaawkquhyfeupnllxfrnkxnqmgpiqdsivbsxdmvhhishmbuqbwunqyowlvsarulmijepkruwhotzsmdfgvgdoskjzkfryafxjonikfimapalppknucehjbfkicreoenmykwphlmsewozlfzmbpvogurtvnoqisfsxbhglkshfzyijvdeiukpfuqcgxhtantbinfubvvhugkknmaxdajqiuitxmjrzljzwtbkvxyialfolle')
+;
+insert into t2(a,b) values ('qnlaxwybqplepblhguhbogmzzdqybiqxypxrsfyfqirirnv','tlqeukuinikkgasimmypnsoauet')
+;
+insert into t2(a,b) values ('rfgxnimdwenznydofujcnxlatwihggrzpwttzrfrawpdlhmfkfwbrmbaoosiqqlbehvmzvjbigfxnbkofpvnvqbpwnngcqulxdlwzjhtadipgndzjfpkqdszmevhwcwdpbyjdxjxyntobctvptcozisjbghahypcqqguqrpwottocadynzpqzjbyasjxijfzcshvsnlaiafpufjhsfiorubfvyqenwcoamvwclzgeuypbxgqjkwgvoetlygbc','nepxslhwkyholtzciqaeilradkhvklubyotgzkzrqmpdtxqpmdhfegjnizozjjxvkixljdeycdbeyomvkvjjtxorpzldfbzrzhiqrfmpsiadxszrcksrgzurgjwfcwcqrlgutkjtzsetkkpupecdwuuuhxbbngrtrnblpmfwdjrvwhfppebwophlmfshdxdpdxcutehjaakhojgdttgcnjcbdmyzcvpmnnrokdkdfltzxk')
+;
+insert into t2(a,b) values ('urmlbuzqcufvfyusbipihsvfazt','putvgx')
+;
+insert into t2(a,b) values ('eltcsjcdnzswlgkdfusuhppbieuhomicnebblnfahwvxvhttkoqjxpbyhfvjfazgajmtxyitkribybvpcdxtejcswcepgvlfraggqxxgirkcyinlchcgghcfvgyxhivifzqwkwcawuxjdwtckrmcxfftosmmzjhgbgevwj','dpxwdgkxlxuzbzomnbjrrqbcjrjithhmbxjtdjzfglcfxydxtfynahxtvrensiqygjvclkhvdfldjiuqqrqqftrwseiyc')
+;
+insert into t2(a,b) values ('uvrzrtzxstugmjrkbeybpuxjyfxdqltnscqkdhojiwvwfxixqyjmjlioujideuhmsqibnhpimhrkgjhufgjpcsdqprnwfudahztvlchyeaafptrnwewogjcnvilqljuvuoilytkpborzpsgyztcmwuzxkeoqyfldrnrsgzlzqrudhzljtfpyhrpylxhqtfxneybcxceabjtcpfzqbojztgkcwthbtrfjzflopvsmqlsfkwb','bhfvyeatyszfxnxysismndeqbkazkqekqvokjtbsffhtimlxjxqntjmgobgvuqlfgttcphgejhgwjpwwhpoggupnpjskuuxnswkynhchjkgiixrfgwaqalrjowoonofovnqdgtwnzkzuyxrsmgkrklpqjgawvpjuqryqdahmhrrbojzzjsbnmkhgpwucrcweivifoligqamkaamrbykovxedc')
+;
+insert into t2(a,b) values ('nsqhnbiixzzqudaohhilnlehlkwfnoouqnolahtfynleskvusuodtztdtsrrjezcetpsqcaegoglrdvwdyrlhzczwudwyiiugnwqzdeyxrsnngrtrippshwd','vrgjaxftgrdxyhzgkntvcrmetqeizwyhjohvtrlzazohxfffbzkhbmgzhhaubdygncjvizofiuwooahdirptabxnqqvjvuvwczgxdulpfwyebqbcryaapeovamzedskvefizdwnutzwuawswdjnxisnvrkmrjfjdqnmtsopfxycpxuagexkcranaclckawuxzwnigetsqfevnydgnyljymdykw')
+;
+insert into t2(a,b) values ('helzfklecttdrxozoyvfrrsznjxnyrokobtkgxzztzenezuvrxrsvhhgjhdntbjjcdeuwolbikhmfowjohyawpoqhrpnptpdromusjwtmulgqmvjmumxthlctzxvklulxwwjwmubiylzhbdmkhanmxnhnqkyclxkckhmeaibgbcytmxkcpaovgccxgycbnmtezqkbvtlsrhutvfclelmyapeexo','mlznpdeqqyjwucuffrqvjpuaakecuwxblrgdihrkpbjszrnkzfkzhifbsmsggdkxataqkoduzkvgpnrnopcexgjgfaovtojlggihixushiwlysfexsnhxeg')
+;
+insert into t2(a,b) values ('ntnacdpyfudybsekajdfoclvstrrbgsirchsiphtqcttlgfdvjfjqozettcosojdytxkxtnxnrylushhoqxtvpgsuomrcapvruwdwdlkdfwqeqwrshldvxexwylhurwws','ijnkzebjownehmgbzbdpirsmhtsggpuctlfosqmmlrdhkgizrfrahbxccxcqhnjbgsuoeukertgxvoaafzojkgtetsedxghfp')
+;
+insert into t2(a,b) values ('fuplwwwudlztwqhrhazesysybfdkdrpsvpkjnvfjoealqhsplcpxfgkqamhbvjvwodiwpsymhcuezyfwglwsgdqzocrbdxqpnqpijwsvmlsailrsiypuakcfoeyvazaxxlmukbzwatckmnadeaupbxueyqqwgsvsovuxbtvudgktimaosdrirqytjdewncdvecltn','ckzcfre')
+;
+insert into t2(a,b) values ('vvbyuf','dkbkvwjvtrpdcgtbaahjporguqvwmwrttievgooxbaonqspfvmefogcnkjnmjgyonzdkfn')
+;
+insert into t2(a,b) values ('dftapecsfmsyjgafkruzszweenlyyocokpddujehcjkojlzpqafhwoychoidougchdykgfpolatfbyfscpthmlogitvcsxmsvkmfwxfaziyuoykjhefokimxzkchjindzgnvcpsmayuelpxhnwhgtlbcy','ymtycimryqeralgpyhigavrzluuhdlmerooojyonhjzqtuodfywunvpoxpufyjcydzfgxinfuofutgsjbnhoonqokrxf')
+;
+insert into t2(a,b) values ('nvybpmligmpmawqhuhayqbpisnctsigwdlgqgaqleqbnfljtlzkffcxggzmyphjeccmsteimdxvuutkhaseyrt','cnuuevrnbdtmolzjzkaanvjmfaqnagafyughmsxengfwmjkgscvgeqtsngjwrequbffjiiltzeqpwwkhkuzdzvwvqkxxqgednzupbkhmfucphnghgxzgwdenmojrtfisjsykzntpasuyriktqlamgawlukifauqbgt')
+;
+insert into t2(a,b) values ('tgztvakkqcghzlvaxssxkwgkeuginzxtmjgiltngcnpxhflrgibcqfdmtpkouadxucnhywfujgzswsetshaawoafbakuafzhppk','hfkglqwwyzdjjauykcqvivdhjolmznydmvaidntjkydo')
+;
+insert into t2(a,b) values ('rxjvjcsmqjpkovuhjvkuz','gifjtzkerjhzxoousgmzxaymbsleuyiokqezwsgjgiwdseoixdqxgxfpowufmqyfafmeexphpmska')
+;
+insert into t2(a,b) values ('zqertj','fufhzgvpaqzgxnajjkmekdssbgasjmcmtpxslbpbtzfybatbzhgvcojwtntupuwteffkhxghyknkfegapjvopbvhjxgwwmptcwqoidajbtqykexfborwnjgjqcf')
+;
+insert into t2(a,b) values ('hqhnqkrltecowjlwyqvbeieycfhutorxrblyzbevmgldkiqybnolmhgkxkwkxazqodvoukrhypxkmwpuonzwaftpniryqtjlsjsikukccuv','ytgymatkbbhzoodvnwmsyoytarpvdqaibeaqbuikpnyqedrtlkjiqhppvcouryyrmpvjzzplownizjnttcxdieiyndwpqncpcinnekmdjribtqxkocmqwalzwnccdvbfhvszybvnwrzdgqnqjhukejvdvxestwkqhriswokakv')
+;
+insert into t2(a,b) values ('ienjtg','frxmyhgulmbpgcgfdqywysxlydoppwznzvpyosuzfyeufzjovojyfrjernpvdsggcaozaszwikkcsefgxgcndqbaajgbusmtmffutzpzkhgqgisllqeelbzrokkfcvlotbvcmlliyawzkrlexfphyyoizq')
+;
+insert into t2(a,b) values ('mtxynvehiianazrzowuoymkgttxcudxduwgfiwqpuraeusjillrhyannqcaafzstslhpqyadqxamtdbdsdmajxwcfwwtabpwyojtlulqaauterpzutvfpsdyafylzyfkdhjefpbmdxsumenpbzeggfscgcpmcwwq','znuzhgeaoywqqzedvudorgysxxxzzpprjmcgprbnbcqjhqnbpecgsxpqzhnwzoaddezhsndcnkpytinapsxvwepjemdjxmncmoydiloecgbslaxucckebtlfpxnzwbupcbwgeydifbolgmaqrcxvyrixmyxechpvnvhrbagrpcwpwfbkohrckawyfvawpfdjnajupndjptrabxnxciqquqbdtvsjseyqgiisxkdloewcqfumixqblktwmz')
+;
+insert into t2(a,b) values ('hzkfbopdvgmvsqngojrczhocvuetaznocuurqzbvfkdnwurnspveifkxvsapzgduyrjykjhxcjrmpsyvxblizryuotvidojcdumhcefziwoztqxaqqmbnrildrkyswtowvlkgi','gvdahtblqvquudtclpgdrfut')
+;
+insert into t2(a,b) values ('yujdwrfuamebotlxpmmmghuwbxpchfswsrecokdjrcjxfsguskakulidrnrnieabipbwctvkmaplmmzorspbxwnaeaxrgttywgyriohjupqkzpqeipomdlrtyiapqvhywsyi','zykmdmuzjopwtzacxsivekdjkrmamilvipuwckxfwubtbxektokwwohrsdizwdalsvxbigucchfmrrnuoivbppzrbxtjbsfakckjkgygraicymwkt')
+;
+insert into t2(a,b) values ('dnnjidoehrhwqbtiuibmdwwcuigwdkaegafifyxhemaptqmumpgubjmxsvsihpqoxpezvfzwwrpiyijrcjybnrcxnaoqmdlyqjjddgtevknhbsovwaeapbgcxuzlntrmmufmquntbqsuvjxjwbgimnyq','doawrv')
+;
+insert into t2(a,b) values ('stbfhalhdwerwscimcrrrladlbv','dokgwelghmjaqxoclqgpfvestalxfrzxepkkcytrilmskv')
+;
+insert into t2(a,b) values ('vbhcuhxiebxlgycgkodulhwlmaenbxokltzcaazhmyqmqwnpofrzbcndepjgprpfatkamyracdfjbenehdofzvxomixqpgxfkydfjuqfvfakcsbrhxzkkzsogwqyfkutrdtmyasifckywqyuewgzjsmlrkwkpraprklzclbjnh','vdlsxxebybjhpgxsukaxphrnxylnkacnecxtqcabstlohfqwgbaugiwuaoadfovcuidsmjf')
+;
+insert into t2(a,b) values ('ewcyczyhsuwalbqwzivdnoovoemzkcelhwkzqvidqjnszpoiigqxirkjaqnluqeulywjfqlsuqaooofxtnmjyetwarswwdvxtxlxantlaecmoqiznjwbmoynktdxerylommwcclellffrfinqdsnnrfhmzqyeozcacvqwqmeqhjirvegbrxxlyrsdirbdoffqitpxlcvsvipgkzbgqpjcvvdqlqhrxjhfsk','ejukonravvlavulcgrexqluvnmbktuhdjyqcknbgezihdhhkgtwwruinpwpkkiitkxjdthncvaslucxlpmsjyefgdqrnfeaexipsqvmablmtholqnwgkoihqyaadyrnnuruibosgimxiigouiodtnrfbofdfpjrrbsjpritdytxmkxwphtzyfaopnibcbrakzteinuicnkosyulxqydgsmuwkhpsbnegrqaaxuol')
+;
+insert into t2(a,b) values ('rqccdlmzggnhwigbopodnrkapxdkzgqrpowhemyzfyqaqqsnhfjdqylbvhcsrcdwgsglpdayiiejqomypruyoqlllpxlwbbqqbbkwyuukoqhqoantpqnofyyqanzeosbsgcppshnievmyaepnvbblubeolobazqyvspdvbwxdnuhaayggbednyftmrarqyk','nazobrlrjcvimgapntpdgokisrkhrcxktzqvayenmjezdkfvnkmspvkiysfxsasyofblnjtsaprzwbsdrltfrfbypvpejpvkrzhncejqrwwcptbuhf')
+;
+insert into t2(a,b) values ('xnjludghhuzhjbhtxqnitsxzxiodaqjhfgsbqxvoujabwkefvxcmzotmhzcpjfahnhdficekfgpxqlawicphxrcsrvipoqilrdrzpmfkipchedyjigiotfltubkuhjguexumzdpaofotfayjncrjhqid','wdvnrabucjypxtohznzrxavimbfsjtdqzsvvmgvlnkqgsgtdjybsxsxfpnviemokojtmthhcyaratormlolqwkvgktekvcfuueuqzssalsinjhwzovortvlbjyrubdqhhccvdidcrpmzeuqjllftemnrecqxquvxkwswqpumnluguhrdaidl')
+;
+insert into t2(a,b) values ('wfugtvrvuywojvzsrmiereuvgdiknzywafvebjihhhidrdvqputpapcgqfohtqdvxsjnaquskdzrrberndcdthhvqmrttbqkmppkrnbjrtdukbrcdsogfczvilhwrgiaknkwmzqmkskcwjtmihjfjpcmowkvibfuplkrhopldhdw','rwybbjgokbbxfqirgdyo')
+;
+insert into t2(a,b) values ('rrgpygksmrbfroahefaxjtsymcjymkgyikhimslgbwlqcdcgcpxwnufjlknzazmiscqhq','wmcaxgieagxgvoqstastpgaqajaovrgzaosocpavtr')
+;
+insert into t2(a,b) values ('eqyryrplzumbsoxehvoeeftouizrugnfuxbzobrealeshgwlfakiopnpctgjgkjkxcicukqtdaaygdhvghidnphsytcfhoaoshqpsqkbfdwjjbtbepxxlbdhtsvoljwqyljiaeckbiwohcaoqkovgmhiodhznojfeozmqg','oafculxiyiobfaoqvralkdegwzdzagpjnikzcnqjlckhsopxtgxgnseruvqelyitjhkfgmdqiawzszvpetxtwsmyvitfrydqterjqgvjokaufhejivkv')
+;
+insert into t2(a,b) values ('cngoifiauvarxuttojwesvorpixkzusye','nbtsiyicnukpzv')
+;
+insert into t2(a,b) values ('zcqhhjecvmbtzsfxkhitkeubtkslxeiysssxnnqjxupeqkkdvljzjjyuadvmnxzpvdcsrdhvmviaaiobalzzvqexqpddjkznfhefoivrhshejttxdlrijtrwerbnjhtplhigmiortrawkrdpmrdqkmazhpoqpxzonreswqddmerawnrreadvehgghxoahvjyvbwechdogmsjwojugrlt','dyxqzhjecfvuvuidituykpeewiemhpqjnvjnjalnwvdfuh')
+;
+insert into t2(a,b) values ('lpcymklvlxtfpesxfxfdocczradfhferbdmfoieowaycnspyxfcmvlciveoiklpcioscdetaobncfgjwwrjejctjvoasepwfcrzfqhybfyifxxnqcpnoprwoxwcetspwbrfyuehhynsjdrbqljbfxdyffyfvupxrvslwkoifqi','gvsvfearpgmncslbauphhjoassogtubeeflcmzhfdp')
+;
+insert into t2(a,b) values ('tzblskvpevnmxrvzpprjtwojqthdnhqeexcalonlltv','zpqzwkorbsiqlibtxvjdymotjomttqgpzqwdtpxqabxseaiyyhxyeiqladobqyfcjpseknrfxyutcseeqjd')
+;
+insert into t2(a,b) values ('hzpzlsdfaiwbommrajfxdtmemlqddszvuwrmnpnfgcozfspsjdvhrbnslxuwojunvfnjklbcjvdvqvfxcaygpvwlqetobyjkskairqjfcrbnpzzsxfhooptrtnlhwdfgivsznrjlojqwoatkfspjvotswlplnukctytdfwojrcptykxtgyiobfcmpayopduonyhctfuyulbcrhwdscvhzddjqhagceovznxuwyckqjjiyiwxnxakgbmy','jhhikbzpjmrckjclgpkdrpznqwvgldamtoipeblaiqxljkqscjbmdhijoaotimistiyzyeazznwpknjxevzutlaeecijvqzxhchiorpxfqxeddtxyljpmhsnrdftsenhqezvjgvugdkbiydbizglrquyqoztxnriuomlkggqbvxucvihvqydtnchciofrntpxb')
+;
+insert into t2(a,b) values ('zoilogzwbjpzbqvkubbsikirzsqwvfb','mlilxgrfcomtibtfautxoibysowcuhihzqmjfhevxxratizotlisotjfkamzdapmzlbhkaahftfiptldgpcvgk')
+;
+insert into t2(a,b) values ('irrwycpcnpqckezevbpwfdlptmvwbboiclqypglgyecunbfzxgefnmjrctzymaalykposkwoqbtqcuduqxrmscggkxhkubawbiadqdciwm','warvbdmymfyxxmceprmrwwwjfwjiqoeazydkzunxtvayeoloftjkhjblwdktqxuoxnalskkddsrlozcfbvqfoagwigczudokbxwwbxfiinvgapzqqxvqyigpjssiuyzxjolzqumlatqdxkfjpseiehljbayypcrsluubgbisxknqkwtvpvxcmlbhurvjuyucklgrelwmfe')
+;
+insert into t2(a,b) values ('vlhzbehqeepyljcpwapk','himpduugrwxruqxhpzvxijcuzcchmbwqyxstducikkqtzpytcbwkvncoajjdjlrnhgvkmfgtemb')
+;
+insert into t2(a,b) values ('fjsburmprmscjelwkplibqvj','czxabuyfftgwwsjvhqnxnwgsuakrnbpwsirpauicqcowselqimchihcqnyqppsaxgzpycazixgjsmcvqsssigfilgphignrgczxdjtwilkxrqwwnmfqmhmcsenanoefgwsahfxjempbhcfprssfstahaxthgorxsjxnkghzkjrzuriupeccyvvdcoiktsgbtwtfntrsqwtjcsqzfhlukrgvrgjaih')
+;
+insert into t2(a,b) values ('annbmboodrsvticusopmltiffmnqiadsdxduzcnjjdmpdsqmawaxhswcqzmcregkjoqxsvciymbbrfzhezkjtcsuvyknkjlvzyjjhgncultbizywesnoziiknvrgfcpcsrudboelslculvlxpffbydromvhujofvocplb','jgwmjzkosobydncsconsiccnzynnmznhwnadnxaybvtwiakufdfpsymmjxfnqgddqovybzhjcouzzbvmesefsilodyomghkheslzrpzseehtazbkzqonjuneuhbkcaurndovwpxcjaruypyeisubldlpizpdmcqofixuegiwvsjmqrivypmijnfogfrblturawpuwkkllzodqfjfshavpubkxgjpspopkpdrhqet')
+;
+insert into t2(a,b) values ('lulkzqytujwuusuonkzsaqshydoaboepzgztmheppxatxtasasuwxpmhezsiozpfclbqshpiuietqldgrpvcwesvwaosyczmzumljpdzatyufpsluywauslmdmgqtovczzokupuvoaluknqmrkswenmcroogujlmemygevblqretxykwwemkwdwwxxweyxyaaemwdurulzvrlncirmdhlyrcqljkvethdaf','pfdtykcsbuvhwadsfnjlbiaezubkkccxvjqkyjwicjhdnytyjqdvajkpwktatffiqeacvsrncxgmuwlueyaqnnrktgrcpjb')
+;
+insert into t2(a,b) values ('ahaibvkrfpvpuzxzpodryywzujymejpoltctjfjsncqabmxyosnkzydpqgyczdueujsclauhcvucwnhohjcpajlmgrnyjaabuvxixwzevjtonyjzeztqlzohnnujqujdmycpgtbjdmxnefplutgltkmdfjjzitsoyg','ljqycoipqmkjukwqiefcmfiifnfjgvlysnaamvjsdghenswqyunbhmajtnbbmbfyahcywzxsodebiavkpelrmhcmjiougubzrvvbnnzkzyvkptmflrwicszotoafcvyvrfrdyezkehsswagwqxchqzmkydwulvgfedsbpilfezekmzuzscdkbubpesamqxglklorobshfwnudmd')
+;
+insert into t2(a,b) values ('lynehmntdaeyaxkyrdtorzpgmocksmrxmdpsqlifkxsokepsrggkewwbbkbqnpsfvblwvlod','dbzzjuhgpunosqcbvlhuhkeqdwequxmrmxetvuilorpvwsbkglwfusuvqxvrvtrpuvotbggtrsoyhzgsrjae')
+;
+insert into t2(a,b) values ('qdlosaucnbzwdxoiqzyfqxrwbvzmawkpfxpiwqxkpqduutaduwzcvsegrjfxjyevjdcrzbosimexehmheurqahfyxgykbgnhptasovpraoaokbqptqgyhahhmfdzhjkkwdkpewsvlhzsjonvpfmgrlzcvbispeurkwinfrsfvptmwyfmpxgoyltjqvjcphkosokullrkvjwzyemiswa','ztcspdsrkrtuwqigavpulceryrzbmdsynumsybcnqaxvninzfayotklkplxjpnizmtestfojplofujtoaqqhpaslpxyxwkkjkfkelutrlqeidftepmdmbaqfystdemvehoawkkthwkmwxahejkzvoohrqswvvqoprudymxqjirapjnynypznndeyddzdedzorgljhftirpmbbfninvx')
+;
+insert into t2(a,b) values ('lzkmspphqjazedxsyetfxhstnddzkyemeapzpcnuvcqclsdkpvelifbaknfbhmyzvklbieljhcvtvywloiqrqbzmfjmbyqtrajrjwbehuotndkmxlvudrtovdvdxivpvnpqmaukgrsujssdvyafyfnvflgcudsfldaeywvecnjdxsnbdsxsqmacsersnj','tlgaakddhchcefpxfgwbmmjpqoqwaozpltvkxufnssprxzjheeexvaihlzvdygrxalonkjoehcfahgamproyljtgwioaxnsfodzwjefqamiuorrqtvujcatogadequxzuzbqrkvtmuonzjvhmera')
+;
+insert into t2(a,b) values ('jozmbjsvpztehnsajmlzuerbazlqsqrlnfkaqdwmqlk','rwzxzvppppuzsllpclxnwpulcjelablpghadkhactcbnqkpjzddeptqygmcwgapvfumsttvafllxboxhxlqydwbbwbgovswyvvhxjhwbmyanhxwgouuionboonvzpwpah')
+;
+insert into t2(a,b) values ('pnceitjrlwtcpsuljqcfuosakjixiheisrcqjtaonsirlnxpbgqdzjwzqckpnacskvyqngcshuzwhdekwhggxklaovrjgebxejrfiobdzyfwelteiupnexezbjdaowttzmhsjyppesplimslsfmzrafrlinqjyezyrzniflodzbquumlldcwomamdqrhjenrfkercpmnzacpmvjnilrmoxp','szfmahjtvlnqocisbshcmxhmukkmerrtuaj')
+;
+insert into t2(a,b) values ('vgystpoppzlefhfuxxhpsyvlyqbuynvxiwnnjukgrfkrnvscmaqatqhfbykanarntrgntmgywlvevstwoqnznuubgcuwgdsqosuglbfllohzaiwicnjqlmqj','eumbhtzcwqmdpabgesppzcpqcylqxvlruqbxwzygkbhnntajylmad')
+;
+insert into t2(a,b) values ('fjrzzdoeeaxrbaypvxjxrntrxmrnnvihofbqrbooptmlmwjdrstgzspzvynrnbdrqnwpmivbieh','rmclsawuejfnhwijvtquqbypchcaivgcwsilrtnjjsrpsdllrpljgbsjtmetgbrafwhfnodcynkeqsvilhpjvcgbbdqqcqhjhyteobmyslrqudpdpijmgrkqkatbxrazjoykzchwbbqbinhuskdevcyfapjuiultnklnqfbnzztncjkspiwps')
+;
+insert into t2(a,b) values ('kthguxytjyygprskeagkotjqtlahutpldkpjhhzjjzfcudggxnmgkvaqepzuyazifwczbqyaljldnyucacvzuewzihpnqyuirnvsabkakvaptoysvtiwwjtfzwscixikhvjcbtxhajhftwvzbnhaayptruftrev','ptmwiwfnerroihkwwgoumohehvpkrjbetpfdmbubdnrf')
+;
+insert into t2(a,b) values ('ifrytiewggtijhvgqlgbykftdifbdwrzhalyvzwvcixzipaaxxzmuyzwlrohpjjhwpftqiyeusmhbavmpdmlhslmhwusevgkbqwiduxmcckoyrnfirjfevprikfqfvzcibjtsfanhsscoywwolprocrrkxoaeekfzcomeerulgpgsvw','gvptsoiywnmyoqqwhgratceuuvogvyendbqojwlcddymdqydnveiruwifgwcwvankflzkwthwsmtugxtfuoqlqtaimnmbscilmhxtmubayvsnntclfkxocjeuujiykxctuvcihvuhmcrmobwijglyolbmaunttpsauucxgbjcliezqkwtqamh')
+;
+insert into t2(a,b) values ('plmjzofnzbotieanhlybnemwvvsumzqfblisiiqbmrmtjwzzdpausokwgrnavxybtqzhyujfmmownchbakoibfkpeozyhyqawylqigduoudvzufzieuvwhnhuqhezxxtbuukadxtcxxlheaghdvfscliyyqdsextzpgfaeckcyvbxfrwqpozclmbycizuzjwwtrvxpvwfbtdhmnyvxdbkdlylefitvdtmgvcmvbkbohulxx','neknllhlguwskqjdqskfaboyisgocqtmgolmqyzwss')
+;
+insert into t2(a,b) values ('ipkkwcjrscnbhupzionbcjazcy','uarbtzenwqnpvretiitoaybewomvlgdwoz')
+;
+insert into t2(a,b) values ('npebienioxe','yvplrkyotmbcgnalrbqcwjsyjxngghjeuoilqwxiyzepjfjzvudyiufanenwjphhebvkbkqaifuxaecqpetajwjvmazgncthtykukslecidpwxvxjutzbbhozvdzbioxdghfnzjhxunsrvaqpnydrwnhovppholsjhkhlahsbxsktktbksesztcbvtsujsekqoamutlnitatm')
+;
+insert into t2(a,b) values ('fsrdjkfhgdpzacckv','')
+;
+insert into t2(a,b) values ('inmwfsbykqplrpakwrsbsyqvzsouwqnwqkfnofjqeqzuqbtrpvvpxogucsfulznmjpkamkujaygnapqjijglaajpswvkwdbntwqkgnsmvmpnjzugsexubxhinxcpihlnwzblwqywyamgksoeitatocn','vucwcibfialzvgxdvgmbdhqvrjykpizrgfsxgiymkn')
+;
+insert into t2(a,b) values ('frytnfaacxihkaokmgavupr','hhotzmyhqeuekruibwumllrjvwiounvmezpagjpzsvxcqzruuqwbraatxgdociumaslptrzzyqmxcelxdnzopgmzjboerskoignaaaxzqndkcswgferjfbohwawnpnz')
+;
+insert into t2(a,b) values ('pedcidvjaqxvvkiqqvxenmpfehfsjtesysoxyjqnyspqfvyijvblhqotyvuilajldguxqudoefbhvrlvgtskdeuuyuvotpnpzlibcysylbsfbrmn','kehvjytvhmytzkrflawliitsfgbwdyoeaspcxcihyrvbsuqnziqigyojpqkewvkjvkthruicmpegfwouxusibucbvwbkdfleezmhgplsodplawvqalhrtwoqyptxgbjxyhvuweskpnqelkbgkrnmzxwjbcuvgqkaxofyohqmirbgazyzqjzkevuszdzatuqxmvbimmkrxulagljdpqowqipsvyldyremrnfqakultni')
+;
+insert into t2(a,b) values ('vpjikltlutohhczvjfvjchsipapjaecxhhvyuqgkmmdmpjufaosgzwufjcangbilpdjgjpyeyhkzjeiofmpntdfpxqxegydzrpvlpickdwogednfnnnpwcyobrlrqfxhpiavywkeccwheqclyvwsggqadetawlfhiwzmutmtgdjvnqhlahzdqolxufnjwzdmsyelvqqjv','mvemvfvolnpnymswlfqduitvjyygexrpfgulslblhyavsmbhepbzyujhzqeqjdhsaokwwvdicvqfoztsrioivmworkukxjtjlvitvovfyjxrkzpobgqgauchigiajrqdydqcavnrufvndugylvrwmaowgdgeizahssvpeocnflyfejqdlaxhaavlivtejcmhhrloqakilrzuijckypabsloxmcjpujlmljxzxttkiovrwwtgygigbitpv')
+;
+insert into t2(a,b) values ('oksuslrzdgcexxfyrvptdcowretpoccijxvhlndpvcrnxbsutylbooixtvehbybxrjx','tdqoxbbmejghtggkhdvuwtbjlelsrqokrvvgephhuieqpnlgbekqsrhhtjbwzekhllajrkeaxskuxjyejezehhaeorbntxaycmvyynomfazsomwwrvdzkvbuutxmdheusczzicvwclhstnxufaicakyctpxyydxevvnpxrlbykuhtmzylnbiqtaeqikaynkfvtofwoczbgbarrxyzqr')
+;
+insert into t2(a,b) values ('fjuhxtrzytdvpzwvpnxzukkdxrxphgnwctjqkgpntxsmaocbyqktxpkyybuawaivdiymprexjuetfcqikuqnrinuxfalhwbrpadrslzhfxfywxfpjkqtsrhlqmtsqenvfqiupblklthz','gvayhtvfwazsutujjtcnjwdjmwbmgjnopeyhiouluokhzxqhsvghrzvdmvgdnwlecudjzrsegiypmtzstvxyacmgvdgpzzecbpoyklfgyctajwokciiicukyswycxiekfaauuojqkbmwquaxpqnbfqnamdvudvjionwpqbkbzlkckgxiqwplijdhtdbujlbjibukvigtdhcsgwadvcpqiguzxyrjcbdyevxcbkhiavnbbxwkx')
+;
+insert into t2(a,b) values ('qkehnytxwpqphuqurpntnmmhazyymdbmaspyegidlxzltfveudjvkgbmaxjtyh','urwclwwmzvexqthxyhtkbyokmgtqqptvoebfijxzcaxyltutnithzbmrtxugpfdrnhrkmbcvepotxpcazopshpdffbqwmqhvywykawyedtojjwthhjpniivpsiblxaumkgqqfxkumfoeywg')
+;
+insert into t2(a,b) values ('tqtzppxgtquhzzhiqxveyqipudqeejzkmzaaqvlzsojgvnehjmjwmsnwhndyyiklrkeorvqurmqkvuiidpxjerxyegajzopkhaflmwofdsdknvtlnblhgntjreqdsdifhkavtfsyvmmjwijlahprpvfktbqllgqdbwylfncgsg','kpmujmagrcdbjlfztdlbrnbaxewpivtfkfszwcnystqgtwegryfqasdl')
+;
+insert into t2(a,b) values ('xvgkkmqpjtanovwdmlwylnqkrfslzibatslaybviqktrjsiqkxdfqdrdlozcqgemdutvdzevhrrmiusgczwxxxwderxtphvfcftpoxwucqcoijqnrfxvxwokwozzrmfliqenziltbvwfncvcldlbztrdyblzmehzpggxzx','omqkooqtwqejpgsoinlvybpblfubjgjamtbwqqudfksvrsmazfzyphmzkpiskolmpvwgdgbhbwxsfmtzubfiyrbmqurhiykobldsftzpaasjszdihikalhoqcaqremdkccokvvcdvsazxvgbucaidrcigoharpquudwjqmfgmujkmsjipexyfdiwzaismpvgmbshbfnmqtdveijgefwlghyaeproykdowuxgztepmvfxjjmfmkxtwqwbtsd')
+;
+insert into t2(a,b) values ('cbkxsovclddymiljucaqvkczhthyhbsimvvlrazcusgjqsmwxxyfxhppesdmfcyvvzovfftduruypqgxuygpjchigtbtmituu','ovaihhiezssbedryygblvicnbiuqrgpbklrtlkrohdzwjxdkeghqdfnhpbdvurmozuqztlrglhdasxahxozltvfccvyhkdnhhavzgoamjafwsbqsawhugcjremqtcfksqopmxdjdpqfbogfhqqnaovrcy')
+;
+insert into t2(a,b) values ('hhycwjvdrlvdsytqazldrjnqxpylsjswbghthvqajohgkgeqnqclkhdakzwzdiuqdvkboupnterqsshvafzzcxjlipzuviklavmsufyinxzbvnlzhaekjwawmiksitnmqkupeovwxuatzrgzfieevyxrwpkpuzlufjfkkxokehhrvylrpvfpkbwjwzpswklgitqbuumgztvzfhjatocpqafsdmtxahhhxeokqqqtoeuznwsqwqoynbsy','n')
+;
+insert into t2(a,b) values ('fuocvspqkgrdksfvbfzrjiifqhcojbzgiqlhevodiugpabclqrohkkthjpxpccqduxrnpmpohjvvihzbculjlttdgciazizdlzqxjecdayriqwmtyldwxuwtesczvgxaynfkqrcmbkkvzsubhzbmwjitcoelhhqdzxzljlzvfmdkkipdeediakyltpcf','aqpuzzpguaamvgtgoefxqmjxwcnyjadzipnbewegtnfaporwjzrcrwnyaypezxiuncoadeehxnlzbdroqfzuagsbfjczdgyoyyw')
+;
+insert into t2(a,b) values ('sysrnuzvyyimneklgtflzyizymyvelrimmtyvhcdmqhpjoshijjxronenvusfm','vsthqajivxujqrhqnxlymicsberaccdfthaylffkqsrysverbxxrlcogqsuwhuksbqrzcxrhefboeeuyqgobiundyfpzinclzxbfbnrjvbuvqyzgbwqiujzzmgugjnemarjngbfcgquokmyxrpetfwlinnzqylgfepvcuxicnicjrovwesseuodoipchaswrcukjrvg')
+;
+insert into t2(a,b) values ('rpnmykgeipxgguijcllicpftlpnemarpypzcdadolieqjmvgbodzcjdbaeutxoqkqzgkecxnvyasaqbjwyhxzoxgmqtnt','frymswrcuodsgabtyfypduhmdsinovdafwtisvxxpvdpigpwyeqnkklmdgoyssuntqvzrvvnfjnlzqxlloreqfunelmbssntmfmnnbfjbeylfrnjivsyxsuoppjvdodhgmjxgzjrogorxfwcnyhsvciepshabybilccdwznumlywnwehvmigfuhbecgjgzpeejaokazjjrbmsfanfemneotwvdlfxrwaumqbnedcmo')
+;
+insert into t2(a,b) values ('uduozdgyhofgrkpiqxgeabcekexpyxagpbwvlsztjjvjapglkvhuidwqljaeureahusdiqkiimlihdbmvsdemrxozfmdxkwbqlbihmugpfpqgqikhwrmiruiatmaurotqpyrouvbwteatkkjpmpcnnneqviwrqzijmkbiljrmedsmuzpraipqcapnehsfynasmasxpsmhlcvjflxpuhtkznzoufwjisyeddqupkkpwcmmmucimtfodgmawm','ocphetvonzkktinlzzkuhzywynkqmbsimotpzxnswduayyyhgsxtjggsuoakftmlpuoqwm')
+;
+insert into t2(a,b) values ('cjsetvbduabqucjssdzpfbwlqyxjiqjvzdtfomfrxicwlvcacbevmrhhgdwusbqqmplcxskiraxjjmxetkwizbjwqakfahfhappnbqnygnuskvsdgcwlxzxgtjmevosixeqoqjvrgifewodctsezucjmkuduowbajgewcpkihprlplmzndjcvivhdstnhkwuhhdomgixmdfavttvpmjferzgklrbkutjoqis','swxfbcgnsepjwfdghutjvqgs')
+;
+insert into t2(a,b) values ('tjlaordkqobedjnguyxlsixawyhejnlbnpfqsoylhvfytpomudglcuakdcvczmjvbrhcfddegxqdyttyesddvhnxphxmrxywjgzkdgvzjuwivmhmnjdtxpxfssbwjzsygkrdoxxkwuyfhuksnjhqgvbr','oncgudokjvsudbddabqdgoqziipfbafrnxsikeuajogmvglzqwzdtzrnthgaqivqzemcubobzwjrrnxvslviqffywfswngsavkcfctyxehzhqtntjwxqzfkfzxetpafmpinluukflqxtshrebtbleupxddizslluazkgclxulloviozdtwkuvyemfhqlttyhkizjavervigdogaorrqwegwnabbqrlgwypukumpvrzbskohomxzoj')
+;
+insert into t2(a,b) values ('ivoekzbwznibqdkunrnnokvakwghuvsifvkpyidfhddjlrivljmufdhzkwksonsixitpmvzukp','vigdpwetvwqc')
+;
+insert into t2(a,b) values ('rasanwxryakarphwqclvtdqdfhhsxncsjluysdrmzmsmundxkegxgrboxlvalhxdrjqjqydhxqgfrgsijozcagigeshykiimjkxgpjmkixtyqoyjkuvdkbohwixzympvorzflkcnhyiqvhqts','zjbqedvlitddolywbdzufnsefhzhxpkslromafkuldajdvkoqmdpafdxvdyolyathgfmbmbsilrnxenqfdeioeatpkjftfpreiegvfofsjvgmbpgnswmosfotrnswunbuxfkvanlnlsurxntcbhfohjaxnawtxsrhbpmmcfknvfvngmayss')
+;
+insert into t2(a,b) values ('csvsigwshbnmicsqodsrzkyjjxogsiblrblqfvdoowrfrunbxdbwizrzmqlcsbjcozzzpvfaabybaobcsbymqvokvuayyiafnwaugfnsnwymhrqtrnqqkfzjwewpaqmicbufieahleulmnmbnlqnydewcuikjermamkcllyynqlfdjbikovzncgvjhfzynrivcrtehiddsskwxjhtmjgrqpjz','cvoudlfgkbckjcpwfffqqivoxsivekpdspjmpgxc')
+;
+insert into t2(a,b) values ('avziicqxrcdrzdoywjiywwrkiozzeogmmuetvaxsqobexhecpcssgdxdpjtutwqxsalenrgzkfhdahxdoyrjnkogqcqxpyecljkjqjpdsfcbiavzagcazzxogbqqmnwrjwmxtafhidnjpgzwsycahccgytmyqqgyvwtwdxgllnvpksluvpiutkpwqhpudbmzozxteiikqccgjgjvgrezeuuxrjbduueolxdjbiqmcyailiyi','wjalsshbanfvffeyfhhcbapgspvtjkeubcaiowulahns')
+;
+insert into t2(a,b) values ('qcfpnslucyvflhjufkaikpcawbjowwemsvyabvgqfuxnwoilbblcvjqpyvgagagrudsgyrxhesnbtxputjsmidfjqaxqeqzalzkvirgvotwxfgdwcdponrqjmsqknyvivgqbgtjcgkxpo','pwjqyoqqakfzfboieikoqgpydumuasjdqqpshjkhqxlvirrlgchblucyjachkxdjiuyxogcnretydmziafxjxfwgaegeeofovqhhbnvxgopuv')
+;
+insert into t2(a,b) values ('xgyjcikgapveolysoqwlsnshyustlleytubkwpjdggrnaqryoxozrmwuutitvwuymisiomgpqdcbtzyymdorlewlkiaaknzayyjxafluxaulpvfevvbtnctsvunhzorvgbba','oyebazpuwmepsplykz')
+;
+insert into t2(a,b) values ('owxqonbyifxouglydukwramixzkpehazdpmkollajherfjyiimfgnwxskszbtthalickpmllpavrkpzlrdjmxnoxzpzxifgbngfseqezgdhmwdxaegdvbutcsbmnvbrmxt','lybtayhspedemrrwoidjjnzcnfrcailiplkkcptqfgvcposkblzzqnldriqjnmbmtouulkingbjrewfibyimoawtswnelpusziqmidrnaqifkwscelondcnpsqjmywldhgfkiodcrwljjbkjfjpuqafzafezexyzxojthsojx')
+;
+insert into t2(a,b) values ('ezhxmsjrjlpgjokduaiflghfazasljzozgmzimymscrimgikchcqzcmqnvtaxgarkajh','crhjumdpdfhgqcokpybwavumxnsfjwktdyvjzzlcfqzqiedmnsyeiyvzjnkcdphncxbuqnxvzzbewnvheawwifjuejofquwxdabxmdbkltxssiwofacptsbpjtdyfsrmvteshjlaj')
+;
+insert into t2(a,b) values ('rdugawllchzgvxxsuqhantrlpbeoejcxuqwaxecyzyttphdfawuvbxjhmjmppowomwhf','cgsdoaicyvauahiodujuyrxkdzyskgazruecbzaumtjntamfpvlhqvfhrbypnpprsrvfgwocjndpyxugnkbdvrctjcxiotixijqymfyqgorpgjgpkygfpzbqxgtajzihrlumxkmuugsfksumnlqswjwiqheuchg')
+;
+insert into t2(a,b) values ('urzpfkmbjeuqnkbwuhdsoahzidhmsygwehksofztdoxcmmmheyvgcuorylukatqxksuhxg','ajbsadxds')
+;
+insert into t2(a,b) values ('acsoiudieekidilsarckhressfqyyrfmocmacuvzfpqsnwhtkbjwgyqrrxnioklswctcthjbjbcrnxgmhplvgrdlhqhdrvnziakxvjkycprnqmrsewmgihvpqrqelhzqmkfvbvcfmblexzvlybzsdpnrvqabifnledsxciaiesvzubmbqomvhrtfkm','aicgnugeeoumkenpmidjljpjdqwvinyqibhexvwqmvnacqalcdgebrqnumlmtoldnkknmkwemphojszeivgutnimjcbtzojltkbdcysuwbwjvczyjaldfgbkvrudwbeszcrrwktuhfgrvmgeajnvjpftjsmc')
+;
+insert into t2(a,b) values ('cnjbxmwyyoeaugcicbwivxfcqunracgatobrzhdrowsenjrvea','doorcalenbbepkapnezwq')
+;
+insert into t2(a,b) values ('bhsyuuyvglhojxseyyadu','ixanjzyslevpbbrrimgtndtrwlncmqhtfvpzlpnedufbqqbuhxqhzaduiuutotgvjqthrodcuglqhorhrzlxperigmlmputwscapdhekcaniaaohcuphfvjqhsxggjtcodyaquhdxkpzwispmxafnopajxihchfkxydywhgioulfgksmc')
+;
+insert into t2(a,b) values ('rxqinkmahkxovsojseirnividlskwasffqepuobpndywy','azftgtmovscrfdslugazhwawvwbpfxlzsawpxkwljwwxveebdpdygtreesomofbisugrspgvykfqfrsyybjdfwwfsucwgdtacpyngvzlhkyupdfifixfjynkzlxucrucpxedneiqcpqkwjzfpfxqnfbgpcamvgyg')
+;
+insert into t2(a,b) values ('kmfhnprsjyvxgtctukfakneiifzcnnfdtwenqxouhofinswkhicsuifvkcmvduxvpizqaqkajyayyqvrhrwyhbjuzvflrzkmpiwqflvqxpxcm','yqoiyerzdqitzcjvdpsifwlvxtoeibsxegoqogjywgevlizuxhujwqrkmlybrancltnyiykftlerqrtrywfzdfjqfznoojgizlfyddccgwqokuzxllxkfgauraiztvhpexxrchmhyzqzwdjuo')
+;
+insert into t2(a,b) values ('rznhncakxyppzfnfxlnijzwsxytuwpjnrgbdihddltxycoustjeysgnbqfmnmsvaufpmwbjdziqklpqlveathcnghh','pdzwo')
+;
+insert into t2(a,b) values ('xoiizkaojypbonirecyoywebvloldarzkficnjrqgfucvdbvdehhusiwvhhwtdicgaoftntmrhzwncikpakwkeswonkdfdycvurmkpvsehrexhkwywwfqzouwffgrlphsejnbbjxisjegsrebncrfbtpzuxijiqwwidymtstrnqzunatnkdiycrnjzzbrcnhxfdpxbegqigdndmhtqmwnnymolkjfpcqgemopqjraflmytvfjmmiasyrhey','mxbzxvkvdiwoofjhfsamjpuxdqkiipvggrwmcpgbjxqfhcwwhwvgqdxbctfejsstfinnqqwdeouixnxopbfwbseiakhqffdmcyqfublaatwrapewixqahnlckhhyksjrgwducuhvsfqximwvzlkggcdjzbrcyvpobnyksiyxroyjfravupvwkqxqhrxcuuqwxefemzbeqfkagvngesezedfzfskmokayiyufthiuaulbygkxo')
+;
+insert into t2(a,b) values ('hewafiuyslmrgbfuygentmxhvyocjkyseepammtcisnmdnaulkiiuysrwnindajiwwyyjwbpwxfpaismtmzwlpnjabnnlzxerknqmqzdjsctgklrawsikupdywdavdsscpuknxswebwjjygmvnqbhymnseshtxuwllhtfsxusvoaipbkhjexmuhxvuxcsjmcsqwohuuseqwpuadikylzpetmcjmcnjndmavrmxjyvijcpxlqgvxcwcfmr','irfwoncvvtplrfcyyeekjdfqfjeqswstenneqsnvqhffndyrhpkgdwgpfblbizqeuwjydndqoyeljlozimvyhsfwxqszybykvjqnccghhwcuvbzmcvlkczetjemoixcpbpjegpmjunhbdwvstkferqftghewnomegojthrarl')
+;
+insert into t2(a,b) values ('thnvulvfmntvrhilxwffvhruqnywgtinlowdqosnjcvajezkqenzrrovlnaonukmqmy','nrvnmlpnnrqouxaaixqpsqibepzcuimcavfvperqgrcqkhksrxffnbxutwqqfkhhsua')
+;
+insert into t2(a,b) values ('yncljzdhtlmnlhiwtrbkkomecvsgutikvbdpqrgeqbliknadkpncecjtqthhzsyqssxtqzhrxadsckzfafdhbwiakuusxlcwldalqqpoibispoekrovoradtfjqgoyzqleowlnxyfdctkvtgtxframtqzofjwhtmfyfmisjygvvxzpsicbnrplbijkbreirehjezaokychlvmmlzcrgqgrzsqifkjnpbswflpobxpkwxifqnrqugyx','fgigulexzpnjbkltoek')
+;
+insert into t2(a,b) values ('lrqxhjkngdwumnyccnzzekauifepeoyhvfylxxjfkloybxpgobiekfvwhjvhbmuhduabtszukpniwhktpcgibazublobmjxkgkmibsoxmhfwzbpvplwkimccdivtijdgyyrutougfihgmboiahzervbtyujwzsyeqofgkvecibufkzzznhccufa','awqwzuqmnvxxpnbicwlitdpapkawvqhiphbzdjinqguowcfyhgbguiqeryvpjjqfnnwzpfxrxqkvyipbmkuscjudylwacloghlqmcqzozytervyubdccrigodavsmoqeijhntjxviadxszpdbohqndppmkzshivrdbosbxqdiojyqaeyhoagtgimucycwhmeoerjrizilbvi')
+;
+insert into t2(a,b) values ('pweikjhahasoyknzqors','hcwdcnzzhlywhpjrzevwvqdjgpqzwsucvrvsymibwiskunvtlcepztsfekjfqrg')
+;
+insert into t2(a,b) values ('dgklvlyrznqwgldqbwygicwelypwvprtpovewdtmqypxaqcsfklnwsixquwdahrbhfztjeyqdqgemkfkwgbgghuxzwavbtrpfyrpuicopcejumyofyhthronurxqrpuwwgeoqdlcpggwoflzlvbddh','bdkekuhmkmqggvpyubqmwfoxfmsaethxodbuwtplvltuoxntkedcuzmggygnpanunlrlzrozevutcqctoeihnwmniltxkilibrhdpwmctjsglxrgurdrrqnwgiwgzdszpjmawjppppfmpoakxslhqekxzaxcmbibaadxopmrujhtbyhnntxjmbbqlthiapzuvhyhaofahmmbvztdehlxsbqdbplhbzisekhdkcgwxlvxbtqksvqwyy')
+;
+insert into t2(a,b) values ('anvslufkkbxdekpfdweyxqehhktdq','dxixipekyfydzpeemrlcwlreylkykvvrndnemzfymhvgnetncxmrzkzrvudzfmyjlmwnxzyziaggvuaaftxzszpyiisjwdkmdvxnlwiubtvmamebzdnktngppiodmovehnxdmyhaaesliacpdkcbdvn')
+;
+insert into t2(a,b) values ('wmphmulpepioltkaqfpvasvgwgapomticyocjpurbxnrgeoawcbwiqaefbfqas','nlovwwlrwegjffykwzskcztjrsereohuajsznjqmrtjpynaaqcmrytmisizalumszcpfegffoxlottamtfykgkzdykvhxapbiijossqaycbsfyrsiqrzjgiclqfswtwfwturuxzfw')
+;
+insert into t2(a,b) values ('swiwgnwmfntoerxtclphcyluxsquzuexswtajwxljmpzasgwdxlpjfjknxnfxo','qwjkeieyaifgcnwyvqsfvinzqxkvunhphppnbsotyjursdutoxglyivlxnucaenkuohyfyvhhjxtqmowlrycpurdxaxsgrsyczjllcvmcgnfdpwclxjufztqzenjskdqvqzicpldessyutzhpulpzfaarbuuaqulonujwgvrumswnahthseecjijgwjzmjwedcwbsqxeoudrdcyhvfapl')
+;
+insert into t2(a,b) values ('qljfneoreelwqgddwwphuhizjrvquixwssdtrtofkjnwfozdrxcdpmrslsrdmyhkwpboxjdqvcgyalieabamvvhtq','vqumqjwxwctldlfxcwtgklnirvmzgxsswvxqqigmedwmnikogtlonxghqnqagakpbouwelfvjzroyarqmrzkidmvuythnwxeeivzjuqvdamccr')
+;
+insert into t2(a,b) values ('eizkkjvlugruvkbkfyjizrpmeandwdbuwscssffxrmpngtbuiuzoiharrccizcnkypkghtnoxxuxhlcmkkncwusetggvhzqfymefhzmnxyheeictkvyxqbbmrckfjwbxxrvocwtwgczsvqbzjieesegpvsmabgtiuasqfvunpvqkfqmpuj','dsrlozcfbvqfoagwigczudokbxwwbxfiinvgapzqqxvqyig')
+;
+insert into t2(a,b) values ('hxbnzoeuyqsgtxijqyppbqjwxaakzqqjiklwosevrwvtdgneeatqjguirtltcqwassnfnqvlmfmpoleqmydchdkbmtcsnwplecubbidsxitwgirfohlfnbyvvdcjciauketeskpglfbbjltjrnhfpmzfaiznmopqjvixokfgnmmelwjlsgodsddwijypzmxeqvsktszbjsoxxlguzhmmlxpewhfvxqdgut','qvohllmpgivavtnrfhkcyifksggxqpeoxgtyyvphofazmedkvcitjuhnrenvnwyyqkwjxphvwtldomapstpyvptvylqweuotlibduhntcczowxmmppulrgitoejkdnsqielyfdxzgpruejzivlymzkxdmaxbmhgwthkatpzuhruhoqnnzlodzowcxrorkfonqcriklvmcufbifawqgdxdodftoyiwpouhhsaikqwjhc')
+;
+insert into t2(a,b) values ('ecmkiapzijdaexuabejncdtyqnktyfxpqquplccwtdxivbrjv','alqjtdjbgsrkqwfatcqzjnikbjkmymbxlhjspfymapddraujyxxdhuunqgfboqpwczzgiuyyspkbrjqrqvbjxfnnwhnjndldnhlolafgdfazglcyaryqvzmdebrmlfpktbxtbdaejhagjtvzvqu')
+;
+insert into t2(a,b) values ('obnpudskjmtsjveletxuoaebndkpgmjjoprzgoppkscajfbfdqhsnzinhakjyexcgxqdyvavktgcacudybvledwutwznpfqdyycqwijrbhnoqjhoiekjprxzqruwtclexkyepucttcbgblxjeiihyukjwhwldzzkzgsnwbthhehvrgieejrmasnmdlochobqmenkhnnlqmexb','sbujftytwpujxnefkiphsgemhujadciovlqtjbjkgvbakfyoazpwdihsubwhrzghxtfwhzdmowddwpxrqybatczclucxrpomnbfjgwefaoxvbcjwtzzrajysczoesujadmdgttycgcrzutcjtledfxqycczxztzcxygxtlviujwsylbraectbsnplbqeu')
+;
+insert into t2(a,b) values ('qwzbdddsmiytucpbbmnakbnophbxdawabgqspsajgkgqksskqylvkzcizygkybsiuwkcbelewwmoamxxvqoamibwrnvsxvyrpsbtqdgisezttglwoakjryqmyrxsnlrgeunfapehtdhyjpczmfppcddx','mvnyaiiosqmpdqbefjziofkwcknvnwlhildtbbgvttvjuomwordvjtfqpceshxxelztrdiabzaatczhxemxfizvjjhswwukmtfflkvquudzpeorajoqstegardqawgcuchqzxrrjhkxglphyfxpzfitynmmsavkofhfginqodakjmitcdqvyzarkfiiuxfvfupwggbrgzwaehaiibfvldxrbrntqrajxdyngtdivkasvugnbnytjpfzndxrt')
+;
+insert into t2(a,b) values ('kpwudewdlkeeenvtcyroihzjqykoskztjyexmhnxvqcaahlkkmzubzbrbtadjwrbgqbkjejunkdoesrgctfmglixrxrnlfjwlkjcadrtprpkfzmzagcuwupywbfthimazsbeiqfgczwrlwrezbqlorrcajwxhsvwgicpaotrxdwgsihpqushut','srwlrvlcvyyrarmisxcsmdgpkimirrbszdrpxyztjzteuxcwofppknykiytazatzrydawlqihpjbxvkmj')
+;
+insert into t2(a,b) values ('skzwxfgenomrvwmnambkqrgtuoqxnskhwnjsdkxptthjtpwzkizmgqr','hfrhkjrowrwuvybwilouueibeygqugjqvslinmmqptpwsxlcpvjiiuzcikdljjnb')
+;
+insert into t2(a,b) values ('zoeqbfzunxooqqtvtrxkpraxggqrwbfveqkodfqocttmgsmqpbpgcurbmydmmogxplnxdpmyqkbithqiixeknpdmwqyvoxjokjaqusbmabsdkidjvuncafpgnvuqshupviwkxvqvsgmasl','ndjhwiqykrkeydvqsxglsdcjtyndwnqstqybdffhtdanhaolgsmmzzyitepxzcshdkozwvhkmpcruomiljgofyucubzqzhpwtgzynrrofxnhepgpazsgdzrehwrxcskngznkmdfqdayxzhtmqshgiygbhsrnexqhxkfriscgguslnujdetdblivuoexafsbxjftsryhkkdeqysdumfjdfrpbzkoshrgqh')
+;
+insert into t2(a,b) values ('xdxcoaarkwpzxcsmaeybqwirfsbgncyjveeudcoadreloqtzndagygjpnkhygxaozhtkzcgytlioyvmfbdpbrucmjxgathoslhasbxtdysrpwiqywalzwykmpgrohgovkdniuwbvbxumbqkymqllyajgloflbzumabbjizsztfopkjdfmiryafjgdveacydmyatfxvtvubptcpkiwr','bhyzlgiweuusolqwpgmutxldqvcjuimtfrtermmbqjeycjgkzvsistrrmanaksmxainic')
+;
+insert into t2(a,b) values ('yijyhknpsjldpzulmddixuhsafyacbzkzltusivldzlyitaxghagswnbonzlpalcilurbrwtaiutaypmmukhzbsbapiydqchxygantnjsjeijlrekmgewswfsuwfzstwyecqbqisezajgixsrsgnnwrkoovhcelvkoiwummgujmmzdwczbmcvkzdwlhhrckqbsruaaulofpchwuabommqaqhovxgkzwykhefustpocilljzvkasryvwhiwm','octovzdblephydecjymzqkbaqoztdsewrxtwxemcvnmjyhdryeicfhf')
+;
+insert into t2(a,b) values ('gssyxzzqimdlftfzmexfamrvpshfcqzslnhnkahossgjyisrbaltnfzpkkisjismcdcgwpzpafuznwwqaxinvdidpfejpyvxrlgrkztqffykbztuimkupdbhagulqeazwimepjhxdbdehzzqyfnktprvtyblluqxrwexjziypwhjbbbkykpmxbo','pknidlqeuznagafxybyylgoxknhqivgmodqgbztzzicmnslpzrnkfuopqvjlpchrzshseyxblfwonkigwalxereweloyzansykunmpzvyhffrditgialgnbyxxwxmpphztpgevkprgqoiioorgqlazxgyrmjvsguheqrqjhbrytjgqesliqcrkphszgra')
+;
+insert into t2(a,b) values ('wzeaccwnfbexhxuniiqkqyagvzsjagrzwpzcioigcgszstiuttagbjwcitsdxufpqxstfvqxdtexweafvyyqtwcsllrxlridanebuocwgvemdbndulyhfukoakhhfuqjyrclnkigeyvbvdxxcmvscobszirvfckiaprelkcuztpamazdjfyrjnasvxxhmmoxrdujzulnxggcrpkjmusuaerknjqqtpcvbqpkcdviexlhnw','biyombafmzosgtsswsxfbdajltjecqekzmpwyclkqfrmkyzftiotoso')
+;
+insert into t2(a,b) values ('bwlrbsfqxfyw','qpkwfegjofejrmmpwawmkubtucvtupuhtycswipnltvfd')
+;
+insert into t2(a,b) values ('hhappevhnhzmupfxzzgtvpgoawdycwpcwdcfkzqmbvhczyhhxekiukyzdgwnfqoamvkcocwf','dphtprmthrqapsaecofdnbxptxxeffqwrtoplsgufdqtebvcvdqmccqjugecnwwskfmdzzyjtvaggesisiwrgankmsrmyjfbjnyekbcyxfnobubastjwxzyvkbdhuiguynptzbaalbepgyavxmhgkxzhxubxfbraxbuatvcjkrtfcnamdxeqmxvpnekhmdjbedsdcerlmcxrqblxrmhouugcwjsuazejorenrwvxrwtaazxcdkvwa')
+;
+insert into t2(a,b) values ('pnobxgkbqqztxduywltsbsocivytygrjdelxitpkuhsvlrzxcfwykrtgjzemvnmmrwgjvcmtsmovdcgvclavjrvsfzwufjiimgryqypuduhwyxqxnhiijvtmpnyfpshfctzbrzvtzjgqeqzxmyweeslukprczdngwfxbgnsynhmiphgnskvdivjzjafcoxjcncjvvhcvsetwfdxtwbiehbaaatmbbifqipuyiespnwkdogcxgu','swuvyxjhrbdhgorjbpqwqhzdnosmwtfiyrphgfjivsnyqvrauyhbrybaoxdfgplwgfpblvdlfgsacawgdjnozmziezwzvbwsejgauzveqx')
+;
+insert into t2(a,b) values ('srhtstdldwelsimrevbqhgzxoyybsfqtnerabpuxhkrhofpgrlpkgigsmwdqekoajaesuvjztygeoztxczqknysbxxvypjhbgopuylgwjodmusdnc','bsaqbmzixiwstacblfmlkpugfqcsatiyqoxvztocavbcklypreqtxffmxkszwsmdfmxpvmbujftmwcwaaibxgvdqikasmzbomytgosmxtbxajaalrpzpdegqrukezibehuxcxbsxfpnfrjjgnvwtzwqcjluwzviefcol')
+;
+insert into t2(a,b) values ('faauknaanklrldsnenlstgxttimgmagacexwulpuzqvdfegmydfmhwbyxtlbmygpkdgccawxvkribadlhpvsshdrgnqdtslsvafaepxojwmrqixhiatcgcvrjtmwqczxgvqqndkrsgftuwqwquecwcmhbeuqtaosdfqvdaszcohyvtpdpluxvvczfzumlpwhvegtzpebuavtnwrbtjubjigmyzowmvivfiqellxczwyroqgrzyfzzptzgwwrih','cahqqzsajfdkdozsqmpetlzlzfvmqsteykxmgccsptzqgbevnanzjzpsdarcrlqqmcdxstzhomzvhvxzuyolfhmwgoscyiqipsxzomurnsdyyrhbjcpiivjyzgqgsjfccnqbmoogyhbscgcdidudlmwcxwxtyehuvrqdpyrqelrjrwtjooefmhokufnvfudlwfsqhmjiciktxobdztdvnwytzgrxurfaqfrocufqsjpvjcptpc')
+;
+insert into t2(a,b) values ('kruxnclorspsytugnnvgcjoxnaipebdhzgxaxncdxsepcnkankolyddvmihhkshgnpnikbksjvandebbkzx','mrtjdarieoyfzubyqetyuqtxrndzqjhpsjwuwkmowmvwjhomwmchuizspjzbervirohfrx')
+;
+insert into t2(a,b) values ('vkkpszpbqkzvsiggqippictgjhwgafjygvcbnakhszkiwfroeqpwohdwfufmfzvgtwsdzpsfaucpfnhhydwuaefceadlgqqsgwxcutniererxsoahjfhihvyfoxkskwgzuzeeephbeevn','beddsvdgsrehvvqnklbjnftdpodmxykkvwkyfltflzbfwenyruptnfohfangrjlalhjpynlitejbqsgdcjvailktaoydbikwcpveyvblywklnoxbtozakjcxpyvzpengilfliazzyfvlqzbuyo')
+;
+insert into t2(a,b) values ('ydngolfajgrohrygtnnjqrzytrmwmcippnmcczbblofwehpiegmjdcguxeoixepcqjcufkytvzffksfzlgjkmetvmzbbubwtqflu','rdozvygnashykidqjvusummqiixmvtnoetqdvtpdjbnwzyyigdpbzehmgqpwvxbcdkjmvcxzhyapswpmeuuwnveafptqulaycrysxllpwprvhxndbrqwxandqsosszjjuiahftgsvgfshsvhanlacrdwmdqdqgsgukqxicuzpyttzfrg')
+;
+insert into t2(a,b) values ('udlddoklbssbarwfhkfmnunhjwnxaqjakcxhtmaeigazcokkvpwfrxryrwgdclzxrflshpjkyelszcrmwgjtusbzplolxysfehhjlsepeokfzcpkzzvewryyowkvbqpzezbeydchxprowdfgawfkkypwqwwzfzvryaxmmswyrgitv','czxiiqhclvumndmlbyhonhkwxzeaecgjjpkasrafzabtfqidqilvbdvfsokzlnlkbxtiowitpxdvmprujrcjjapqxhkho')
+;
+insert into t2(a,b) values ('ftsifwpkwkqqyuqjntxkugoubiozxxidmsqztrmkolqnrhsoqymrdihnc','bhqdqspdqotkhszwovkltbsgwhuttfftqidlmyllijlewobkrhxyqgqyrugrpknygeabclzwgmpyzmikcdbhrnwcueimapmirkltrspmoalkgdgiqgqoilydbnndtemwcvwxitnfinaomwldzrirkzgerhrxgzetbgbxhvmwjuuvrdbwacsuexgygvmexkhsiixhplrfzrlbqmeaivuqhghmglcqmudetucbhr')
+;
+insert into t2(a,b) values ('invvxtuejggriuvqc','qexwomauniyzsmkpobcgefcoknoglixykiajzxwqifzenalddtcirrmxewbxccysbyaapshswowngtdjnbefpoqbnosadtuigkcrybqozgslrqytnlttclgozpmryguvmzouavvjpjcxbdfikzjqjyoaimkecvwprnsypemrqupoaetpqkjvahuhldcwtuczpmxj')
+;
+insert into t2(a,b) values ('cklbfnuupdjxcvfxeikibucmwoanmescrxiwusymrmostxsabikumdruikaevtddyqhlkpjqbmmfxctzrfevbfmmithmkljoocbmlymnzga','pteuqiqxowgb')
+;
+insert into t2(a,b) values ('uvufcbqqwvuwdgslojysfwrypbwbefvgomyuapphjycnhvkcxlbpbspchminvxomxhwgmihguxmfogvwgeasfpwtuuqfcqbirhwvadyppkojmuifowrveuntsmkkty','dwvzitstwdxxakwhahutkymwzbryascsewsainntwmntvvkpfqxvdirybznvrzknnaivxjjxthusfdmoppwkeqbolimjtsnmqjegzopangrfozslvcomvquuhenjkbdavlmpwkzdeurkgwsmbtyfiaizgbwlbmgwyndszxsvckbbrasbjvfhoslmnsuvwwg')
+;
+insert into t2(a,b) values ('sitdsnsaamkumibexbdlqagwjcbvpajgkctyjcrihcweffwnlwtnpdnemjliimnnatfluzdewqsruwsiscsqcjxcncejbjzlqaytzjcqctxavqjupieduqndksxlixcrhblvrfupbvmatqikgchfdtpnrjdifbiwxpybjoimnlihstfunpois','syuyjktazayizgynncjozbvnlxbrbaqllaofnbmydenjwfgjwqcoilllcvc')
+;
+insert into t2(a,b) values ('eadwfgsxsedajsyszfspqdibakrofqejoqfpjefbalwudvnpokzyubwfvjoskhmxkirkxmpbthmcbiigiziyxnwocybhqbdcpyrjspejnecvxwlcpudbgtcxygdkxw','tvfqwggdqxcmcbqcxemrplpnetlhgwuijuzavzvauzavlzysmhihbdaakuwmmscwdbxwyexmlgmiyduztripwsktotcjegbzttwlvyuyirugvxegequpcldhxvsamuzinknxvvwjfqfxclnxpqcdimpwukfgnqvwqytucvlsjbwmkcdpsmjdxkuafnsdergryvyporhpguygasjvlyvftb')
+;
+insert into t2(a,b) values ('vdtqrevdogsqxcxukvipazsemrkkwxytbatndzwlxpmkyzequqyadpfhmetjbtarbheqfeci','mlrsyctqifavstzgcdnzsqmbuztiwwpiabfkcusgsmexnfjthviuqjynanvitmkyppnapnlgynfovwzgowasdzocvdaquaguzjowjnagsycpvmusdroevywsqtivujeoughvmcjarvtkhseaxcqpgvskedbqlleniznvelpszfvrgcxqfqdbmmfjwvvyygszwsmjyhdktufpctenybemyfrdwvwxybzpgantuimwudfulz')
+;
+insert into t2(a,b) values ('ykrrfxwwlzmlldwzawgvgspdjstspfkcshagbgfxckvgezbtmznxzyaizwkgjkvdrhhifoiknjvloxeehdwxebepnhwvxqymnvkcxjlcanhaljjisbulotlzgqcbpnhsmccgpfyohierxbtlmmtpuomnetakpxdinsuyjlxppolctxgezzwjjhoybrftubsgkonxhjdnvzvbe','mvp')
+;
+insert into t2(a,b) values ('usfkg','xrljctsmxxewc')
+;
+insert into t2(a,b) values ('nslvbwlyxddywgcqs','btqsuljsrjcguyggxyukdzhfiboieqdgcbaewabelocebileukrpycevmyksrzoecnjedfdscyxdltbixmlofcgzbqmhzirrsrhidnxpmkjamynbpqhxwpopgvffuwvqqlnmigtsgehqqsfopsxmfmjcynjmswgkrhfburymsltgfdroeqrisyflyxwnklkbchdvfkuavdammwqtgomzbqufhhblgerdqmglxnykvleg')
+;
+insert into t2(a,b) values ('iljgyhlkisblofhgobacffzmvm','ufzsllnmsqblxbnzjnzjdmxykwevqokilumeaiyubqzshsfhkxfwhqdwtimgovaqpbammredlwohldbthrewpsaltcxwlgyunwuweulixszyxpwhrxzqslixxspxpwkrkauhwsrowdhcuqlwyhceunqknphgocvhvlysdatnxlclq')
+;
+insert into t2(a,b) values ('btndsrgtsaaoyqdrywosnnrskkamcpmlskmocpoejaiqsxqqxrddywpoytbbalnjuvcsybtbfdeortvjlbrmyvnmkrugslbglsxujopcurtuizudygxtswkfiwspmyvsthctpathqlbbnpqrzwqurzmiqbywqhdolafjtartivrovupmmktwqhprpgqaqokcrkuquqxqasxtthlprfzcxzkcvqvqqqyynfmnrzaworyndnabffmzymqiyi','uzpttdxcdaswdkpieeogqupyseakeywqyvetchmyhgxujbfcjlqszspccfgscnymusmqbtycrzuyuusrtqwbiuggdwjjnetdlpfmvywvaszmvscjqrxtxfdqrxgutxqqwgwhrgjqhsbicdmreuj')
+;
+insert into t2(a,b) values ('margoogvpecpemogfuydhbxclpdynmxdbnhznqlvtsdysdroisofgfygxcosqjmhnycbbhjrllwqaflaadndthklyohmrkzygbdzviszdtbhnavijglardehtqbpqrgbvzjygjrgngnipdedjcnamltercefomlccczwdilkpetegqyzleuvcxdsakvrlmfxcizdxwkczqxdrutufisieiowainmadhivgfihvygdcogkmpfetiwgwvqpwm','hinmalsvkhihelmzsuwyltklokvfzzdabsuztvfkpcqplzirkzopqoedwpyyjothiwljji')
+;
+insert into t2(a,b) values ('eoxtjrplwybnbrhjkxnrxavfvpvflfdypnpqehhvhjzqetqllmrdjiopgazxjibwkcblxclqnwpyyndquzmjsagtwkkgrsulrauvnbinzqttlukegkiwbeytjndpidoyparktubjwtepliionugwnxgmddlkxjkwyoldvnspxoafokdcduklsmgoyxomiueglgtwnmlasittluubtarblymypwoibdbdvthxwvghrecrfeyrmuzkqtw','alvlwoskssmcuvkyxtkputlldgpddktetwxivaxjoetwyngcxdh')
+;
+insert into t2(a,b) values ('zhospurrmvfeuifeiwfdrqqdliqjmomfqfdfnwzbzhgtwajccplarnzvxiwfpqgeduoaktlnwonvmaiqnenoobovxybjqvexufirpvppqwfrcwquqjaadprsdpnhkyizaovpmpurqxlgeqnnkpdweqfmgwsxxjchugwxqkotvqkvatyvvdshwmyaegaafarxxpksesjfbiqlmidctkmxmfxbozlkvdkycxhbugkgflpbuzfhxiyxdi','sphddohuhvlzaklcbsamzovcgxzcpbgenftfuvkuqpbitpxlorwqaxsksaapmbxempoarstdnoaytnpojucvwtwovbxzmafegjxodjlounovqhgrbajyehhejmfiercpuzlaztyvbcldfotstzlgtwflnsocxmbdau')
+;
+insert into t2(a,b) values ('vmvfeembmbqhheviefntpvkiapyrguyxczgkdoxvpzqpndkxiyhdxvjqwprbgqbkrldcmrjltsnesqjtkgjpjvwbdxbyzuuopdmpyeesefeuwpxwtkgiehdgmuwclecjpkpdmdzdfejglxwehpyigcvcebjomxcqudqsntvixetygexarslnvbxrbnmrfrjenzhgqzyxeabgsnjpifdiuyqdwxzhzfvdely','dcecksbcmaskzcgrdnnhkvwjzvcejnuleyrcubkszixhtsnmycnhyzxpeebkwtzhwlvzunuqojvbvfyiwwaitahovzyrhhugkjrtyubgykuqr')
+;
+insert into t2(a,b) values ('onwndiyuxdcmxglhlqwxxcmmnboxchvlmovqoovcabfrndqccowqjvhwyaowmgqpzcyobsewffhtlizcepgpzmzecohistonlshgmdworlblzjlkcyqqvzgdsmdrnsvivievvpasdwdddctapzxbjetqpqvpydirmincywaingownhtbnvyswrzjkugpnfvswxhommygqomxefiularfeevnzbumgpqxuemckuwdzhtd','tpaevczycsurlnrjtvnwbozxqpacmqjcxhidmci')
+;
+insert into t2(a,b) values ('ibcoxgixvddqfhmyjicbsboqpyzbrieszybzeicbbkapzigbblnrpvkotvjebutddbbwejroujnvqnssgclkyblgkbwxyodvdnmntnrhbubzgsubtoxkndxvyskesgaxlvvciyjtcrpvnmiaxbyflhuutbwdiugjhewvvbljuucfchakcipkbyussfyenoteddwqzeexzuzmgrmuqujuraqokrpwjyhnvcncjhkcpsspnymaezojxfsejwy','qxopszbwlgmwvngnvbjxpomcgoiofoxnxfqsjlwnkqvvwqrr')
+;
+insert into t2(a,b) values ('idvmnhdbfaj','swkjnndunazwmsshsyenkaqwrqdugibwwnxvsozyphmvtkiywsgzdtuptnravyxwnykbefmfhpukyphcffxekcbqodhbmtdgohoyigbaqqomanidrbeckytbszoqglgagyvmhicvdebczwdnmmncizzkhbgxrydnzbvmjyoynsjbdsjpwd')
+;
+insert into t2(a,b) values ('xsyfxsiavfameoedzcdpnwvonuvttdbfesywizckslruopqjsbixfsrtstcgrcijvphphhitbmsnyqsutbwalknrfwqnhkwbgpbmchszgscgjdokbeqgwzrwrlrsbenuvvpkfjtbgrqzahwcnjxmrgtzuguzybnoqdbmvwufjhxqgmbysycxjyrbcjezfuvdycimioehp','idmcwdzlagxvvhecpkhsadgkata')
+;
+insert into t2(a,b) values ('spibx','nedpetmtjiszncigouohnuuycaqgireyyykjlfwxwqrxetcqzahkrckcocqlcxfskrcfbtbujbmrhpgsfmgomgirtebtkdashapcmaxescmwtdxfksdezezhtvnykubwixoftizpnzvbvazqouvxdcczvxuzevsauyaizefkpzeovrcwfylvevrbpvdpljdittjbsehalkofrybxgseofpmxfvcidfwdnwmufrdtekwuofjrd')
+;
+insert into t2(a,b) values ('jeliudkbwwnaglswqvkwghjelejuafpbbstbudffmtsnemqdgiboyhalcykaxglluex','wohvwdcyhqvolrgxjvkebdrrbzooubkwfccfifihcchefmnmtdgqpqkpubfyndxbiwvezwqugiiuzfthlfckhutrewynzbgpythmsacpdktnrfoxxflfhipxyuzlvedbvkloimjohmftiecwhzaehbiplrzklxqzztiqjszihcitlpuifhnppyofubrxaecqbbnddbssr')
+;
+insert into t2(a,b) values ('hpuybjjdaipgxkdjliskdlzr','yujjimsocqysnkktlobkhsnylhphdzjnxsgzhmnpyzvfugveooottfcufgcferfwjkfjzglfdwrfrfvvmcqpnwfcymrjuwixuuy')
+;
+insert into t2(a,b) values ('oomdqbeaglnamkabbeblylkrzqpjcrtxvfvputuvglvw','ehqadmsoayxaonfsnhskscikrsqtowlbntaznieijhsnzfdpcjpruousvtfsotogarmfejydbbsulpvmoxlanqvtvgkzuduprsqrmcwbfigjmpgsdwpmcspwtfwzaojartnhcccooubsmzonrdbolgfhigrmblsxzsoox')
+;
+insert into t2(a,b) values ('xksriqnhxebjbgdtkqcdpxnlrkgixbjrvlodyghztuhaxtgtceibhitkhjxujldxeegarrwtiwzcbnxoxppjcasuwdbnddragyrdrgcxgsjokgnixsfunixcmlroqzfxuklllnhchhyjpfgcfngfftiovllwziywlvaqtqtelitbheethxnbzpgspoyiixfnrixwmzsxitawlcqrtlmxmmhqornsgokjysrjkuqutvpty','pteykclvehpkhplkalxrczxaxxstjscqzgasmzablrplutawwklvuopiesqnrdvjzrkumwuciocfrvvaccnbxevqiowtbggwusodlscycmnuhgwmljlqphhoqzhrvovw')
+;
+insert into t2(a,b) values ('vcinxsgtysqvtlbtqcenghntpbbdfkbeerjgisihytogmwyawjgmwqwiagwsufhyqtrzpjrzjtusrymmnlsnwnetizqbzqbmsajkvyotnkncqebgech','yndjoayairlmsfevjxvqkfeysmehtsfxtqhsfcjvezerqesjgpeehizqnarubjxqpfqwvfebqnuzzemqqsaojemev')
+;
+insert into t2(a,b) values ('wpeevhdfpdwthpdbdpalkcqtkoaonkxmshivwxwehjjxhqceizjbftjnspoj','auaxmzqkemdcpehuqcgarplztvpfejedqreq')
+;
+insert into t2(a,b) values ('muzvhhssjdjukfvhdpogidjdqujbibxrjyqgqakeltlzgtkizrfkfdawufltverwgtlopjjxsppcjg','jbkzwiqdnbrogpzmqpbwrdsciqealhvczeqdqeycvmbrponwzgypzwetfxwulhcynthmgylfeyfqhitruwtwqjwzsbulfhzyoasjqpiiefgijgenfdlvwdhrwewmbunwtrhwgpirrfksslcvhjugckyeckgqhdbmoqzgzewwkjarppadkiivktmjomfnrdwjromkspwonbqykykjczhtbbwa')
+;
+insert into t2(a,b) values ('niqursynnauhtzfjqysxbltodjxpvigclrjgvffsxboufprstaxigrzxlywxlwzkkxouxcbrsukyhmmggeccurmswhnjyocmemnqutsvgrb','akvshnsfwxdakedvzrbcuusfvtxkpfyttlwhcltorvtgy')
+;
+insert into t2(a,b) values ('uissavs','uddohvrkccxodqvfmfolnzndxmvwtfrpadatjixnaexiwnepgaqhqosnlhdjpsqvitgfbzsuclqcbbscxxzzivsqlmiglnjhcphfrdlstspjigyuafufraonyzllvlvivilnhqzmbqorhhafchtynrstluvzpnwlvgrppjgefzpdvlsywtgxue')
+;
+insert into t2(a,b) values ('ouqoppfblulrydjptmftzhlfltwjpuxhgrdgmpgqiopptqepgopwbwtecvbmghgdwrfazlxuakuuzanwgygyegilkhlkjzctnihpuxwygjfueochlikjsnoogzjajlcbqksqbzqyfulkrkcmwaestytzc','oxmqulnzirensgxsvcedfjcfjjdkxcladewmyvhfjdfttnozhypbjwryouttcksdcnsoflgwwukghnwrvbupgxqefyslxccfny')
+;
+insert into t2(a,b) values ('gotjyzbydhyktdxsdryscxohkxumgzffvtixesmszhsvixoxjhxtewktwtkmdm','nvldpevtqkvzujbtlcpsaamribkyowfroywunxvmlbuftmyehizqurrxnetsfxlbclzdedyjxzgyiwyzqjtwrxihboaxcieptxteuxcvvdwbwmatinntgtcdymywpubmzwcltkhbvdmpphlldeblxvficegbokobwtjgjzolkmtqpokqwzlqncqdexlqhxryzeqbmzjnwcmytvhlhgrfhszxoreyiuhhfcdww')
+;
+insert into t2(a,b) values ('bsibqjhqslucqdknqvrueapvmacfgcirwsyesjoseeybfjhjjsdjolpmahronwmugyffryjemofxdpkbfacgupwwcnuldtfjfpolssruefavjibmfvvfobtmcqjjprjunpblzqffbfclvrvbrdovfsfilydegparbonfelvqomtlvhovaikxoepswashkhxtzoesymaulxcdrwpagqnufyuhbmvqczxgxgunylmziwppkaohzozf','quxlbrokct')
+;
+insert into t2(a,b) values ('nbfzydwixferkeizwclwmzyhvda','slwflbxmriyruvnnsrtjdqnwmeyhlkuonhljldudyuuilzrkfbhqpnbaevnfiomobwxhmgqwjzfmpzaxcegegwexjsbsaguihwctbldwuzqpmxmprymhzpcuulyurmvvtlllzyqxknxegiiysjupeemxq')
+;
+insert into t2(a,b) values ('cigxuosjsbeippamapvtidybyhlkfzyspritrabqidvnjusykydfdaafaoedapedivsijzmpdehzltnzdwwkxbwwpqewempofhjxaauljnwypizwvsykoiwqounaaxmndl','uhgcjvkimmkhzickomgkpz')
+;
+insert into t2(a,b) values ('yuxnmjvsflvxihyeovmbsndjhzavuzaafwqikdosldzxhjppycefvuchokadxupeuaawkwpqhuavzjedzcdxulifepbrsmmzvxauvvjvsyysvfsirnwxvmbxgbzzvozocvgdrpvuxnzmnswzflnxruccrlvjvbzxykytfggitkcjmkkbfeagiqjxtxfwpmhdufpkqvmmptuoxkqiewhyfq','ufjtdwuhdwjimwdxnbnvyctztfjxvufdtaahxajnmmctpxusz')
+;
+insert into t2(a,b) values ('zwpzdknernmybnjzmohrslriuxquqfilwvlzkmwzzoxsjzjdmllnlrxmttctxornxbariosevwokdxjgbvbfbgiivdfykabudgqcugozjmljtsbcfnrzffnnxhkpphlospxngbtctolquxoemppumwfxlsjtsiyagxrxamqkoajmzhsmjljcyw','hlcjgdgqchffgvzbyjayqbukrtpvnpxsvzdlbtngkyupxuzgjaxfoeqgqtzosuehzhuihqowhevfyl')
+;
+insert into t2(a,b) values ('ngeyyyoomepwdywucfocipbsxzjpjrueadlsgfwzifwydjpqcvvuwaybfftfobamloopnrfhmxbzxhzbrwxm','iaesznmzoexlrbzjzukxiqkyrvozzooyndkrougubrshztwxlxmgiycyiwwpaanhhjtahmumsgrwaqdlohckwljiowbcpwyyoyshgrhrmimpbyimxglujomsvnakitnbxkareoqiyjydheogzuzlbvisgxccltydmtqxhpwcbbhrbpvcjblgqsudmhuiaibowfhurkzhfjnwbnpsbzuxckcvkjeaphkpmsxvjppifwalgonnkocdexavhc')
+;
+insert into t2(a,b) values ('rxawqxmgpveqtutqrponveljwkfyxefgixwnmqhlvmrvoyyxmtstsjrexdqgbpabqfrqhowtwwyhkotwjrmyxmht','ksydqrrepifboltwstsrzpjwosvrhtedjfnwlnpsygbcdcaeljvnthwnajmrovigvtsfhytiextxlrzuvipvnhqgk')
+;
+insert into t2(a,b) values ('rthmmektucpjslzdvpckelrusmvjrjeafeppcvaetfbwbcialntzdmoljlkymeomlahvvgixhjzzpzonqhhaclqaszxxxlpoaevvnorpyhdppdcvuvehpylzeywavfwtvsvqtkvmlfxbtmocwiioouyslhhygtjdzafdeudmtthsnvkynjzeomixtvyacvdkbipfm','uzoqphfapdenowvgjfxpcjfpvabigyguteuighlohbvzrsktkhbfrevooqyqzatjoobrigsqjykbsreekgqrcihxegzuhrdljlbeivvddneyezpraotnsvqyybmxsqsgpshqbyahuqdvyxrshy')
+;
+insert into t2(a,b) values ('krlcodkwccrmtqratbnrusejbddcjiwwlgakojigzzkcyimqvaezagcomchfqippjjgbfuvhddxsvozbnuzasdqixzmnlcdezjvxphlpyewnrncazyfyymgblwmlvnviahxqmbodoshdadkwphmflzaaanzepkjmrnpkytzbrdxbpegezthdoxomuibgcfezvdtdqdmtdchpzralhg','hoswbbsxkyfkybcpvhdmusbzqedeuyjmeljnuuemqthlhzuymdplqaqehuemvymiawdxldpswiwbdjliyavessofraywinqtohttqgtxvdxtkldzzueeihgwedlzenhqiqezphfeovslhtakebkoyabobfrstjjdpsjodcvvszuuikezehexlxadrawwat')
+;
+insert into t2(a,b) values ('rsoapkxozzlktwarybpzbanmwpihnwqfebhjqihkuzfmpupjtvkgorvbubchbfirdgbxndkytgllksycnqsmnhratyjrosmconrynthpzrhtdkwtxydyrdoudqihjfmjeyfqhjyecsbbsnqqwbykyzhzcwsfjigzeiugiiyvigdpmwzpokbzavjeswnrmirukdihocptqyldyezcbzlisrfu','skxjzdqlzeypkuughwbcfgagfjykikcoaioozliljbzlbovxp')
+;
+insert into t2(a,b) values ('rfypiwvvrlnsdprbpfjvf','acslinaesvkgfmkhqrxdfnrsjzmkzhkkwvqfnwmdtphthcruodsidulqkchiffeieauehndqjgvwqzdgyetpxffzpdabuubmrsunmsdfellkjsqrfewjkilsofdsxjbhvoxqewosxbwmcygmemonxzdrrzkrgqrtlkhmbykjuqsbqkknebsupcugtfbezbddcuadragyewauqplafjyezaqvscisyzlufk')
+;
+insert into t2(a,b) values ('eppiidupteflnnmhyhbqldlfdvhczrouhlqvsxoifkcnemfveiwlwykziphynakmcsanvdrewpspapuhoymsniljhhfqesmhhxmpfornwagwlqjvlmickhlkzeinxeveypfipkzsqnbuoyrdqjwpiqwhlegeiffnjucxhphxxwhyjfgmprygxmpkgkfjmoavlgfbhmxgeufqbsccgnllryhgczoom','apqrxcfthhzqddfoyoxsqfxajxgejdwkrlwodpsyxjgldmnbfrxkxmbauwxbtggjuotgswfbtrmgwjeiaifbpqyzrmptpbhgojzcewxqkljooarcwbfuuzadyumuxlgndxsnbfmdwihytuhcsojotrnkusagkularliuwqzealbhbmvahuzevdxazxhouxfpjxduaewbxlndux')
+;
+insert into t2(a,b) values ('kjdyeipkwbymjibdeawizaynubxqcvxcvjogzeaerpmqhmpjhbigrugpdkbitlhgcffkmxetpeesiejrtrnfbhkukesriislhamiubmyqconxurluklsxcfrgpkngmzjsgwvotdpctxntfspryrrzijajmanxdkqtjzmejwizfxluatlsbnvqkjlivnohjkmtid','ccdjrhqwaoilaejmenjpirbwzrvjivmrcpxcdlzmisstfdkobhbnavuyddhodiqovfgatullbipljyvbrcmlhutzmemdmwgwrwdvjeosnqbyurmahsibiyqocdqyhmkjkqeclbvtcpbcyyedomaeydcwomexfevrxsohmljndcdnnylnbrclthpi')
+;
+insert into t2(a,b) values ('yjwazqppdxxlmpbfbyjztccxqjyjvvmqvgqfkfkugdeuneukacllcdtprduuijilpgrretowxrlqimvqudurvfbhdattpuqnjftnflezlhkbjmhrifclihzfijkpdcifsphiwcbllscknplsqkpcvqeinehxlcdofrntmxrkkopyrqtjrtyfplpxfpgsrlfxfldezwbauhontbzecialqfkonqwqozjv','ghguhnfnliegkxcdimbyuoyedlxyybnkwzbokqdslhsdwdlskwzotjxxvimulahvvcganysaqhejkvutlrzealuwdchlocrlifrxmdvxrcetlcjieslzoguvgjsitjjlgwpxrbzycvkquhplyhgnjzjeyrzlfcwkbfencspghoyzfponxekfjnointanraxjxbkcvtmtc')
+;
+insert into t2(a,b) values ('zzoybfefgxjpciieyoweykntbzywdpleeafe','iiafdhqwyqmjlmyhmzphfuovoyyguzfwbrfqrkfgnlyfkvcoarylqavo')
+;
+insert into t2(a,b) values ('a','imotgmstcmimivrqlfhcsajzrtjdldwdzpvswrcbwithouxivbkthfhyqlolfxpmxvmteqemaqktamevnijjzruhwwlhzwvhzhseqkyfncldhjtjeieieypilbbunmzwddenjkxbsrigfomblhpusowguyqjwyajgfeabawwcneztmqddpdalzkqba')
+;
+insert into t2(a,b) values ('kfrwfrgqibyfclbmfgtpzxldicrbgmrkiaximacihafgrbjjrtakfavljdqknkreteubdojxogudtgqljivdbjzumt','avmlekhlnrgsrnpnhpfksnguzvecoqsxjtrltzmxswomtxdwbmtwidkynfioodoaoxulwhxillhliqvgwohxendifxmbiqshcxreihsfhfzdhqpusmbknditjfaulwihytnknrft')
+;
+insert into t2(a,b) values ('mzuznsftazowahjtwfnkpmaaeewby','nozccrbxuibmwpnbrrkncvwzukpmbgrjipukncrnrtqkqkslaxnwrbuxssgxfqpjty')
+;
+insert into t2(a,b) values ('gyybtgvybytpkofseuehozofturqyvjbhnwdhhejlxqtaohnywjcucvzumsxaabelqntgordmdnlqcnlsofaxcrgjojsqlvcwcnvwassmr','cfbdrupzlsexvffurvauzqlukgwqqsolazwbdgyqonxcnullztounkzcipnluzglmxrkbabwglkcdrfcvmoljkkfzqdipwlwmobqrwlqjomhzltwkani')
+;
+insert into t2(a,b) values ('snudapvvqlhotkhzgtofvsxrngmizterwgzobveojnemosckbedtnygjgfftvpyhjbkdywqrsxhthwrlvbeljnbesrysetkdxrrv','qwwryelfptaztrmdg')
+;
+insert into t2(a,b) values ('wuozzzdgpvgkyeesqpxdgynnzljlxagpmczziuuhfeibruwvyxlgysineq','frqrespuxlevqztmuyhlzftwjlctbqciytdviorfjvgmnllaofmueoqciasawddqqfpohvfbseyjufvednohidgdlwhnveftlhduvvzebjdspdztsqaqqitdsckxulozwaz')
+;
+insert into t2(a,b) values ('quzxyenspdtptzupnntztqtapyjgiatfsoqrabseqpraliqclmlfxevhxztfvvsspwdichdfnpxsuypakneqnyajrrnqsidirdfarylhvxug','twknnxleffyrhbuxbgtodbtjqkqaywteduihfvsxjcl')
+;
+insert into t2(a,b) values ('xvikedjimaonzphfukpibiilcsdfpmtztjtrfdeisy','ppwebsioevdajsgurknlkqhhwjazpcqacykicfzlaxicnqwvjxbegcmtxfkdiklunjhzmogolupzmhmeladwqtklygfturyfvkkkvkpifvlqhtkuogvuxqzrwqchmmnvuxuttqywbipzg')
+;
+insert into t2(a,b) values ('fuwlazjnsulkddykaurisqccliytxkybknyigtkxzesjl','updoxrieaozgulkgmwnuvxrftsxmisgctrpuybpsfhqgrorjihsybkdlxcudorfbdrjzsaxpknvhywronmzqnefwiiufnrxjkvvpfuymjyetuwpijgmadbmmbmpuzodgctnmnkahltoqidfmrqhoimcitkdezwsvgswdnmtdnrysiovlvmzjp')
+;
+insert into t2(a,b) values ('mnyrnfvseqmfhjmomzhxxvvksxdqknptupvoinqbnthcerwwoenqssjvcbrttdzogywzomiqjeuwfpfmpcbpwkogfarxfkrnvwdzcxhnzcruntkxtmoxfzgwusshxdbmwcbcckpiqmafzdttrlizvfmovtaxjdbnqtxtmclxkelpdyetwxlfnfueexmnravqhffwvhwu','omafecaxslerc')
+;
+insert into t2(a,b) values ('bseuchoxykxspekfnnfldcpnrowyysdzkjkrjujluhrcrnyakxvbdxgboghejoerhfexzobbanpkcjeivupxwuccvypeygmztkabvmefkowvealwogkkamygqwh','lfobqjiightrairibqgearkwsciizqmdqgdusoolgbtpxahpvmwkxiqmqarjbusizhnsrwbjjbfxqgncwsreviymcowgcucjykosxroqmtyqxszafzaltveotbvmkwnwyjbpbvqkctdxphjyzoaltykqpxtioypsuibzvpqkpg')
+;
+insert into t2(a,b) values ('wnebcwtxirmzygcvivrhaqwzrqylnkwjkewdzdpvvykrfsmjxybcfnqdcrzqzfpslvpmejvygxxtsxqwakpiyuxffngbziqecxghmolzvfzqguhhjecuqptdlkpjynpmwbkgrmfpddcajmkuankakvtkaxfrfyoufviwavmpctqwzmfnyvcsdgpiaefhahngujgilsvzwcptsuuchzolcluxpybugfv','vobdusdyyjesgtjnutcnxydppkvgihkpkpsukjcqbdyablylhrlhthncvzzqofqytunwvjexpjkglezoekacwtjhrnyodkegoomyiwkwbnwqfzumpmcpzyelhvmarjzbvjphalwgbdmojpiaforkvxxmspnghopfjindtilyzcvaogsqpylbd')
+;
+insert into t2(a,b) values ('axnhzvjtcsjwmvmnkovwdmilxxhimlfzpwndjzynqrsddgbgnwysvhwdvsuozpcrkfajewjibkatrryypfdanlmihcimrmwonhyqipsfkbqkwdvadsw','fttknhsfkhfjtsnnncrtrhjhstnaiiywhczcermutggktknbujwrtcmyufzslvuvxvldlfnugosjxisyxggdmoarmtzhhlkycbjucvcasettczmgcraoxssusldfedahwafbstznnlvvisunnwdxwalgkaffwqburwpruouahfemerfcxvcfhfoemwdsqklkqcfz')
+;
+insert into t2(a,b) values ('rkszlbmxuyssknqjmuayrbbmsqbcpccstslqkhmfotqsvxcxenhylronohokdrhwyvhvyoofunqzmsiqglxnzrbotturvggxbzkxfdmsxcvdktnnxmemvlur','optuxgdycxitgglxmzggzajmogeesfycemnjqnjiohezwlgobltdfzgfzppoykownpiagvzzfecfzobtlgvyizok')
+;
+insert into t2(a,b) values ('hvpekpeovkkimqwjybmhpaodrkcovgfrouifyvhbmwqwxvjqceeufmknqtelyejjrckxhmdnivcbfffjkdkghtdejqgkbxrysbxmkeuwiwinrclkgzhjyebcmotuxpuyqfekgesmdqshgxjthjymwhodexemyiwvavqenuebfoiklyfmqsjmbixijepwxydycvbbvvwczpmhffzezxcbshrpwgufphorigwijsqdvlruwbufiqmgzco','rzeehyusictwhqmhfmruongxiodgjjmzzpaygyijukcfwkkenylmnztnfuokb')
+;
+insert into t2(a,b) values ('lklsqrnjkuktvtpslupbuddyuzwwwqqkbhnpuhzuvbdwxwzioconhamntyluvhkebnwngswoyevfedqjnwgmtnbikbkebhhvpnfgdbbcxgzzzpcdvpqaeovodkrmmqujbcfgjhcbisxsdlimsxwnxpzxiizasfbcpnlmrktyjnvpllqcatgfpihhuadguaqcfxixfcxmkykniqwhbkoqfjffqpkpgtcwrpza','cxcshqejhsojmyhwhtqdeneblpflvsonqwlnlrgkjflmwfsbbxfvmovwfwdkjbgbrhqmvafdrdfqwszusghbmikocdsexoobhxjbebbibdjhcvdtcjlmtpfudshrdzcmfjbllgzfsvsrhiqjojachpngmtpnddvrfrskcxbjksnrxwzzbqpqkdntnuqnfslogarvgdvaelbrkpkqfddixbnqhhlvtsplptarvtrhjadoveoh')
+;
+insert into t2(a,b) values ('yarktlyjfnrukydevmlbgijerglbelrmtzsbwroiblctrgvzswwrozdbttpxfqntsoknvvxjxywcjxbdtfwrykbyofiiyabkzerpjzdwzytfpmkkgvrpfhgtbulduzglqxyhwv','tqqxpphmiasdlmbkeyajdkqfjrkkhwwpvrnvedrxdovjewerkrkrwhezyxgurcbvsxqijepwwuiyxbccpczooffsjngmsbbczuvbonctuiekgjlkqv')
+;
+insert into t2(a,b) values ('ogbtqivszqyyfcrbeubtjskwuflolouiditmdlqcvxeutieysxyzrvtdvohbzmdcdkbomdcckpmllimjopatfaruzwvzxdpqswtgntjlafapispvmrzmlesuodmuzssmmbihplnjkjmfzlxbxprtbxoxlvlnokzyegfvvmcoempmgdlnhcmwovbcmcffjgmfqdauzykpisvikpblkdzgafzpbqawi','ocyzglbmttutmregeyucdpdnbiblkoobgrtxcuabxqjwyqccdzxdgtlqaadwxnkbutdmp')
+;
+insert into t2(a,b) values ('rxzuwkfjidiwicnazeinbphjwuiqlwtiuvsuqwuhvvgmfhoklvcqabublqtahzouu','wwjuqoxsqnajigtqijmcnwxkrmduucahvlihyjbfdqfouiubjzjqstcklmuahslhzujeoruuew')
+;
+insert into t2(a,b) values ('uzeguetxlwcgcuuryszvqcndewaxivvscxryxhjqbmsrdwfgxhfdrwxjihbbcdilpasuttumuzfhunllqfvhgoexebhfrurqjwikphyrwmqomxoalglcex','vdgoyqrbypdjqnxyoyocqlmzupguteqorjqbnhiefyqltsrusawlpgvbxcftjydaqmuiinkdhzybanefdxjhytygaavkoilabfnstbjidwjwkpgdgkauqpcstqhhiyfwzlcpqszizesdvhgegyeldjnwiqs')
+;
+insert into t2(a,b) values ('tqglnbasddeznwfanndrbirkwtrlgrimwzjdaqjlimmkacwsnfmzacrrbisjegalqdbusituouawuvysdktzjpvgogxepihkqeeqdgbualcezjmiyfaxwqypydwvuburanafswddjphwkfzirlbjajlkpyhxtgmmjzvcpucgevoctbhrwonahwwgshgmqekbgpcwgenhgosumpzayjwfhbajuabouhlepxrlvweujljsgxpjeczwdie','tfdcvmnvuwiiymmqnkenjiygfksacmcfcbafvdbzlakbsvrvuhauhrknqjnxqfsphuruccazezboifckmilfcoeodafvgpzasvndojwtwgmkbzdxlmyjtskinmjdqqizclltgkdxnlelgwfncfcwuhcizcybipzfwzyypibypfxpnygpsodllxgprqzrtsr')
+;
+insert into t2(a,b) values ('iofjqmplfeynosbebpuccmxesjgmbsfruckhidvglrzprotknhyymyvfeqkddncshnpljchlqagkuekhxytudqefgweoshobivzwmplkxwj','fmltnfibbacixaopxralhzzbahdfzdokeoksbvsnaadfnirhnsjsptkbhikxtsgyxxo')
+;
+insert into t2(a,b) values ('pmdhmcmuarknrhjwaqtxsmfakcahlmdtdvxahehbyqdcnbuvylzqxeeramuvdjtxqfrvidjj','jrsffbybolqrbwrqxynqzfxoutjtzcjlogimwvhsuqihpdrwo')
+;
+insert into t2(a,b) values ('sjwaphdzpstiybssfahrafutyowdwwnyrqwdafyypycyhfxsgrutfcxwgzvmkvptfjdozakupzmzmocuqvgyqrmpzfqvokgyjqgmwxueosnrohjv','hyzpciohxkeocsvbsefsxrrxukuvhuddxtjw')
+;
+insert into t2(a,b) values ('mjeolfusbdhlcunjyntiwunbzsruvencxrpbvhvhikwjnwnzqazpwbzcvpvjqxmclsslablovroqqqummmmqfkudabvwfbeqcyixgdjnecglmqghkocmaniibhmliornnlglfptmjsrxueounuyqxfvylriiffntxsnzuixxxqkqtzkbar','ykdjinombizicibwayrhfbdeiyapymruxxzfszrngwmzlkkoutjmtupxslhfslsnjnxmjuwxbqddswchllcxbitkuonouwyllcrjvlcqujqjdbsleskeqmmuurqfmpigmhhtbmtydewqatgwxdrnmaheixubkbdvvqxrg')
+;
+insert into t2(a,b) values ('jyfmpfdzjrsqhksogrugeppyxuvikexhegzdcwxzcgkplixotor','vdkoenquttxaxqeobdyxuikmondjniaafcyckzxbcocyjbkvntlarvwweszgntbhhdecsqedfqpuhatsfjxcbastxywouugfocgkkjwrmqusduubsrwlymqmbpylzmsbepsjgwgiccodkzrrxyqtvwjelbttcykpgnmluulphcphvmhjagpjtfxbuyldprfzcw')
+;
+insert into t2(a,b) values ('shvaliechitkekiidojqpqkpqbsbrwrflzdwjxbiueocwvvhyimjjhmwiohpooxzrltpzbivgpvadkqntoasmdrdynopxxhfxvkmqwoxcvaxkirwubvgmadw','rjhorxkadhvjtfusbhxqhhyqxphpbxhpbjhanreaxkmyujqmljnneimlbmqlnfaqfjbzxtykeyomdpcyqzaxqnmhfalewuoptbubzyykxl')
+;
+insert into t2(a,b) values ('pejjmzbsajwohgjyljlpvqdtjbavcqqnazdybpdjvgvlvvh','qniqpwjfnoiylnuuifjuapvvjbhywjqucyvggokpkvluzmsdorczyqycrzkuxyzsnbdzfddnqjnlaifvopogknwkwzfpyojilmqusnxnprfeyyphqrkwbepzuqpshrudbmxjijitzybghvtnkvusrrjjqodkmfca')
+;
+insert into t2(a,b) values ('eolbeiggiulitfbyrmkbpveckvshedkpesevrvpupafpegkysvywwoqegfnsypahmjlhqlnwyargufmseasfguxbroeexvmqmefijxgiugqtbcfrhsgahflykmyoeogssgdcpputseebvfprkmvjazjuzq','yrvitnepwsedyrhvnlslcqkwxlrvyxigklcerrpycpvhyqmkvdjblhqnykjaqhlvvuqcqhjktwujyvvbsuagpbrvfhuqcerraegdmxwdzvsfhlueqemzznnabjkjtrasvnomaoajoyipsgxggpmfsscpfyoyhjaeqj')
+;
+insert into t2(a,b) values ('ydnljoahnshakbkxmqihiyebzxjrsiaozmuzizvjxodfzoowhbowwojtkzypjitjbadmttljoxcmrvitncystrv','iqcipjlsrnrujn')
+;
+insert into t2(a,b) values ('elpxxahezhtkpafdqpjnlmuhvquxxfymlhrfjfirnozavmuicwigzuogkmhwkiacjfjyagxqlknuooncbdiimsgcqbuozbgtkkzieqpokkywuccymrmesspbavpcwikyzwyprfcowukhzxsvkdsncvigjbkcplyxzgzgjmnamfnkaenvhgkiudfbmztdjupwwci','xiovfeywarrmxlnptlwifahtejmbxbcsi')
+;
+insert into t2(a,b) values ('wclnrznvzvdtnqgzexkxuzsgoiohtkgzflhtxavhivchkbnfejdjljefpcxmiirmasshmehwtbxpuwosimyvnvvfmygspdfwsucxsnpubcqxvxpyiavvnzlhwpbqvoavapcthkruqlvpwrlebzxkded','xoaphoprgvkzvjnbfzkmociqnvzjeopecmpfnjfzvbldesrpfrlnkfeclaoikslbyeqwhhykxtxjrczkrhnqtfwccjitjjfvetfbrnqougmznndslmnwpgllxqcujpanptzffahzfyxtyxayhhfogspjlsfkiukxasnnhcbxgfjcuxydgguprbrspobmehxvobcasraeldleypyzkhzzcpmsrxljlr')
+;
+insert into t2(a,b) values ('yfqsyxgnmduucxikzdyfalcyefztoqdkbsoqtjndlzkzlnrqeiatlykqiutfnnsxgpvejdbveukbalujpmiveumujaqreofyxawtqyaytmortczkwppkezeizrtaemqzbrqvvnmvabwndiggqtvtauuqttqmlobmicvfruoayqjhnfrxaxbosgzjlhgasqiufyglapijsjpczkxpswipsyf','vfgcdeboaqlhgwuxpnturhkcibxnbrqsimrmcinlqjkbernbrofbedmkutidjmcztxmcuuxqmxahvirwijxcdxmopditnivdugtosznbjfcdqeplnierchvokwbyfdbpecrqrqjtqurnpsnaahilmycfoijfvxciymppfipscarzusliavmohujqhjdmflhhlkbxctzessgsmtswjmyeuqxrgjgndehsazxiuc')
+;
+insert into t2(a,b) values ('soifoceprxvqwlqjdebkvcbpbfvqfuqry','vlgujkxjxezjjtntefaoekasjrtukwwqwjefjeabtbthyhemnkyexgwrzwvgtozvuecbewomvfrmobnrkxwtlufejzgqjvvwnluspiarhbhzehanaxjqzjuttoztrpivflifloxqnqdcnpzwzealbcciwticxhksrvnbfhqrujvuoatgtudtcfeogzpjkngvvvckcrjxyrmgwcqvcfrjxldpwebhadnyim')
+;
+insert into t2(a,b) values ('jnuyvhrkiqavrehiudgpfyiofwrzfwqeomxfekidtjlfvuloeqzzgygikkanwvcgxvepbbiwiciczppukshqsbaiiiwhcrwlkwhomttldgknkuxirodoxuyoiabbpvlptfltrwsgntyeislqipfmnuiybqqdzeaujbfzmkuztvegdgboevggonojmnuxosbsoqpbheiwqiibjsymbndhmhgcfiopyh','uvozkjvmfkhztpzbuwrvaklqiqdkqayqtgrafzlpntautkhdrnyevqrwfomhdcfrsgylhaoxdyfzfjhquvmzowodcgmkzuwyemgssaoyzrwruohruwphwrsjdpanzrbbfqysllcycxtxhhjuwtdndnruoednvjidswioeuolcpqsezaofbuohgiihiklcqeap')
+;
+insert into t2(a,b) values ('mqszxuakmjfucbrfogyjletbzaluofqrjqbnzmtwephdymfnonrhkzxoykgekeggegrvwcaqhtaxgdagqjzvwaqkwzrylwjreocwjlpfscojvfwvecksftsmrkifxnxogjzvjjafbomdgfzouzdlkcohvbcqliidrtdulvdmwaxczwbvnfwjyqffudbnetarrzdjvr','mgrebrmgypahhtftsggse')
+;
+insert into t2(a,b) values ('yvwxwbofzyfdstaytwamntmbiourefxehhnaxbzcqhczmhtkujixcmwbmjqrufrqllrrbsenuetuqmcpmjrahgfmnxtcifexsbghvhabuneuxfggjvjdwmnmuhmwfuvwthekbdyepenllimgqczyxflenfifuzqrewc','mgpzjzleymrl')
+;
+insert into t2(a,b) values ('zsqdsqobccucfawociibkjzpctrpecpknyhu','spjbdnfubrtdxcjsozcuxnsaufknzjbhmtkxbnxesyjhfap')
+;
+insert into t2(a,b) values ('pzqjejiuwvurnqwusgirumvmhaayirjoepetmetmhkmnfrkzdnyctwhalmcynusgdglkkvwxriaxbrnhgubyawidsljeugqrrlyligglimxyxamkegweatcymywbdhouapbhlwfwivjquusuxlokbppkdzmsxjrhplisjdrzngqqmqgcnqjes','immxytkozoqbdouxy')
+;
+insert into t2(a,b) values ('swaeqeidtebzkasccesqxxpzqwnehbrbnagfwxogrignjcbtnltcyptoppkdqbcoheybghwjmehjqkeqnsiyivslkilnctcswmczcirkrhovlidlxydndyvcsgijvvhzxpdmazdjeulsfgguixhxvutqgnaqxivvlchhyoygkuzswnebwcjdizs','sdwlrzhakgoudkvzeshdzuquwetkxjimwlyalfuhdfeyndozfcjisxphqaqdosyfmtdeuikyaistetkrpshgkouobplmevpqrjwvwranlviqefvjahwwsqtqy')
+;
+insert into t2(a,b) values ('ntxzaeuapkdnujbxwxjocqaswsnynftwxowlphyesfahwcdzbbmhygsrkotbsfknyfpfdurubrtlpctihnwzyrztgzheryfdftjwwjudlrxzqvupvyzelrumvgbcqldsvpmghejyfwwntlqccceqaeqxodrieezykg','ditcsrakjnqxqdbgqggcecmrkojngsyhgfnwitoqkpjjqnilsucqiqmwkhwnamvlawkcbqgukdflttkg')
+;
+insert into t2(a,b) values ('ebijncxoyjmllopqnyckhuemxoejjqjnrzihrcevoismmtbjcnuuevrnbdtmolzjzkaanvjmfaqnagafyughmsxengfwmjkgscvgeqtsngjwrequbffjiiltzeqpwwkhkuzdzvwvqkxxqgednzupbkhmfucphnghgxzgwdenmojrtfisjsykzntpasuyr','eoyysqbloaupozfxsuddpriphitldsrcrigzdnurvaxwzpccapbswpagirzseglahbyyrbhowlmrgcecpjhuyutgbmxukjzacnlxktgjywheyapqfqrribaoutgovkoqzbbtmkwdhnfpfazgqejiycjxanibymnbspayahmupzuimkparlfjjanllvemeebycvocihgleznjndijrl')
+;
+insert into t2(a,b) values ('oepwauvjcyklhfdrknzlwqlyjbedqfsquxnfzrb','fajjwpvrdlskxkdsyrpgliejhhahhybzqilapluvvkrcmmzworlwrwfyjrfnnaxweomvdeokroytahhvzvumwixzvkffzouahrltfquuqavigusvhsfktwusdhviuckrdnfx')
+;
+insert into t2(a,b) values ('yjexscorobhvgjgbacocbijjscswstouwhwyxworguzzxyozwfqrgxcljdistgogkckrksgbtkthqlqtradgnzggkfuxdagodqrhpsypxxcwkdtjzvphmbuxwmzoigsinvphxlfzdhxuhnqoeqeaxydoptuksmjxchpknjjkfzdvuevoenhpbfzjnadnqyf','fnclruaamtdvomnexldhilmvbgquxsevuexvilquiqcdqhjriivyodzggrxcndouvvkrfbuubfczy')
+;
+insert into t2(a,b) values ('xeiozmtbjdhedpcwhwuocdfmjvxwavpdiavlpdhcmcgqoldwhvikbnvwiffikvshwpbmgzqulnslszfoleuinlchljamaerrtbfhfswldtyykeqxzwmuttkiuixrfalavhbcxmj','bfhkjwdfruuilhzsrueossbupthzzftmgttqvpcsitffeooar')
+;
+insert into t2(a,b) values ('tjwacyrvibqsdgm','ueshiwmgzybljzsycfmuthvstounlimuhkuzhpvsio')
+;
+insert into t2(a,b) values ('s','axeelzteufxyswftsmhwaqrd')
+;
+insert into t2(a,b) values ('wwnywzyqqajwffxqpcdcmmmkjoxwzvenjhzqjneuoyaqekzbdoeljivjriepsbnrpbhvermzlmysxsitwufalcdaqwntbscepjcakahjpxsandgijsybgijicwwbibxgfucyglckcpurhcsgscctxtauuieyygvvzeazxhmvlilplosxdrhraqmgqnchuyxuyxvuvfkohvujdbbvsvi','pebtcmkqogbcfyaeoundrnviiegyvtqvtqhpzvtlwpohyathuklvhalsyrlbmpyqahdtjugevxxbzcjberklafniecvvksbuahsnmqukcbklnkyitgddvsmutxiadpdvjrftyszshnykahpalvpshoonjdyxbbhhxyrnmfeqimglfbkvavunphtbwhklpcdr')
+;
+insert into t2(a,b) values ('tlgukyeltdjysqndfcdlzbreosnenjkuasfnrtfbdzdybvnbcepyjnymavvnmdxmbrrzpndqbwdajjubwpidymdtyqqtjlnoskveflwgmivpehbeshfbbpbqcuoqhgfyqpvakcmakt','qwxpgcgnkbxxpuvrmnjbmhqvbysbdpvnidagmqyywjuapjxezjuowoxhedterxfaqunaljhzzbmyevgpqgecxawgtyjznrlhwwilfxjtwdodreyeymrravrqutvjvyekyvybclxpxuqmrsccnjgxrnnkmbfwxvctgpxugmlgxdgzausaztnkfstgunzojrmdmbxmtbjpxtvklozjycfmjudzglshys')
+;
+insert into t2(a,b) values ('ifjmmmoxkhokldydjgumbjhcfcdlerfftyxrgpcdacphocfyylumkopyrgiizibsfavvkvlidojcjwgmzgwyqhintlmrdcakxinpjrzunnjqezrpyezgbniuhifkmvcmscwnkrelcobiqbmcdcnofnqmgomwqyrxzowilmdvuxuomjnhhkkikpqthflvllnmcrd','utmwvcqhrgpbwzyswrmatqiumvbwyuhnqkjvymqvamxfcbvjmbxiuckhevsyrngogpmhbjxyexqrmfxkuerdvuauyuczedfoqvfudzrdeiirgrgbakfshykfrmaocqzhoznfswxenvemhrxytuzy')
+;
+insert into t2(a,b) values ('lzdjsvbwkuxridklbvdebdacpbjbolnyaebzrahiyoktsuvzgguokzijzmzmgwokaedimhvdsolcamjxhkvhjpbigfawhmujj','bmxvvcsypgqkphnydqovqiooybockfoahpxqwcyctkouifappyviyxvbbpmrwmskdjzskhxuxtrvsmfqqikubwfukbbeteyrktkodirburjtqqcwwvmmgbsuqqrkvubnjxrgcujzggzzkpcytdakfwauvgcbizwxqdzpptxjruybmibvvkthiyucskrfzpdlhtpyevzekhxjlxsqzhowwbt')
+;
+insert into t2(a,b) values ('kdfbmqnnwbxpivtzlzvzvcuhgjsnocwxrytbnlkuyjgnwimhxoxitzgdnggwjegspkkplvkwswyahpjimauoinkbxyggbitkspqhvjuudwlmikxkgwghvxpucjizpofeogroiwsldnvzwsiwsotllq','vnshjwgwubytcstkqmqxnepgfxlcllutdjtbdvkkdtrsyiyzfqamfxwuvxofiurfiulnvjbjvgvjldfyuamxziefsnywvhkoxpnvbnldyuusihglyqxeajxacautwmxnsvzthshfajwqgwtlamuwezq')
+;
+insert into t2(a,b) values ('zaqpxckbbwuwqjefxjetduchftulzgqzbznnzirgytmvkmhyuuwnwjjvpelsposxyvlg','ckdjiahoxawlzpbshpbtftgttiqklxotslnlnemyiooqdfvvcasbverzfpqqsfhgnnzgyrzszgquhhkkzvphxecohaliekqbcromiiteetmtqfdewzqeptwzecteoaenabqasetxkdmxhnoxwffwktesnnoykubiznfoqviaoglgjlfexrjzpubqwjrizxslkowdjtg')
+;
+insert into t2(a,b) values ('tbxyaxtvpmiyfoockmfcenonpmohnnxgqldqqrnxukyzckvcbcptlnelsibdgbosijgxwlmahkstpoqnhbqejjznmgejqqoitbpmfiirahrxkwrvftpirxojbvznayfcuzveeupujjdvcuhrllevsudjruliffabnxoxvdqzodkp','ugvkuiffwlmofwvicofrouilavuwxnaosqxbrogtlqkpwy')
+;
+insert into t2(a,b) values ('ikywzqitrymnfhtolprctyzw','cyyquuckqpiiccatrfggvcdtfuvsletshsvyzhmgxscmedvabujsedgvdegbs')
+;
+insert into t2(a,b) values ('kwuvvprsekwbzzwvxquhplffpulhimtjlroxyyncrhhfqocxcudrfapbskqythyxyvbwxlhhuwwsqhojknjttmnmldubqvfzbnbutvmvervawjldicgrgvhpvhktilrlegodedjvnaejsh','ukpzobewpsgpqepudaednygobfhdmgkowlknjolkurcogtqecrfekfkphsupcnapvwnopjhujvygtrurrfzjnskeseoqpiscthgtphubireofnfbgwujpizddwcwisinhmorvshyanbolrfzbciorgjpygbndwdianzggvozbixaibenpvounxddkxqyizbruowujxfrxnszvyfvisyvafmjpmbklhblrdscnzkylawazuggia')
+;
+insert into t2(a,b) values ('vfmgmveknldspsworzonumqcanx','ttfqvsuxvsrfxlqoheywyltreytndvszpbwgdezwknlnmrlytxzrfoogoxrogvijnzkjlkkxotepwakqsiecvgcdovblwvibnuuxolnmlktmubhckltlkskijnwbysupbzgyxbxcnmembegiafwgnmydbhndrmdbuzrbrwmurfwbzaohciredwnxgmipkdrempjzngukjxgcj')
+;
+insert into t2(a,b) values ('opgqqbvametwbnjsdrmhexkccrjvqlqrqyaleglstudhudbtgrczigcgezcrmiogmfbborhdgmpxfltxwwyhwhqyhripjheycoiqpzrleyuisbeltgczwpsjhftlfracbrxxuyolbavbtqpdhh','kkcwhyurwqevmjwkeevrfvhhxudxnzedpbfxtp')
+;
+insert into t2(a,b) values ('abdmpxqoaxryoqermzifxepifrqomklmxeubrotjgwipzfgpudtwhhzhuhlerstmolzimtyodmkcojmjacezurmruddghdktafijuoipskkajmvxhcfhkcklgdtznzyrhfsu','tkyvrgehdlsgprbckkcdlbcvlnqeywoiwscneihxretzxghehywwvmhuzsrphwqvllgyooenjzevygnuocgmgtras')
+;
+insert into t2(a,b) values ('pjarhnkpgaaqltxsxenwgnktwqauqdsxwfdwxoayhxfragptlunluhlmawzkqwdtrkuswmfcx','mueywoxkiudckcjpwgzmordwkujcfrkyynmaqkvywzj')
+;
+insert into t2(a,b) values ('xhxmxkvhwkdhcirwbybamilpfhynmelgnlyuvgwwtqkfcukimyqxolyfisglohnchwcvkxlkqs','sgszzbvfyzyjxticxlkwbnszwtcqrksovhtxagotgvcfukmvabmnbvmxkoxdubrxazhoeiecckovpwgpffbuqwdyqt')
+;
+insert into t2(a,b) values ('awviktnknyfyzdgsgnxjrxpzzlozqwxrxuxnbumsiogfmjmvfhhzvkordtfukwhbblzridkhbffhyttwbbhzabbwkicvvgrdmswtigidednbekwsslbqqsmoiedvwwtjcvxlmcjyzsdyjsdnegrjcfavfqenbzudxvkdzaxwahsyzewfyq','jdnxenepkbqcfgcprazfqhsdrwtvoorcrlhrxvkvaecgpmjvnrbkbxahifppsjlpuhqtxzvwabbcjlbhyqfxzyqpoghmoqnrmibfqlwwfcmahokwlakemhzenqymrspswqtuvogzxlxyefmannwxvnvzhdqbhqqkwxqa')
+;
+insert into t2(a,b) values ('dqoosqxuznyomere','rswacdtvsnnnovtdnrruazbexvhnxwfpezntcfuzbnsvttifrkjkpjxfgictdrssrcliuwavpcmvqntuuvdrhuhlvqnsbxzzutqskmwtyyntyslzpmanttvdszqzhktpqijhkgqmqlappmgxen')
+;
+insert into t2(a,b) values ('vzgfbwnbdbihtwobiuumyhnkzuvpsjxkntgraapwydngaemdlagjrxcdhmcvqqypnxorsjdlciemvelaugwnyerwadxpvrddujxewpdgtpzlxkgdevobrxnzpcnxztnbkhoymiaxayuvembvtsyxfsqjqcqpipjzohaaumjrxhovfghcpppsuhjvyrejafxfeezsrsyusjjgugtlwwxcs','upfhaeboxprbmawspbcvdesqaxouyccktqpwmqzagewuofdvlveryffjwydfadtbtqlixrhpejwigsnqyekizcuyotvgnjxvmbmmabhuhipwadvczbcxdzfkoywqqqxmfuvubymtpmz')
+;
+insert into t2(a,b) values ('lqntnwj','qrjdbfyrxybriwmwireohwqsmtwsmnuideoatqzeueybdaecwihacjylislhixc')
+;
+insert into t2(a,b) values ('kjpvkcjleggroeupowlbtymscusmpmlmkqwddyexkzvdwufewsvqwktbimjyxcpcpnojfwkyiwtkrmpyippiqoypuqljarmeykewktnvjqdgsjsorqqqrttprvdohdvmuiksqatptqhkaapkpdvulkdwggmyapqthvptbsxwpexrlrlmdymkqjaggzmgyauwvnszdacvjphjgdyxcblradlgyndvrcdgjapwcbleavhgrhj','gikmqscayyhgszqyawqmycfqkvhebdzdvskyqzsngsmylidnywvtyswlzwjmulsnhituksqiqfksiwuuhamfopgqydtuoumpqposevkrxctunfiggazvohxlzttgiyrz')
+;
+insert into t2(a,b) values ('aobuvvwvrvdrolygsgwixmrzzhgkfswcdozqcpqjjxlmbylhxlqlpipvevsewtkzygpnuljbwjxjxtjrnbpscfkktbedhmkqrgtepopgcyxyrdintyeyfemecuwnrgwuurkjshsolihfppvzzqyhiklikcatrkaosbnoaskilcclikxzdxykwqhwmcefgzuleeokikzvctspjkathz','wgmgsgvrxzqwldpzhlozxumtqcqdbqgmxaxhkuzbeyjqjfosjqqygnmvjqavmvwisgjmthqbqssapitbcsldduxqsxmxhsphfbpestfmbfpklnivqgtevjsufwkkfosm')
+;
+insert into t2(a,b) values ('vddkrbjkxgrpatkklrkfgqhldgkktcvjafrhbfkvnpgcockcwrnchalxibbyfefmuaqjcelqkexmdcookqaxtnqdfnedhhkopexzvcexppgnunhwgwgscmmzhfmkzlcnsmysejlqumuizopwtoodwjcpvdrgmevvzpobhntbmqeyvpcculaxriajsluiudnyl','ziuipbtpdljwhpxxyelnwmxiknhfzyomeytyuonkmtxvmolnwanruoaslpfzqaanowfuzxricctsjnwcbifcuelcjfwadoylscdz')
+;
+insert into t2(a,b) values ('edixxhyrcswbkbkdkpymkhvelhqhvdlvccfjukkhdcfzbqdhuoketeqkqgokqqztcfoopbvfjckedlxyuudbmlihcra','aozjlbtghxfxyegznpdyvlzxoyuphhvvaabzcfkkcmfjybdhhdiybwwercpgvwmdidentjyryxxufgvivqzkymxokrxssfkjqbqyvdrjljruhdrgsnckiczntmlhtqxtjpprdpswksazpqfqcjhtuejwfqzgpzsvtktoieclbfhanqlsufnaukrdseakvogfxdvwfotrtjwwgpwykznijaxsiivjqghpkpwmbxpbauyyepulfykdx')
+;
+insert into t2(a,b) values ('vwrbnsndgwctptpktrmpnjhvjixjzmypzktwobqnuyxfjljwesedordjycgxgwqbbkgabitwdytqbfqpivopwubuteehcmdlvuqeetdbtvsmwunlnsqqunqwaatbjfcwmqbbfnqugtzdlkpnrjikildthqhinylnjxxcybxzzik','kxlktpzobputorfqhcjopyezxvlzoedouxwyfvoyklcydvjeryhgjbtksiiwvqpfdncwjklapmakseprvynsdlkdyikkrydqxqlxvmxhztokjwfcrdbhpfofuhzemnxeiu')
+;
+insert into t2(a,b) values ('gyskyxxyrinnatpamigbtpsfpqtiuzopqhizczbkkvyxqcdeozgrczdykabxituazvvqktmdzelwpyqhrypbibpisqgfthhsawjdrosdgvzghqelolnafhljwcgbjjayizwvhblgtjieqglkbemdcukjsgeehbmkx','mtdwygcrgwqfwxvmrvumouvwjkmusncxyuanpfxqnupbjqhvtskorazdhenuvmcivpgjjlhmpfzfavpqmuhqvfabdapeoaxtgpjsbdxxawrpnnwphriuiwysdfueoddykjgyagfzkuczkvcobmnoqrceplwmfrxpbvrijpcwwvplzhiwufcisdqemqwwwdeifknitzoiocndafellwrhjodcvlecebgnlroazrlsdcpwzhnwlagxo')
+;
+insert into t2(a,b) values ('aoblrswbabhzvotqjpkiesktvblurcpparvhntyychhgg','ruiofvaducktvvhv')
+;
+insert into t2(a,b) values ('mnujkgqebihlrzugywmlbkplagbhkomfnsqpjdelnomgucaicjeiljwmfwvcixacfpkkokiajuynckatndzirkrzfmirinozkbhenggltmztwgqavbtesatnxuixzzbxzmumflcatuffhvtprzbqxiunibksjzabcrafeealoepjjnkmfqcgjgwvmmrksxdo','snctehuwkzcymtkdtaxcjaeoxijoqgxttkrrzoziytmvaktmehqwzcwcqtixawwkdikqzultonvlblsjvpnwgxpcavfawygeckgp')
+;
+insert into t2(a,b) values ('bsgndcgsomrhbdxrtqwiqhwgrokusvchqeenuilmotirhdbfnqlvsqnjyaubirbqohhfjtreroilgwtkzicopqhjkwouomhllgpqluyfjmymnthpldptmrashersedwwvpipxejaivzqebsqfigdzelrjtrmviwg','piblspqkndpzymavbogrrwbxsafhbpfjrpjb')
+;
+insert into t2(a,b) values ('knlrffqlahpuyysdasslohponbiauctwbsoqircrikgnnllcrsbfpcppbuwelipdxyvyxeqkxnopbtpqvjrdyjnuagpkfrcjpatkeyldenpqjdvdgqzrzjobjfkawkkizlkyyvrsmzqaqgffkoczqxoatubkuzciltkoljprtpjunlaeavpnlxeskpc','vbchohrzshmjyexnckkdqctlvithuhzpjghjguquhtfofhhqrnlsiaegfjyhuhswzthgedhqtvlddchdzxshtjxwknairvfprxrngqchunfmooydltcqpyxrzkjofagekgkhlmpjvzfhazamytngpggjzqbwilunaismvzrbfxpsrocvvudjataq')
+;
+insert into t2(a,b) values ('fxqgtptxrbhtosveqncxkkhyjplcomoaizwpubxvlxyhnqiiprkdhnabviuqzcohoasofytfmasdnwoajiohhbipalvrofmvmzgvqokrbicdbfuqqwuegpxcpaioqqxspctsfsluaphkuanipxdufagibvvpdgryxlsxfddmpprqhzqgymyreknxeh','fzjkaviwtywhikftgndfacfpumbxwcbmfbwdbzejyufybeyteuzdgxkmsmtrlywqadiyuexwucftbitkthxcyymoyzupsbabqblcavqghmnnsokckkpejoeyctftqbolyozonuibhcbinyqifzfkqwqwbosofsmvbwhvmajvmqirrcwksvb')
+;
+insert into t2(a,b) values ('avhapjbfcuqgikyvdpjhtvfxgwmctxtosytippvnasvprxdjguzdhrxyrgztxyqmtswonlwoksh','hrgrvwczumqupiourjgaykxicvlsfejxbflzjzqdatcmdnzbyczkvicaktjcnqvdwmkdexkvqizkbodjyvfyokhklpggnnqurqlavaptfsbsbclazdukggdzlcpqftrknmkfabwtwqeuxfcnynomcnpgzxxugnjqdugwrcctjfafkeuwikgfdqfpmutkcxjnnwfjtgaatwbpyyipflsjzjaqksumvmyx')
+;
+insert into t2(a,b) values ('hovzddfwsrntnbftfvybroozcwxhwcgfmvzcdxlstfilbjvbfytzekqeoslewrqzxcmwxsbvauhyuoifgaslwmncvvugoitukcrdxetmrzosquzasutacqvgiqfvqheuzivqkhpxapveqnwbjkzbhqkrnhwsdfqkkfcocfyafhvzdrnptrxwcqliqnlrtgxwnunsiqfegrvrfswlwmxaqunxfrjmpohmoxnagpmxichhgslnedgmnvkkdfdjxg','eplrrpdekkdxojefwehkscuskxjtyeukbcbnctwmlxdf')
+;
+insert into t2(a,b) values ('ytupmlbzejlldjabhvbgnwtezmxlhpxgcumuovjxqjjmmladstggfsderaakwgxzgwfgunxaqbwrttxeavnictfikgekcoqsgfmaihfjamukmjetsyhtogbbgfccbhuymqempxdhpqqsrqbpjxcjoztwwhbuhbyvggsagonkwquh','ntlizmsqrbrpridwlnbsarfmmhbajibmebscgrbdvkcsjgfcdguaxgxcntzmjkmphaxhhqjpkieucwckbhuatvtpewwjwqftdvzrtfwmuecqgjqkyrdaycitvbvdbetiiaqllhybhblrwfpiglpczelxoczznkugnenscioefejofacdqbicvxuinpdesmyguyyrmeshpsqvmbknqqsajtzhuddajgadshwvtjypbbjcizxih')
+;
+insert into t2(a,b) values ('qogizyvfoorybtmhhoeghyqeohxjwtqtkjvqjkytvaanungmfldinqspllbwpvizofzwhslzqrzwpqyasrxujqrcyqjnemgtcbwnwcephjjyfjccbcbjfveymgiuvafycxrtfgfzcyeyvvjxiwtyhxskvrmbkczkvxygqozgogdnitsrbbsqshbmxubvtbxnebysrwogyewrmnsyfpibtubnqzrljlenzefvhpyvqbdlvyb','habttbszqvzdryvkkaqnukkumlggekhrmhpblmtyiqjrifopealrghrkxfbbeskyeswnmvadgpwwjfufgheqkepoqlyxginqmyygfefszrhgkaqbwciirjhkupdvtqqgyuhrsbwftebrkoefeuowmuiihvpfdoyvsinqwiqjuuilzsodma')
+;
+insert into t2(a,b) values ('utnajafczxqwkdsslhxdzbfuwgtdiyqlxhrwogxoyadqkhcesyzzrrunqyjogqztpsascccaaqifwvwwlrlirdyfznewrskosqcuyeqgvlqkduvxboyabdsvvoehusrwqnvnehwzlwvlifkykkithtfaoyjcumbjyrrbrqgoupvqmxlnvbxzpolniihiju','dysaqmpidplushmnsarfxytllefvjenidpcrcarjwpsstpfcawpctpkhftphmbnzwggqmgapzirallyxvyryvekiwviwzaqylebwawmyqfnzcttjefddcevspffcirzlsdipramieyyikb')
+;
+insert into t2(a,b) values ('upgedmvdociifgwzjhgmjifqfcfbkbpmqvvvosryxnbjacunmkgppnfezjgozlvzfvuohtbaxjkqhhthxdbrnlvivjuuveymshimxppjikmvne','fiogfucjnmiqactmkfoadttzkzfcwfvbhzhywblfxnipzcyihbeijckmehxitdlfnagnvauujagesfgwhzdzslkfbayveykcbga')
+;
+insert into t2(a,b) values ('zyiavnfhrsvgnhyxjxutbvqtuzmvefzsyxmfxqfxkejcvwsqlvmvrqdajkbtwhsayjjwtzdaaulx','rvtcxvntcqepkkvbbldovbxoerlybjwqryelildeimhmdtaavsuqlpbileqccpopgbxxvbgihbrjqznuxabyfowjzijhlcpuryhtyxjbuwbyrcabvfdhcypbglbaoqyfjlpk')
+;
+insert into t2(a,b) values ('xeqorejcjcyaosvfjthxostkwipfpibijgpanyrjrmrtubjqdwzzvjfuttnehxmqyngpwfokwqugxylsongavvsormlimdybpbkiuywpdacxvxcvpwovnrrpoltgwjbhgwmflseiaf','dxqowppymkwsvkxcubmgzbkgnhjrvsboqznunmwcpalwemfjbzhevptzgitjipywauissqhgjjxgahckzcgxueslpowzpcjixldy')
+;
+insert into t2(a,b) values ('grpmjricdymxidxjrtxxrccyewkdxagddqmggxnamughaaermitditfkvafuzntyqathcbuwguzyrmshnzpvckmkzwbwudcuekahhxkkvxoufdsyabobvklwbhmmsnqjjbzlmmidohvnsiavqocsfexyjanvhvmolcqpulrugpvivpfuhvjjecxzghoacvjacsjyrqsxdrtcyxfhzzeyl','nvjaouvhxzfviimluqfbputqatbkluddoxrpzalxhmunpkemkcxuitqxdewsigegdx')
+;
+insert into t2(a,b) values ('ywhxvzjgjsjtivrosdowbegjytmxctohewegg','hnwhuxuvyloinvbczzsayuvifobtnrbnsixdesuikpupuexzfepsirxfkgxzxostiqi')
+;
+insert into t2(a,b) values ('qhoruvcceocxmnllsxbrkqioahhewsvtlkqgxwhao','uildltlhtxggupnkaqxdbmbzpcjuvpbhitqaqullkyhxrdugtwzimuxzvmtgflygaipglneovbwxjonycbnhwwcbkpphtqxkkcdiquodcdjunoafmxgumbqmufiuffrl')
+;
+insert into t2(a,b) values ('wzjhfnioagbaejcwsldozdgmjzxxnanoqmezrpwixcwolwjvokicwfmaxodqzthwbhny','auwgkmzfidjkofibkthzouwtclmxsyyobbqkjdsfprcksjpwualgmgdhaknidginrmcdylwqpguklwkmoftolklucofpjojiutczhnvzzjlmjwijfifhbohrkiwezxarnpx')
+;
+insert into t2(a,b) values ('m','yahqbpvovvcbmvuxkfrwdwtztxolzskvqsrdtskxadraveoutiiukwgseqmjugqavnlopavheojbsewxhozvkgrucndlgtymzgwfjwlucsgnodyakypmvlubkdvxueuxyipjvepspmqvkdfvtzmcztntgnhicrfrbtdwdaqhzncwnjrmjxtyningyfgdganuzlxrcnwppmumuiwrvillwvyxzzrjlnoibzzqczzjx')
+;
+insert into t2(a,b) values ('rexoqipanvpiicswwwrifbqsmgnqwhblnyfipy','tknbdhtpwdmrmzxkwzuehrkwqfqsbgwvkmwuwyvcdvbmpwdgixfqzzcddeazubjcxsmyzxxewmeyrihukdasktegylglwxsjkcpvsbakbcwbjirqjzfcszusfghwviybyzrdaufwoqnfpeul')
+;
+insert into t2(a,b) values ('yczmzzekewqzuhntenuvoyzfupbomjdfgqahjizhmhccybszdncakptlciuajseutcekwxxjtvpwlysghfqqqxfvliobqrrahtqdhuvhgjefwjkmcqxxgefmjdrsapjcgpgurxnkubtrvgjmzcglejwshrpbmjktdeqvmslrhgoazmrmynekgozcyhmzedfqsbjqlby','xgvldinzispmbkpyozhtkbrntakkhnkuilkzyaxgdwovpeekzaedbudpycuwifstileylcqvgwnggewhsomfsmtavsjoxgoeloxjcodxnpslvawxtsmicokxqjgwtnjmbelcsladtpwcwlohmswprjkuwrubzdhzarakswgyo')
+;
+insert into t2(a,b) values ('mjozwdblqkgbkklsazgdonjhvktwvjtnotwacgwpsihdmnwbemgrmqlrlpdurxmjvdqnylyxuxuvugzlsqiublnsytskosznrbjresydacfcfpvuqtjdcvjkezfncamcnilpjfspuzdkzluktchsblbkqcwoiejahdu','odrbtxniarflwgenotxdlwjpsghsmjgvojlzhemzanlnoftvosufrxoszsewnvvctntcrstfeoruosnrohogqdnsozlstvbwxfchqvikhovxkwxsscfswftsrafeuhj')
+;
+insert into t2(a,b) values ('dftjnlkqfjkchmftbzlryzqgodculylcpthtziurdhailkswmcctxfhzqrymrmrvqxcvsxladbbgvqxdrbzbjgjipaypkqzuasqsfvadfecizdyfgumpkmihisdlkjztcajwry','mwwqhkxbbxrmnattvhahypndsbeydroyneejmwftuqnlvtiilbiksbwgttkfhbtvrtwpstqtp')
+;
+insert into t2(a,b) values ('atqxksuhxgwafeyoyppwwqxxghbbokiftnpvyzihihasxvoinpaxtkdzwjplrsgrscybrjuvzwxynspvnmgdkebnmyolickbwqahwbedqzkngghnoagiqlhlpknegsnfkvbdaaolsqqffcdozgpghknrrdegutxweqeotscitjgctvvtnusxjmactlzcedlcwxmjglnqmmnraitbdrpkhfxivqehejuzfrmzqudbjn','kanjsxrdijbunhztawmhceemgjebotllayppggqwqgolfgnmtwgdctxnmqsumzhfvuozpgwtpwaasfbqgpxadayxibqxmphgsyucjltcbfyxvwicnuanqhnjwsxsvtgbtsyidawoojmaacizwspwgihmeatbbncqixscmwqrgtmngifqbhudruyqsncooluahnenfdsqacucgkadgraewkgikzixesniqmjfjss')
+;
+insert into t2(a,b) values ('iywlfhcsfhbfqafvjyapwwssucgcygajhkufvmbdvxeeadulpannqrgnsvtutjzkhjtjharzlwlddyxnhbqeoccgnpuwuzqhypuotnzqfsalqfpzpmlthurdvsywiaoquvuvxjnjcpmfbqhpnb','qxmngdwpyjionfcayarpdgcvmkuovdvnjroeezkerevrtuutjjkhpkibxtqasetsfzfzmlmlnizjsuzipwfxjiowukqijcvfmstqsgwklzcroycsfzlieklyonclfxmanrofzightcscigtohtajekydchtzkhxqlsyuqxtygvrbchhiwvycesyslixyaedvgktrbhbfxmynoqnsfycnsjeojbtpkkhxvdebjxjczanot')
+;
+insert into t2(a,b) values ('zljrmrvciiljfxhhjdjqdczruwfqnjonpsjuocitqtetnklvjqvcqatmncvtjzdzjwjaqavedqfcqygvhzskyqrgemkxqwxbbbjytcbaavfqsdywukzbxwfnqqibqlybrmvmrpcpknfctunuktmsgylfwewmevlhliywryueytpezychgf','ocnvsuofutlugdlrtduxdnjeivytaoiwooftgqeemvkqhpdslbzmtmkeeotjriramnuilpufkkyox')
+;
+insert into t2(a,b) values ('zvohecgkzahqsbtjlxubqaxunvsawivixioraslehuptioytewnwgipbmyyejjhkwzvlvovdlqxbfwchyagmqtzwxmdfrnygtvdobxqiarnsgttuvlhgethanlotvmfvcnymmzwpaezoxsaqzkmqtyijfkkndvli','jhupibuirmfzhuewdgcgftegtmhslffpfamdbgotfpd')
+;
+insert into t2(a,b) values ('bdgpjzlhwfdvdggstlfjjvypxvgfwpwvownmakiagclktgghxfdixalzajmlojhbwflxodmmdmykiryaafrhmznxrtzwggwrxq','sfepxpahkmdmhxhufyzhqdornbundbojnzpiolxogelgafzwwaoawxuibkntqdbcrejgwadquepiqtmfsisopwvv')
+;
+insert into t2(a,b) values ('pjncauzyckdhlrxyqcnbxsdrkrqbzsmreqgpvwemywwyuwvmsjpblepfpsdsweccwiqpcuorblhsgmloyptjqxutokxbmfificwhgxplkwcthyollguhecinbfbhbawnrukrjunanrghkzlqthngjlvmgzlggbhtqdykesbkyopttbuvpmcygtyfyotfzxf','kmlzfctrkdfcoejshcyvzftgfopbntunvpudkrrdegacgpulxulxsbfmehcaudrnxkaxgthjqpeaqfibzhqhaxccquvshsxqaxtitrfrorlpdzdurjrdrqwcwzwuijszpmdfahgybmfmqw')
+;
+insert into t2(a,b) values ('xmbgvawdfnkhjiuhkgplcgqyxxtuqpxuqasretxbegpkzbmenfoacazzsjpexvfucgtvukgwwoyplqbwdzmfdjwbqtrsgycidawfnhtqomohzhuqr','kxxryjleufmrigtdmdzwhvqmvefjvjyybwhlpdaidrqwmcttgbzlbxggpihsfglqlsaofxrzvysvoocfbjucycmyyugqkrixtpjcvrvbgjvfntjborixadywn')
+;
+insert into t2(a,b) values ('smtlhifoznutywjrrbzcaazbfcrqytexpnfwrsixtedmonlypgxboqldbxvsqlltlhwxhujznkkcuakcoeheiiqnfoheyrtnevdkbveywrwxjleagaejsdyaucmsakuayhudxfrkkgyxetnfgzylavxemtpwojanblxncighixtxtwj','eaidxyynwzpumczhnenhswbhfciqxsbxdcbsncqieuiogafagllivknyndwyvusogqfhsfyqgqtwvmmyqpzsupudtjqsuwqexnoocsymszgy')
+;
+insert into t2(a,b) values ('dolqxcuiimggxjotbckpzehmvnbdovfuciuvgjgpztjykrhgfqejgulzhqxjacvffvjfogcejuaujyapzyveyiycjzjytdkbuosaftclaskktijikjwheiozbkqocmuabhqrhwpglyqvzrkthavkcytyfbzpjrtoqtdptgiipjlhoqmynvqebttsxfcfefgohbeasrjtonsoffhghdsipdldjrjfywucsqmndpifidger','eafwsvechaakujzpbqbtwg')
+;
+insert into t2(a,b) values ('cwxzgriwjbmvqahutwviovx','csuogwdurrozzghghyupsgmyrdnjttqzfhkgrxvvlvtkszpxnifftaoytyukopqjeehnccmlilqkzaiqdlnfgeccyp')
+;
+insert into t2(a,b) values ('lxqerlytqnkyhjuuggumwgwfykooklrnwctqhzpwfezolozohmnpoqfsugqnrkxkfawrabdquhuadnxvmvpuvebyxyyrpaqzfodpgyzdxnnqnbomjqqnbvpfb','sgnwcjerkcgmnzrhbhyrajfmumfmkhcnlnxoxxbuvmihjjebayuevmzoywfjxcfsjwslmjhsgxmzo')
+;
+insert into t2(a,b) values ('ggzuqavwmcjcqvqlsdqbsgmurqgvtgatpjgascaqjmtsnoothawvncezozwutxiuteoqfbdhrqxtsdnkpjljchqppvgtcjfhwxtozgdwlsjpkzcfxykkzoyybxpzydpchcejybaoxkxxxaqzovvqqmxtdeiatujlizmvmtglmrszzdtegnkzviuasgvotbaeasrqzlmkkpsbqfqtdlangndureanrwauvadbhypqkztfldbngjwvtr','ixhpwbfrppbbznlkufusvnqrzywejyxibiloyilmrnulpqyglugiswolfoswotkbevuoterjvlrjhkkfqubgamkrbkmyanpeuegargslawjrdbcymitmyayfkfcjyuqyswjpmzylfospdzomuxkukicdcmpalaeymdrqfpgclypodsxrdvfpuszrwgtvtqbqusrqmofbfkotuymvnkmvgizbzmkvmi')
+;
+insert into t2(a,b) values ('fqptoadylibuzeqsqodapgi','qejgkqhjnkspmtnbnhtecskgeytbfwzdiyrzrrecmskoighazltomfzjidowvwqblznthxywuixcglvmveyqnjoibbmmxbubsbheqcomphmpmgemsxwuwcosbkojdvzbhprzioamgezhzjlvddbtswmzznoyegyqmkvtybhmfsuzfktzappwdvvqe')
+;
+insert into t2(a,b) values ('fcymlqrkizksjsytfzznkohtdsrwsujfuppdglepevheozabxuzlwauvhplutvlcwseqsinbtxpwpqmwittndihhzdpaiuujldjhpugrpvgekwgyjucvnptutkbuzyeqkoguohsxhowbprlojpqdbuyoiifqgqsnyrniduoglaeyskolzuzcmkvqoctgbuttqzyveewtjeyvldztgkkampbzu','kiokifpkbojlyzijzfgpsxboylettaygqhyqxuvesqinuimjgyiuykxioxfxbrofwnxyvvqjxhszwinujqerrvxmczcuxcmeguuycrbvzewvlfapxozrfcngocaodvfcgtdcbxjbqabirjzgtlktplbymcngrkbvmufgqkaeksdtjugdewvtknfjwibjkdgtaktttzoohrlgwhmcn')
+;
+insert into t2(a,b) values ('qoavmoxsqxpynicashozadxxveuqqjvjexykrmutpkjmdvnemjvlqrsjduoypnzjkftmdsrjpbvewzzhmwjwqwprropjvh','rzlnjblkklzhjkvbktszlkmkdkqnjtuxaqfszqfkqjiumfpidzfwwqcremcmemdibkrwytrdidvwdyljjzukqwgoylenlshfyrsbmkvuqcmtptxdpunbtsubbzzxzpguvffxctvbwkobqewmvgtsspbuyoxsjeeloioxvhdkycsavwhwtevslwxgazv')
+;
+insert into t2(a,b) values ('dyoxyavtvutxmurzpqbrkypdkvohhzyjngplxcefxahjkivxfcdkjkbfltrmmftvsxfozvwulopaaiuqgrxuhixukkgkydjytegwisnpcpozvurbebuleynvbaoqawlkerudvslhikdqvsmpxnaahgnslvaqocbqirqsucmspztqgystsdfxylppztaughybyezvfaozzdaxlgkfgvavjnrkhqkofgamcpe','wwxsrcaiwdfzbtrpgzjrtenjvdrrjoxfwnaoxcbrljwjhxkeebrpiobkpzjlzzmcbursdjfxltgpanyrfinkapoccxikgjqrgnnqdvusvgsrmnylljkrylmwvnvajmcikrsvqemuinwawzctkbsoqcfwrmclkkrdnufkegttidkgjdrzwhvkempbxicpptxkyttvjalpjpgmbpdfimcauhtyosspvhfuksiqiqxoyyazobowsdkravstku')
+;
+insert into t2(a,b) values ('nehuusaywaayqdrxksxnahjd','oklqsdlmtsgdunyutscylhlxrqpcrbjmweoxxuumhdxwxlcdouwkwwfjbddrjmzfhiniydqsqhigfvppdxdvabvssjaykfgryqqiyqwgugatolfehqjrxbcggdzdn')
+;
+insert into t2(a,b) values ('lyfmtopisaivkbvejkjuzpqwzuoffzatkjzqdjerbupchgqiphmraiomnddycbukpnecndukzruotkwonybtzanywpbridtwzlbbecuxfzabole','yeibmhatxgnkuittojqgaukcbdgoygjystjqxjaoemkxuuydtouquhxaszdtqvqulneckqgtickcjvwnabppfjvqmtbdzvizxoeofqaclonfvbrgaotktfeppwuziptdlywmtlqpinvzlvxnytvqgsnihljjjexdyrzdvyfzfoeycvnajwcdwxwloeweghcdfqbhpbfnmfxjgmftdjlnfuhrwezcfxxpbgrymwifezer')
+;
+insert into t2(a,b) values ('vanipeeztuflclrkspgvrktekepnx','ydjskpzkorfjpqtikqfkmhtyiynoadnysumgovwrlwlohfedrrbexewialqjafjwdyevymivmtolercbsxubsnekkhkexvvkdofvblehqlyhbrgszpgknwsiysj')
+;
+insert into t2(a,b) values ('xajsovkjigkzoufhsarusmqiqztrjjvdyxvvsijmcuxstedbyaocbblqghamyztlthdwevlqqdwpjkqdioueednfubworjaegnshjawbhabcmxcdrgruoqhdiuqgnsxpziesdjhjugoecedysdsuvfbin','bmrcptrragzcvhkdvossbyjibmcwtgihttrvcaofkhonumfpqfdcsvrreyzupyrgljwfdovqqdseyzropugglgrzwrzvefjjwmpetovvakpiryyahcpqbmzxmnvfvfmozukbswccvobhmbulcfzzcgpqrypafthc')
+;
+insert into t2(a,b) values ('ctokpohiqvgiskbrlhlelffbjfzavkzvhnmhfbvydkwbnzkvsxplhffveqtkbtsikrofwrxpyqxtknhuezuddihvdcezozbftxvypnutlezgrugcntuurqrksrjfzhzsipahhilsumfuznozrzdqpwhrcgcvgqsdvrkledqoiawabotilfusnwgqtsroyp','vfjaouquekqhejlflveuqxwbfewndgagnlwqzqzovlferoeifbyhfskigrokjdabsmfpykmxwyvxvrusspsfxkgumwtvgkfeirocpdv')
+;
+insert into t2(a,b) values ('zeajadqsqohpgzcmdaxnwzfjctuebqnhxkiyadxnxncvfvqhpilcce','kkwovxlgmqpjcxrfixekgnyejkvxksrjrqymlniiqhmdijozpmopncalnspbwxogzjtvipzvoszsbhirslntlajwfacqfdvuuxchftasumruxafnfucpnvfqmzmheilaind')
+;
+insert into t2(a,b) values ('szznpnvlmqfyvoswvtlqoawznvtxribxmyzunmtbxfycitkextpwknkqbbezuoeqamhakanddvsilwevtzpghfktyayahlqnrxsjqctztkdeihkvlimsftgdeakqpyraqjjypkurogtjwqiyulfjizzojfqlycweqhqtxxlymhfmjkcmmghvipdm','crpxvdtdjgaxwqtlqljanrvdrcsvcjbnazdebekjmihgjjiiqbsnmqgfccjtqbrfwuazvgyhoiwsbeplttrgfxjkoqbkubyhosaqyxvjmwhvjmiurdotgoxttysmssxemtpzkwouoqseqpbbyclpeqyrtfp')
+;
+insert into t2(a,b) values ('yttohbxfvzuebzauwklfxtegajqhtzhnndxlcparzmebrggevtcqjevkhcfhtnecujnympgocmdrbwfktpooelzaosvuosya','bmewdwimyqiazwbxjlxifugqgqgyaknklngvqvw')
+;
+insert into t2(a,b) values ('thyyvxflmrgkvjqlmtzjokqdrzncdzopbmpnlkbtfceftsyckalmwptiyrrasovvovxlopmpjqkuhyyrmggbiduebjmemjoinqkacymmfypqivocubnkzgaxpwplfgiyrzvqcsctkzxxloccvgentpfyvcfjibzlqhnnmxotqlipgawztwjaocgfztnkytcwpxljohtnrh','phpvqwjfvkkroajzsyjvpfrdignupigvugrmquxowbaokgykzvgysuljwdswirfw')
+;
+insert into t2(a,b) values ('fzzkvdlekfvaptnaorialkxkrkvuumwsredwojalddqmkdroegqmuzdqamwhszpgxxdwciohuihysonsywfaavbmtctdjiszqfqrxqsflrmodmkbnxpisyub','ayepbvslhrpjuaaueqarcznrakvnkgoanavaijwghlrjmlvkwd')
+;
+insert into t2(a,b) values ('rhfhyikjjerdvelnxkziwucpcramayxqvweflibtdlsafprhnbtmgcvmeppgaeshhvqugmdwthkyl','jnoiiesrmpoeqaztnsvxcvfrvcuxtdijjhdhklwxqowtgdzvpdbhkrapqvphglnkbichnarzpdeejvaaf')
+;
+insert into t2(a,b) values ('tfmxwmyytvjxmvfukdwgbjpnwdcukmdtzfkjbgoebgkdd','ctpyifpozrnlqyhzjhkpmxsslcvpftzbcttxsejoyqlyygsninxmtcoiixhvdgnadckthrfiqxpngctginktqtkfxqawpgyxozifywzjlwgnsptsuiikcugpkssxtkfrlnwyvpzxxsktp')
+;
+insert into t2(a,b) values ('zpvweysojybrgaivijngxxrpvciyvargimztjhmtutrtjuwjljshtwgzosvyyavlvq','ouvzstmxnwupoeghqqahahwudardeqbdhjindoyrzlrmstyyykbllvcgilxyd')
+;
+insert into t2(a,b) values ('ugajjmdiovwmityueatoxgqprxfvusmcsoxemnhdccvcmtlrliqcupyhikgcdwxtzahacyzgmofrjdtyqnohmsivddizotghkiyenslqtodnnpolqoaujztvzayxmylpyybjvqkdzyqulquxxlnbtnzgtnqqzbijmjtchbymdtffvnghnodtvaeuwvmvsacnlkzgnuvqklkljkepmw','wjwlnqihgxhyjisklzshoffdouiudumrgipxeqwrlwveylmwydomfihzebvqiuegsttaerbrlyortiuasfsruvzcfohzfxzzffklujtfikckzxcdmlsjhukosbwiibqefepyabirfxyeueik')
+;
+insert into t2(a,b) values ('gxaa','fzgaqu')
+;
+insert into t2(a,b) values ('ubnwptgotjqsichrmlgrrrkcmziokokyoaiybmdtfyutlmfnjdagkhksfncqhcynuizppclcslglxldixgjvewvtxpnjgoytauyrfbgbmcgesoyuleeqjdwvkhtsbjriupwckrcehrippbosjspwzkfrptncbchfniomflywykehzvsennxaiyzlaoclshuhymqcwfmxibyp','qzajxfjjnofnzxmattvanbjgtczehxkbkbulsxbbsmnpfrgpfc')
+;
+insert into t2(a,b) values ('mapxlhzktvqcyakewmvblomcbphqnfjxjcrfjpwirovbcbkwzikkrfzbrlwpeygrzlwqwkoquvjmyvzrhwhqnuhoewrzzubwpsqlnrucphsyhifddt','dwridsafsakimtstexvwqxvsvcjepmgmybxsxbwpg')
+;
+insert into t2(a,b) values ('tkmauuhoebbnigwrfatvnqbsezyrcnuhojqcrcprsevaoxervznorklizfmhuovnpkqpmzcloxfcbcklzbjizpfldtybetjrmsenqmzsplqyqhrambibkvvhuoiyuoeoycoylxzjkfgkblmhoswyuhxlmnajphfewmbvbctxbwcmipapipgsfyzivrmniwunfrpdmxmqjavdhdizpxjraqofefstsuqpziwexufzregegjqfcvalrdvbknoo','oivhjemjeiwidwucmzkosjslgxwgsiakxujuhpphxlnofbtdnkrpjgdlofjwluioerkoqwaccutebrsxofzpspfffnzdqdwlyguyspfecrsmoamuulmdjiiojgpcatblssitrmjcubrqkfwyghpllalqxowmfshelhieezfebsyluiqxctlucvqfawkxqaljgzpczctobtncpcwfbgnetprj')
+;
+insert into t2(a,b) values ('pqewjjbzcboytzhtlwfeiczvxckulznzunvdslsektninrgbtmrefxxawtabnzvncremdeougsdlbgejkbztnktetbclxaxplgojafsthhylzxsybgtqnvwxgpxkouiavldusmoasqimfpzw','qfsqnpklbdnxtpmxkvhjbmjrlexylxaocfajxwfvlyqpieuneranfacvligebymfqatklaorzgzmmvqusnjfwqkonxaarhhthncwnftbsnqpuevanqafpsjprsoyisjltxhachgsstivxbpnfrgatowasrmvsxkjdtbusnfprhaamulgbhhrflhieflusqisouprmnliugqlylpnrgxyuraddpwluuwngmxayt')
+;
+insert into t2(a,b) values ('hnbmallmsmctvklpkzeqcnjpuxjdvtjmuxrwomyjifrfayqsehgohlgpfunkplqvvphgkyrybwkbewpcmyrkgmkjkdt','umqojdcykjimainhkbibswocrqgdqrwvzxevbwurdisygsztrisgydsmosmnthygirasqtag')
+;
+insert into t2(a,b) values ('urtgbfdhwvnlpbzgrdqsnjzgxnjwrkyyhczstleoauzlimbnofzbzqppsptfaexixwjmivfpcybpxlpcexolrjgumojdbrtjckpuzduipaempumonxhtthzjrcfbxshmhevuvfsqbexcrrsaefwahwehorlhjfpaeagmhdmndiawyrrdvameinmziauajbfzetqekqqifjdinvgykshfaommubmoecntevlyyvfc','yogexkvwjqjcunlxdeagbpznagonpqwbaeyjrwjnuapnevtgrganjcmis')
+;
+insert into t2(a,b) values ('pladafjmkmmyuggnoadryyofehfcedgwibrtqbelkoqoswekkrexeydfwwccleuuah','pgvxgjifrphltmllzvoqximxluxgbstpweuywafsoiurlrvvesjjzkigohhewhgawlgvfipdgdpjpijaqdzvkroerjzjppurtctbbcuq')
+;
+insert into t2(a,b) values ('vpjwlrldszsclisymreswqaeobzwbvizsnizveidcgojtwabntolvmlwxqabtezbyfyshyinpfanpfevuoqqqchvfsoexddqzwmsgsjlhzoexkvepxxiyg','torkkuvcmxxpttmnaubwkslogpadwxmyapyqdgfotixjzmraigtokciphmvbzgtgynopwehbbcbinesvajkavewpekhqcbscsxzbnxhzmtlxjfgjdhhqeawzvvfsuqpepbcjhcemclmsgohpwxtsvtgtornbemjdascyfescuktfpbjkfrkbhvuhv')
+;
+insert into t2(a,b) values ('xtinwuhevolgvixuszixfkmzugmcsiumoxphuwhkmoafswvctksfzqvigvjejbnwtxqfhgnnpzuayquokhfddcjahzkdrtrvfqtezxfqexkmywsqzbnwezfajnfzfj','rcilwlkvixuuzivgelpbypntoisotgodwznuhobladwiktjkvispxjcmujdfsfcylqdufgdkrudusaovnyfckbblpdgrmgrbfxarukzhfwbkjqveqapatemfyxpmszznkvcaifcnzqgyieykxwzyiygwyfvaulaqmgrlisoiabvhjbsnvhllyutctrnaxhcqouesnchxhchvzawylblqthmhokzlkwbqlxmalvovppwsfpio')
+;
+insert into t2(a,b) values ('ekdjyxdethgdlpvjudomupqbplwhvklpftucucdevqknxfvnskypazcrhnwqdomalhstykhirrhlnqizlknuzoojvmfdnsfaxkdhqbtrmuonkcqokhejrcltlahvjgnvepguvpgxxfupbwaohllhajjkxbblhvshjheatjadsibqfsitpflpiiqmnupjpamcrweepxkkubwda','dkjnxpmitxogtgyafqabmvzhtjxwgoomfkxwmqptechismziazvlkoctvppwonkphdmfrejwcemvvodlpqxofyufjkmvaxeywlkpxefhcjzjxmjezvbuztacmpotqnvurbmcikgbbedymgjrpmjvqmtqebmyilsgqfgjkxovcdokwiikydaavpmwzjsaajquxanpmjqklumsmjnugjjfqsotfydvaheiczo')
+;
+insert into t2(a,b) values ('','vytyft')
+;
+insert into t2(a,b) values ('yxceqhxdxqgtghvryuuxhzfzsmewarlgjdxfabbespcdjyhyuilppvaebxvmbwdowhmniuzlgeiwdqyxnmbdquegmxmdrktriabrindmpy','mn')
+;
+insert into t2(a,b) values ('rmipybrqutoptqximywxzpqyysepvyhgjprvbimvnladwvmjfwzyoqljffthpojfnyqrfvtagwvgiycsvoolefvyazxfnwyrxkcpljqwsnialcdmrdfroloezringk','pndqewswimmctumnrqrevlcchblchdmwbxyeizym')
+;
+insert into t2(a,b) values ('qhxsxcbaimvvaotsvotfenhjzbrzcjtplqgwuczgsklimpjgyz','hcshqsuqmxtqhtejchirmtpkvrzuqxarknmsfrhtnxhouagwzffanvrdbgttqdpttyersueocdopwtxwhvevwnholaoswtrtsuyurnbglcssbueuoieocgquvdupcgvsqoekrojtgypuuwsin')
+;
+insert into t2(a,b) values ('kmmwmoywmactphmihrcubsepurhuspbidflcfthexkhesxyhisxtmcpdwkssomcxizyuqqnlfgkipwpmkoewljgubfqdpgyhlvjevflntxoxeadhboaggzgexeoznjyfxcfyiubdxanthhgjrkaanuqolqfnajdhhdzoxxngagtuozvljvewgshjinxceqnolxbmtqystcjejnrlifaevrrossrakrbafthhplzyzbr','xqtqqfrghabowkrldagfnsxvaulkdthrcsetfcksjfhpwgymmvmfeygczshtwcknpqtkcbjhcb')
+;
+insert into t2(a,b) values ('dhaxbzrwknvegufwjqpweoebv','ywjzrrtpafbmliwvzlijeezhipnpjghvberrwjcmxnzfwrnhgecjydqklznzybfpwpjrwdtliaxifpgrghxkcafqartcnogjcwejlcqezjkclhxyphjwbpqmkaoseyouwhdhurfggowpgpmjc')
+;
+insert into t2(a,b) values ('irddqxwznigsqovairrrhcsykbrbemnqwrddnyclpulnncrmumvmutzvsluljmqkrawlihjyypogxldunfdhgyojgamjenvxbtafkwcffztijwmnxspqtqflpyvpaiczvaunljesvdkhvbkcnsluvlriymlvtpkmcwevpistm','mw')
+;
+insert into t2(a,b) values ('didkvflczubeokrwbbyijimirouxzrftvjxewvbcakwhhvonhqkqsqkuupvddrrpgtphwuntnteocyeqnapxzhcoqd','igdycdspersjlbubvegqnwcrwwiqxbkumhlatytbtwtprsqicmhkoutcifwxkbwjodbcgrhebduxazmhubxpfpzjxtjdmdggyxoqtyoneggyyvocqporhaeeuaguhodohgfsgjparpncxnrnzeiqujfscexbbaanehuigiqftyvfnmbigagjpp')
+;
+insert into t2(a,b) values ('frslvhkoykqktlxrysuvtiuiwuecmeszukoivunaencodfwqdkphaoylonebcsijgmacqytupmjfwaxrawtbrdbegxmrlcmyfmnawlsuiqpudaitygggvdzhwqvlpaxvjmmpszixwrnxwcnz','ubtdehzovqadpkpumyrzfrixlbyttpybmffslebbpevfmmysesiqnuqflntnejocoxomztzjyfcmbshuykfiflqtijlercuvnvolhnnvypyabddqpqlfnigsahkakeyjbbbmmdywcbvpekdyqajeokhfksnfqazpllynccwaupdmysvqkgrfmzqnrefszkigptnqmfixvznj')
+;
+insert into t2(a,b) values ('gimjjrgrgfiohazissypmrwqzafsqqvpnxposldhlysdaoeuhxyhtjjup','kjcxotuvusglhznkvibdqogmixwme')
+;
+insert into t2(a,b) values ('rgcarijwxmmlqwlgejkbpqntyimwzvjlxfzdyvdjcrmtbmbxtbalcexlkqqqxoafdstbfnrlyzmdqnoquurfphwvgpvabtiskokmznlhcxusknltgghuc','jcwjuknozykhcnapqqbmtlhoryqtnnipgyeqlqnzhgzdazoahydsiiehfxqilxzqhndotyshlrodjkontpzplgedzouwtegnxorpboskofpytbnnnwcrgubtcbodolyglpjxqjodnuikyazbmzdzhfxgsgidxajqjbqizdsdwkgiohmpnxocanxebju')
+;
+insert into t2(a,b) values ('sjtvpwdwqahqukutafihsxxnxkieqqnzgxllqotkyhedfbyryxjgmzupmprgiuaxxhyardxxuygwfareqxnvoizrowoeeruynpgyohyeohsbxxsvwpsfplhtsnlztqxaqqxfozkgshjjdxtuwiotnfsbthqpwzbjwwvdmlpzierkgiuaruhxfvahnmpcqytevvqsqahwkjzepdjtzvfdaavpczlr','bdddcnsrdlzmbyffxagqalwbyiudimifvjgfgwuladmnhnqazuisqncaqyrkubjnktqutqehylplksjoijeqyonhmayuloiafvjdzruwlptiqfbqxvzruorvhgdultarwnzirxmgrfowykkyyneozhfckqayrnhuznzohrtpftzerlqfgdgepzbdewhwnistqeahivqodnngzgaoxxwkap')
+;
+insert into t2(a,b) values ('wummyswxxhladqkfngaaudlbsniisqenarlinwkeqnwbbydiqbgdcxruwoergzagtekvpevjohobegsrlautnnlduaywrfyloixzwulqjddfaluzimuscftloipauarvqomdogrkjzbixhrgslggsqzgwkhprwpcmyvlkiekhcumkaarfc','yhxwmckkpxnkrdkvvflwxmjfgszelseulqyikenzmikutddjdwnzhzegpgzprapxrhkvprjcjbaaqexovztseaeuxmzgxnkemlkijgugjpmtzfhlvyuuketlinkqpwqmanslwqhoikdpmllwdydtgigfolwiqvzvddnkniymhvedctrjrelubnh')
+;
+insert into t2(a,b) values ('aaaohhwvkhgaffvwswbsrkgacxhejwtoygdndiheoviqlhvmzlbwjrjweowmylgddspifhasqyfczhspbaddmmdbbwlmdrgzqlwiwetrkpinetwrwlefcmocrmmwejlchckfxvkziyqaatsqcjruuyfznxjhqwhhbmfyjzlvfumlxevlqolpkohiupkqpabgyehonqiezwonxuezcyrynzqeebfzyuprqkenglfkdbzxmxmhrvulfn','ykjpwosztqvaxzppoutywvrxerybabsbchhuxomgcwznervgbtcujluzxsedaurgijbqpuzbcjtqpaewxjgfhwgaxrpshlhjxvtdesyuxjcnrsohlfslymjfkaxskwjl')
+;
+insert into t2(a,b) values ('cckmnnuqgqpmroudnblsolacdgcudossitiryxvuwkyttsfbvoqwlyiaqingmoxuoohszlwgzssgsyaxedaltaboiwqmrcjtyzzhosggzuzsnntvalxnljtilkboygjtzeglcazvgsqcomrzewxwfvwyu','rpekarihcejdftbyypemmgucwuutzqibsfqkztknbuksrmnrevcebrnjigbohdrcnrxgqobtzicrpwfrpxhzxczzgkxrgwblsyvsodljomtnizrilgzbemdjwedtudyygppgkzzvxdruinjmvscxrnkibjcbikpzidchlxoevlrctziebozcnkaktudliqwlqjrjimeccrahlrnavnfagjjnjvruxdwknnqpykxpxqwycbysdmpidn')
+;
+insert into t2(a,b) values ('xsfbmfvctghmrgvcdohfqevfauxvpmdoyumrujkqgylqlareomqmbn','qrkmjewlzpfzueokxcwfmtzcvbqoupixljgpdqcxmfghbsereropmfkywjevwtptecwwpewblpouqhoynuvrnhvmjodttcqigbiqyalgxzxjbqxc')
+;
+insert into t2(a,b) values ('ufzeuoyvjlvztrbqmvgsjxvmapivbobmvzyitskojyapaqyvlecepcvtqvobgdmlndwddijrbfqiqrcdkivirbtqfgsqpmiawvmeoisksiwj','guurszkzqsnzpbzxalfsrqvbcwpspmzppcxhhjwijxsghgputcebtbnaaitcqwpzkjzroczouumufwroiyznlwaugwqkkttbbdfhidtrldrruquojbcsbuafamdguletxdmimckmhzfqnutojhf')
+;
+insert into t2(a,b) values ('vrmfyvczrjyeoqdektncnemkyvnbxhvsnmjzoeggbyozbhpsmumfpmvmmvrmuzazbszcszzhnozhvwerolygghxxkotibuggoguvcbzovvrxbxenyzjymniktcmpugqiavwmbiayahqzgeeodobksvtnkauanqgmcezhhjfapjsfpnnefjfdpt','besuzwfheolvjhvtwhbdzluzuldrxwxzihovizzzdygnsurjwrmrelvxpdtlgreuqkbrugnybqcqwxtbqpybejxoourcmqlqmvzgccwsithqeyciwnnpfrxlsamwxbtyzkqgivqkjewwemkvedxhfxarviyrruntwwyhwuajxslmhucpoqrejjbdetjykibtnbvgmilg')
+;
+insert into t2(a,b) values ('dgxgqychehwsnkgtpyxnojizrtgfpvwiomkilrszehogyhppqjryoxpoymwnerjohzngeacbmikuaelkvsolpvlzeh','yophucqdantayblvxzmjzbnqkbyrwsimawldsckaqzgyzntqjtpaxoqgamtxnwdkanuehnefqaqirxpcsdiviyieueqfwanjjqhiiokepe')
+;
+insert into t2(a,b) values ('tftid','qaaepfotuzxylwtagfxvwhppadtxehtkxnqdeligztn')
+;
+insert into t2(a,b) values ('jntcbxtwmtbhbaqifdpjomyrfeguwkaolgcfavdojccvywmsugmccsnqafurvylhumwpndcqlbcsnunoffrhpoeepambroeyewejcqamdnjxjfhkuukpdywzonnfayzmmlgkjklqljhfgjxzrogltcfhofgmalyaxzzdnxlbwgiy','tnlomploxvtkhqygbiopvxqhuntquahoknmlvaevuiptfsvdtxccorceudyxjdhnspqiqlxxngpaopp')
+;
+insert into t2(a,b) values ('oielwfjbspmnjtkvqzqmztlfsiztjwpvebxgbendluutqyjchgidrsgbyfpuhawnchgdeqwnwxmujgezicxaoiratfamrlvcpoykgdiynwewzydcqvfawqaoxwtfhzdrdsjliyklyefdftgwnmghkkwllluriaoqcm','fcndorskbicsfbufigxtewtastgwbvgeztfh')
+;
+insert into t2(a,b) values ('fhavtqjiffrrmauoemvyfemtrbupzgdqccahgmoritnsyglsfvrvonqrjhkuinglibvkfcmrjgdovrsuoucaouxewz','xjblhwxgbvqhvswqdezaumhlnwlwwjvegnkwibbsibinxwhmlsevoucosvkfisfanintspvneoluqajnlcmuoqnpojwrepdvnwcfmeumzmvduxesqrqvjzurpwljzlaaajkbqflipniotlvmmgczoltsespvjztlf')
+;
+insert into t2(a,b) values ('bzkyhdbacwcemddwsspgtqaeyavxmkbkyfjiuxtyxfsjhejuhdnkfkrfzafbaenrunnudmclldiiujfocvzdmpaunwiqmlmnieqzkuwnvxqfoksksmacxehrutroouknyuqnnqxcgjyusscfpmbodwcwohkspfxpqxotjkxnzrufpfmezhjodqxv','hezfcgaxyzpthjxhkzaccpjzdxhlckklgycmdntjrbjwmyytltbqnbthkorawgmssubiqwxqvioksqotmjikhfzmcvwebklylnxngvrollbeurduffhwnlkoecjpkwxfiotgpzjbkbjuzdvkpmfmqhsuanbpeoqvvtqmnpzfyjicjzklsdvwtrnympkiwejmhvmmtenhicejj')
+;
+insert into t2(a,b) values ('saupth','zuszrwpfpewigrdyvikuhapfpqpsaevabentlvijilaphamlwugabwuwaootomiuorljhyxdbwhkyhcebqltelqdhjbcenkrnadqkpckwvodfchgkkbpptowewcxicuxsmjoztdpkuurcbjqyroidhhwucdodiutdybxaegzhshirxllnxlghmcwnfhkpdvvsngrchndtebvqecitihnxbabplidfawxzeow')
+;
+insert into t2(a,b) values ('tbyyjqhipytxrkfjwkcyrbmxvrqrpwfpadpgyhcnukumxoptcxmqtrmrgzaddwchphedhnwahhmauwsbncrcvxjmezkgddijzoltbrndnyvgouvpibofhhruljxfttstuvkqypvetgd','xumptlpvtzeejxxnufjybdmeudkndtccqmeajzubejhivipkqpenobtkmdxxrwpixvrecrhcpcjprtpeqrdzdmgqllqwosjklzfhtqlxdtvxxljzjmodvmdqaynjqhrayydqrupsjcbqyaixroytozzzoyjeurknkgrkcqixdrffynthdbbfufidbdnylfjrqtkszhlyrwdnjxpdxugtarbwawdwjcvbvwurferlakhmdvmfrrs')
+;
+insert into t2(a,b) values ('ezzbasoegurrgsfaqdglkynctxeeaqxnfrwnjcxjrzyfkejxjrqdtbsvnycpepkypelnbgiujuczxzmiwllhtivghzuekoiutfwbncyfmqhunudbbykpvttdvqztshlbneabievcbwxhppbautnnfcgicuktjjivjayxxezgrdmwgdclfzugwdbkofdlxqtbiystbvzxyjjgraovowyzcp','fdofwllqjiownjfqjzvamlqkxdggxsozilorppykjznvrfrwz')
+;
+insert into t2(a,b) values ('wlyxufmhdsiarrpuxzpazgtirwoqbubratypjaebglvojtyqtgtpmvoojderqlljxxendkrwzobagmhmynxviptyxdzvuqbxfqevizkcodieybhndpablvmvdsdsnqfyzoazryiziktunejojomsgkmmqosmzabdhylbwhfwfxh','eqcaieqhzykwvcelotfafofknxwos')
+;
+insert into t2(a,b) values ('awedwsqdvzybachzvvfwdhhnzrkpotvngvjcb','bbaqscwwxzydhtswjpghfwrbffdxsgcakrxnrwimauhwuefwtsrosyfcgdrozcfkemnrpgcjoxgycprjpjzytfltqeooffymkigbptpmhelpojvrveyufqjqhpgihiseehamhyehclksfmkegvaifpwfowxpywpwstvtigyyrxtqblfylmrmbrkyy')
+;
+insert into t2(a,b) values ('elejhxevsfwqexnrswakdavxrajlnpexawpkskpszgaydxhlopdkwfasgfkyoidxvwmnycafuvoezeszkcafimifyjwwiibmkrrttznyrjnvkpmzdnwjvdgicffxkmyqdanlovvxltevdglvountdawrdywwiikvrwpmlbefkfsny','ukcstoqkqvixuzyrsrowonilleyuursroipgfwhvlrsllnwtqintfgvaooistrpjpmoigyqwyeyetkeyqftnmhybxiuexkmlorwjxkpqnzqyhglexaziotwwpbgedvdbrhtzwfjzjlbhexnvbhuapixkizejiswrdfwdtfydutypwheigtrcbelldlcadiwyodwazajwynpxgtargykvln')
+;
+insert into t2(a,b) values ('edqbvoinsgbfqzcabyhvkxrpoldbpwsjyyoxmkawsiqsouxqwbidzkgjwbvszhsizgqamvghegfgzmzdhcreqridqjbigmtaexczbazuvbrsfdpmmdqlxtxdoqhyfmojkjixlmsgrqanobmzyqdhreesashrqkjwqvolnqgtzacrrovmxggwzlwkkfzexejapxmiuuub','xzidrjpkchlflyeagcefgwptiinltjhlthmzzdwyuxexkbblpgghhbyplpgifogrjujnhlmgumoarerlgfw')
+;
+insert into t2(a,b) values ('vmkwcfpticjfujrtvqxpnzakyjuiygcxldygjjchvftlzwarjgjeylhkuvxsdcobjmccxpfmyjewuixwazqsiuknjshxx','ecoxhbkko')
+;
+insert into t2(a,b) values ('jieycjumkktiwdoqmfuepegwkmuorbbplbjcjnjaubgcakahlpopzmjhkoyehecreyxfsruhllrlkccfmxvutfrrruuqfqahdxusjreagdhnybrvkdvpchahoeuwdwoyyoecbrqqsltquvoqanugcltvwnzjteroqkfnuugrxktpynvmxh','tohvbbkxmoklovmsqhqxizvasomfjqmovaytyuvsfsywtxkdngpytpmkdhgzewnwzjojitgpbhulizrqnpapbotlfijgwdhoyyfwbpptwpnqxdfajydjmuhtpfnangegsimurocddbirdqiiqfvslropllu')
+;
+insert into t2(a,b) values ('qhxjskgejiknlxtarmtlecooufrtcoijzrvoqokvyupgahfozpobooikvdkrpdfkndnqmlxciyilvxiebvhitubyxzkncytqhnkjmrlfauf','hczuoydujmxvfubwmxxcldzgrteegwgcswhdochddheiotyiddbpbnlbgioqaeefygmjjoeiqrjdljbcfcikwrrbepnphfuftuszzmhqbteevhxmyeryjkcqmsjypcrewnktqoxbswjdruwqguqqkbaeinbeglotqdwwyudhzzknpwreglufsvjxipjjtcgfdubagmtqgsyjfsojgxsubcptbiycrmgebdwbnqozpadvoxmlusehhikewia')
+;
+insert into t2(a,b) values ('eigcxchulpcymgohcjvdaajinwmrfxnbdligruoyvzlvmjrfhicgvtefgjrkufpxbjudtlhtontcegvmunzsmauyyctcavyczptnqpvsaxhzxkufaheqvmifcjtuekipsqyxrsabdiedmhiubhorocehkaegjgpzjqnrbeevlncbkgetqeacqezuhkbrkowwdvdsatmegcwaargu','rascyujubtsglowiljgmwcqfpywzaophsfnanwubaxnehkzumcmhqbgmxsuxacirsioxfazynylicyxdxryijkaotrhskjurfeaqhgflvrnbsyydsctaysoxjbckqpheruhgdyrmwauad')
+;
+insert into t2(a,b) values ('zwflxsznnzvnkzgzfffppbglnbdenqbanztetjcnlzcbiflwqoe','tzqldrknisngfwutplbqchyyzqiuiisccrjzdsqrlnybdkztdshsmgkitbvgwzxszxlzgwdkbbxudjqvhzlacqfolwbvkydswsiokwrnheyvkmpdmpxduchxmvmfmkbzvdomrlhqgtqwfumwfpphgrnlkvzhqgbungeferyvhcpg')
+;
+insert into t2(a,b) values ('ekmeldbhobyfjpmocewiattsetuwfrjdloerjkvlbmqrnwmnevungczohirkrsisowacgdpexvwgmuobtkghagetriqxfeimzdcbaexatikfdyjsfsklwvkijrufyfgkavbnjzkwtiyhsyurzaqzexcxvmuryiplsewvjamskeqbpyamuutiaxnnciiwlswzdriesobvsgyvkrvpjqowjtnpbovfhb','rhijfnnqvoohjbecjdywbmniaksbpborjzuakoacjeyvgkrjrbxweamxucvwsgavswmogasttsxfnsvdjkzaryelnshavppbhmywfagdqlwthhkrwbowwftioojabvoheqoirgllvyzrhjtiazelqluurzgcqznqzgvyppzgteovzsnearwmtqqetvbiog')
+;
+insert into t2(a,b) values ('dabcdkawbazkzerexuytttzblosulalpjjezuzjdzmvnzwwlptpzbkeigpajprtmdxgqtsmvamyyfcndorskbicsfbufigxtewtastgwbvgeztfhoihytwkctjtufvxldzvdvlclcguddasl','byhlciylqdblvbczrfaedllcojszbqglgtmkbuuussrkfwfsshoonautidwdbcqaguugenzjeymdilfsdqoibrzvsqwwnaxbdznxpnsqrfzwuyw')
+;
+insert into t2(a,b) values ('lhobdiriqelzzsbvlcotihijqptoocukbdvpdhtduxalwimgkorvajkljelwvrsewiuhnoimjykojngmayyjcipdwyhwvtmkhjhtirldmuyofamwgfrtteuwhpnublfdvhofooxjtlprynzcphqjzptfzc','qgrprgnpxazuniuzqjwerytznfkhsbbssseqmrpsnnytcvfxjjxjskbtpaofxlf')
+;
+insert into t2(a,b) values ('hrsaothenvjoqwnqgnjnqtdistagmopeoicswnihjnkgacllmjamkzmaogfipuclbydsbs','pgycaqqyinwavxpblqdosalmwdbfpkjowdajqywrsdxqpizdqzcertdaltvpvspmgtnbc')
+;
+insert into t2(a,b) values ('mallpiwugpdtyluqmkhjzlbbyfqsnjnizlusgnomudfmavuhuxfoguhbvrbyqcglqkfsgrozcmqqonbnzkrfqytfo','tkvipphimtnfatsvpcqjtlpgewddckdrmzhglhngmgufovffamrcgwohudgcmgcbbtyrxxvwogeeiunfuheidthwmmujz')
+;
+insert into t2(a,b) values ('rmknymdkuekwqbpaueveifdzwzgceloptseoqcmzgyjkmrtnnwnepckiualhufkqejvycegmyqdyguqscvwxcefmlvnkxngcexdddvtnxfdldkhwdkggwjieopanxlovrfgrmzppwbsowwdbwqwdqbyklj','qmvhigxrjpwalfgkuevzocvcpjocpnerzrjfwhkcqatxurpgrcmelkhtnp')
+;
+insert into t2(a,b) values ('ynkuanodjfzauqrxtkqkmmboxtywarwtdyjnvfxmqilypiwezpzngletftfoedpxiprumdmmduesxnjiphlneyepitfqoiprbwvfubfqogkmuvbzstfyricoewuackwlwuisavbyhlluggkqwmfhvsarzqxeqstw','cotjqjilwnpazvqrdatnbsniu')
+;
+insert into t2(a,b) values ('wcjfyhsoryzfxlcegpfpcjhncuucruscfalocqnbrbxdcdfetybuldjcdjblwdcherciie','hpkwmrkcowdzimkrmrlbcrhdctlozqlfcfuirknlfabjnqflzhbjjaorruuewebkztsxhdubcpkexwboikkewlxyrghgtuwgiuolfpdoslnlntvddhjaytzuiluqgobsjnntimcanitkwhggif')
+;
+insert into t2(a,b) values ('qjkmemccgdxrncobpjgfnmpmxxsslfovqwjhpvzqqrjzbmsxipynjfavybagollqvbeqqwdbhvuwgdcfufsdnzvcmwglowiaqygmcwzvjmcmrdgzzxuxdtcjnglcnitkltbrwxvsqrtsggdbrbfzsfmjmvrmyjhyihxypufrikffgldhoacyilukjsedaaiibyzsgkbwdkiebomdalyjwzwsnubkcvtnuvbp','gaiikivpbuinkwgwjcwzezkqvzitsqjpephlsfpcpxgfdltsyuimi')
+;
+insert into t2(a,b) values ('qqrbgwosldloqohltiyvpttrxmdimstdpoqeisukvfmoilpxjeoskkfhaijjefqsutnnndvdprjdmwmplwfhjgrdgoxyrpvkqdrvecqltqwsqbkpbyzzjuhrxajrfxzoenlsjoeggsmzdvfhgydbpwhyurlpkxodoyxshbnzsyvhotkkajgltwxgtxpfvkrnkwiuvqpczavwkwvyvhmxkxxdwdeypuxwemfxblfqrjnaldwwyr','wunlgtgvifbbarrwevixyeqckewbhdtgnistngatbvyskgqcfbmqyjpmblbfgkbqzthipbilftjbfrxwspxwqzyemcxvpbloelevjbxnnekrkbcuicqwydbkjjzkvhurwldvuhsjqxkyqyrsyuvanbpwdwwzutnrrbqzxwtasbhlmadthrwjeqjbnhyxdxkblepilwcjaokrrntjoauwzkspfzkszc')
+;
+insert into t2(a,b) values ('unzmfdabwuuruzkwjwdnhfipbcyxmxhiawcxbtwegmtulmxofnxnhkrlihzfxpdpdvzpgbjcprznrnjzizjagvuqcaunbllmtejndn','ssoqkuibnfyomrncz')
+;
+insert into t2(a,b) values ('vit','dqgxflovrotdfgqvmeevsgltountrqcfkelcplqkoixagrsgnwzlysojkxfwhfdrrinodxkcmgdlyyydvtgmxjbzdopliqksgcuhzyvafgqvsmgmizkzexvoijjqpkxoxsmoybvytjgfaavffqvmjzrd')
+;
+insert into t2(a,b) values ('jdvmbgnmhfghcesgwqhnqnisffrefzilitswagpxcknsktqzqzlgfzitqlhpptacuikmwzkapxjqptpfskpwfcduzlovguoozhbagrkocfklvbyleexgoiaetsomemdgsiqsiqeqcryohnsgevyzgrgyvejhylbnfvfqwykpwcmabrkq','cgzrgvfgzhznijykfhcvfbidycacuwrxugljodblhmpqseqlenfelchdyrrkpradntpdrdkhgqaoaibzspuybbupvfahvquccctfuvvndmlbkyquomsosbbtkxmnaalcsfgedcnjqlowegvxisqx')
+;
+insert into t2(a,b) values ('ufnogcodgnfzzbtimoexj','wjusqcidqcdanjzhxvxfgluuwoooqeev')
+;
+insert into t2(a,b) values ('usrwxmscsoqmehobmlbjihbfmiiuaekedzkzetksyubegborwwkbuukex','hyppzexdbsorgvpklrwjytpkmctvahwfdawdaidwysqedskdevhcnvdmhyzhzgdbkiylxuavmxlvjpotgiiixcoghgteavptskioaigiujoacopcxlabwekquxzpacmfvolbri')
+;
+insert into t2(a,b) values ('iznxdmuzmhghhlmncpowgztezpkmesznjbusklunihopblvcgcklcuoosioikkxljsgenjuhlpczpvujlmjcfefqvpfrslhsqnjocwbftzbx','rbfwvwgltqnlutexxguohuwpkjlfttnclpzrhpzeoqwzitcdttdvzuqxlrairokuzqkkzuywofxnwvhnmnodhvtfwhvgnrdpvlauunghaygrybunsjjobxsiwchgkjifrltmg')
+;
+insert into t2(a,b) values ('reormaucujklrfjprkruiesfxsdvtyhujruzcuscvojockohssnyihqxfxyfqdnycfiuulscyyqasswstjatpyodqathbsvgxuxwdxfebmgxqwtrzojhvppnys','tdmksgvnosvlwxyywgkiylzfzjjegmnswjvnzvuxcitrlkcjgyksgxgayflqvdwgceavwpjpdsbkeozxfniegjibnmzafmfalbwbgpjoedcrthgwhvxewcrveexvkdowtznx')
+;
+insert into t2(a,b) values ('olcfdidwymrqfvhrcgosmqfudfbkcpyumhangnqhzpnmwbccaljmsmptltayrjcagnyqkanpeguluqgqqsqfqssmslfnpxjwanieumochlvezuozat','luesjlnlubrefvitstnombapnzgsdnzetzmpspbuifmwcxmwkmednoazpwmjjcawdfqurajwxfkalsfykazghvxkzlgcesoelvbeoneryhhmzlp')
+;
+insert into t2(a,b) values ('vhvwehpgfgyqhdofsbuqbftmfpeqnyqltcaakxvdwwjbsceuparplmmzypvocznwaqghxkprettjgecppmauugewjxghcfxmvvzedulnemoecfqsbdfzaasmtjlqcpgunpvjymdbgfhtcfkaitastpxmxcvrwqepy','dbplbsumpofyanlefpvikymachbhdqcweingnjwcxwruftfbtxtkqjrhtoa')
+;
+insert into t2(a,b) values ('fvegihtzdbhxhxbhajwueixcks','cllhsejijrqvephwsrosafqspqkcnbyaezgzjqjqvmhmldhelduhnhhwkopoxospmrhnwluqehwyectaykusggauzdxfilhyfzpobsvlttserffhrufpbogpxlyvuplhwtzlcmgpmcpeeyvznjqvmxecdoednbbbcnqgleuxenxodqxskszwurmfgadgbceruoebrpqenqhtcfmctpsubhdhrjkn')
+;
+insert into t2(a,b) values ('ktobeydydyztebuzmyzbugyuluhmeqvhkyvmbeaoikjdcocorbzkexppdyjgkucgdguugqywccywvxkypubxvkwniedbvshgpodylahvnhgovxclccmvbylpeboznwdldtsauqufugmemoktsviwmwreyiixmzziu','dimhwqfkkmoosbdcxbgeafgmvzwoclqgdhsixyngiovwatswkfjcstucdhooshinkvqwcachtcqmhisnyerxqbshtffdfkadufuffvlxdswhapzvjnespmhmovsqfkbmpzccmzjltdahpajggxasxxyngdlmcutzghulmspbtdsndw')
+;
+insert into t2(a,b) values ('xhzuuyclyjilfeaxbyxzznzkhslsdzxqhlwctlqvxwcgaqqvfeikfqbrtoihbbhendmhjtsdybailjrqxfojgnlkcobdwctaoahxgsmpulhsqnnfeebwlcyqwftdsiezeruvsqnvaqnbxkniho','ksxiirphsdamlxwrpooykbcbjhttakgbhfwygyphqpisoczmkxqmwzmvugyaifibxxpfgqu')
+;
+insert into t2(a,b) values ('hiqzkkfipcghcukidbxtfcntrdfxhklervplsdfdfwjqufjnqzihxvfltzigrklpqumxsbevpdkwnhexhcwnihjwddxsypmdhjzvzqjfedjmlwrmwsldgghirgsvnthrrcohaftedqgetutfkdvznujybtecqzoswvpzklwjouggkunytezbaetcgqduxiwnnr','rdbjyoazjwrbcudjynpoztpjkboyxiuzkjjqhnayyuoeoskcvoefihvyblueksancvtjmikdsawtyaksctkytnobeqldlxejppdursdvkygazwqmljzmhpcidfvttknpqqbjrukmhpc')
+;
+insert into t2(a,b) values ('klnhspythzrrkqbtbjtrncgdnrfdmjfcdsetwpnbxulltiuzyauywbhnijnskumuffldhumnnazfafffpxuvzekarikysphweaybciidnbkjmjteojgetoojjwavbeojniklndrmscqztlzegbpnragzkczjjf','jzaaxuwsfrfewsuwfzixsvcbnzxcmpumqyzahjynisevebdfmvzgndxtseahstgldsjbgofjfmkaipcnheicnzxrfvlroxhpeifcdtvrbgvplfefmhpqjuxdiydgdjbyibroojpznlfbpngrriuxxievnmtsersgambphavcrlzjyjmm')
+;
+insert into t2(a,b) values ('xeieormbleoqpnjfjxnpg','guzukyxhqjcugepm')
+;
+insert into t2(a,b) values ('xesmtdbkieleunjvcixnxcfoxhomcdpogeflkopgjkspsebjrnoufsnmenqnafxqhxmxcffxlxtfqnxewecrwpsnudirkrvsmulhayhnwyftvxofkmprrcnvhhftlgvoqyuapwbddrnztprgjc','owjdenbksdkuzkzrtldpgrpjqzxtoivpghzgyzdraryilnlopvdnadbgguklemaxcnrqcmnfzazocneqsrnwbnbbfpmqmzqjufwomptsjysrnbaaqlwmsjwkfdivdlkopkbsbmxzgeovovnqljjccdixhwukessfwsnlnnnttdiyknjz')
+;
+insert into t2(a,b) values ('sboondvsryreihwficuwikrfeytdqbnnclnvlnqtcjamcmielzuhuwgyrjypslsxpuihasfnngkdpkevkm','uikcsonaysrlpolpwmxoyydddwseyddmqdtsvhmuglhmjigwjmtkemgiqenjzshjowdvczlmuzrbbewthhgwguhwfvvabhaniygulyjuhkwzfryubbyjurxgmkylmraciksazdseelazjyvqfijumdyybkjthfwfootpeswwnegptbqecdgwnfryfsyqilipwrrxmzalqsduizvstxdeklxqg')
+;
+insert into t2(a,b) values ('ckpbetzzakrgobtcbgiuqhpodhbklbfyxoeqkysncpdhwxkxgdnjndefoikmliqkdirxpsrhb','papdduxqbmhehimunle')
+;
+insert into t2(a,b) values ('qzrszdvdblxhbcspsxvuzlpzfvwbpikjbahglrwkvwaoycfwnvjssxumyyksnuaq','rajygywiusdmqprpcmlemozndmnznhvkuvcenaglzbxawqusaozcuzaypzdndaekovojapmxqbkgnzmvooqhvexlkfqjcuyhrxqbpdfnugewawexsdrxwshheokeliluqlkgppvjwzdqufkkjadgubyrjhsgyzohrmmezxywxrwgrnfbxfpocjdzknsvvnvpawhvkcldduncwwmnocntwexihkahpnfopjjrzlujjegcfzavurpjb')
+;
+insert into t2(a,b) values ('pqhqv','tlpzftzlnaxbioucmfszzhfnajxjwmngtxxiezfdabinphbhlodisoxldmynvtqhepaxphiozxhwmkoxnalpfjlqrgurxduzwoaytvnixhmgtwnenwqex')
+;
+insert into t2(a,b) values ('hgqmwmsrrezuyvufhvcdwufqiwylgvqapfhknprycktefuftlnxlizahuobruhppmbmxzoucklbcuphbo','wyuxexkbblpgghhbyplpgifogrjujnhlmgumoarerlgfwzctzwbceosxscwtebnfnbcliqrgmfwbkfvrwwgympmcxxdmiqyeloclryajuazpugbdvocmblzabwaiokmvmkcwxugrlbbbddotawyvekvcywmeaavheuwjxigeldnlwejwlcngyaenvmkotgeczhfsa')
+;
+insert into t2(a,b) values ('szjjefnrdzwptixnfc','tccxanvntwutmaugpgwtgretuvbmcofjbcohemrzjqryzmrgxccyxmpqeeywnknzowhvfpuacuwrpwyloawdtesbqxoioeqzefyrprew')
+;
+insert into t2(a,b) values ('cxwtifmpmaghovfdfnngkfjksuoiourebithfrumybxgy','wbderybijttavdjowfhrvrzpsruxxkiclznkdlwlvvmcuytnsbrunhgwdmvjcerzshokiwlgbdvpnnsyicucqbvzqvshbhqjxbgrmjuixmbmfcsluxenrpzumnjclavogihemokgfoihynntmsjmcvgpdvcbfqokrpjyfhrvgayettcfsmhyjlmnnqxivfanocaliqcdihmugalxmodczoqccaksbo')
+;
+insert into t2(a,b) values ('glcboujtrlabdosoidctkufxooiuoukgqiipzmeoinhkbpapuepdvqngwyeogxzpeawvrppwdxxabqaqivtnrzhzdvnbzmalnugwocxbwnynxgjjgslkvxhgezxqykqtjlyobjjtkhgwfplyqzaprtunxiizhaufz','dcetiy')
+;
+insert into t2(a,b) values ('mbznupmwublpzpezakuujawbzbkqsboxrvzimjggtbkzklozsxpfoclheinkeunxzzdcqmrghljbndjtavcgbluuwivynggwgwkurqgkiumikkkcbdysdffvjxjjrucluuevtsnmpwtwzexfgbiscvyrquxhklwikfwqyxyixsrwhzescaxrqahybrkkqxvceshpyjwrdbtmeiwmgthumejdhomkgivojghfaurxinozzyby','tnnrrhfevnazmqlgudbzeqwhracvtkbgnsqeaqnzzgtjaotrznjnczlxbkgemoawrbfnmsrvwdokgztoxfurfmbabsqkepcioijf')
+;
+insert into t2(a,b) values ('aydsvxfzznznwdalfrxdhrhvlqoqxpkyhgmiyzfagqbpmxfutvjmlxczcvjerwdylgitrflxiytmynuqtbwgwjsilxjypijcpvdcwkaqvgvnzvkebuvijaekmwvnxktqvlypouoyzwrgpabfnsdrhlsydqvexdprphyxmxtmcnjwswrdquojyoqbyrutdcglwvn','sllcwdogl')
+;
+insert into t2(a,b) values ('rfttblcrsaoubxsuhsbzxuraulkdkollforqlxvtpsrvzotnojqhtghesricqgpldeenmsjjjoanwdxbdsexucfpcrj','angatmjccgepfmgowpakilacnocvvqqbkwqqxpbwxcoqoirxfvznslij')
+;
+insert into t2(a,b) values ('','')
+;
+insert into t2(a,b) values ('ljqxeprqygvbumpmusljwkenktfwehblqazstkcyqjxticahqlsxwyffgwbxbehqzsabskmjcjihvwtasozsojkmyvtzhcsafjlrfrovmykxouefxifcngkflgbumozactpyuuuzcvzfnnspxnbgugybyevggyvypczxvbbqvnvkibqzversljfiixlnmhmzxeilp','bspdqhgmvntapcmxapnawxyosyqlwyguwtjrvealgknmltgptnwhfvutcfiyqbmspiiiqsairqjrlmvyxsgdaojuullgrfcjdrmmuyoyprrsluzokabkhlvqvmnglmyaniyikpkdazortnavjaxweygrogquqwjgeunwugvededuhspzhtpxbkamivuiimxjrfjkjseaexffpwneh')
+;
+insert into t2(a,b) values ('nouvodblhmalesfvekyxwvinferaspcgylrdhmrummeefaniagjlmugfpxhwuawcgxwrhanbqwdljcdazwrqthjaixsokgnswurdmkwfdunzxgdaubjqnunnnlsswtuotcmeokrmajebae','firsfaphyaeeijmqpltsjvldzjzvinzrtqypcuehftintwgzzobqxuehmmbqanvwrcxqppuzazdggerqwjhbidkhivuypaqhnwmvavksbyjrildvstpsdsgbxmbumannjhgxlhkrbtkpsvhedunvvixximkaseiodmwpdblbknaewlc')
+;
+insert into t2(a,b) values ('ikkrchjlaajkaarcfanqvrljeevuwuzzuaspfxtyuvnygepiyemrbcsqhmogqeaaxqcyuabftvbzcgvkymyyqtrjitawjsztjrkkgsdgxfbubiybimpzqealbsftwiwdvebkfxbkwupxlwiqmllfvllslvtfsciauwhrctqcgfziywtdpqmwmuolhswuztfyyiqrhyxknhhhzztx','bghgeycmlhcmuiwsxmmjogxcikgusfkljwaurcbxhiulvtbqjuhhldy')
+;
+insert into t2(a,b) values ('yjfhlyefsqnbmjmdgrseaeoebpkklrquwtgnvzqthxmgerfsbfxckptsblyigzbqjzhuloozmtdtyuypacqmivuexdqmayljpwijqyqrsunnmifazeudjybpabpzojinbykggtkbpwgmzarnstypbvsazriohtt','cmeuuracwfdzergenqzptlepbejxkgeuczztbunvcricremhxpmbegydckfnktkb')
+;
+insert into t2(a,b) values ('ajqrpskucjusgqdmniyxphpwvdheiulmgfxeuueqfaozxgugjbrqkjolofwrrnufzldnrviqinsvsdhswzencoudzkfprrposbmtilpebccolbvstdlzbgxlkriwpsjawnorcvoaikzpddexogoncmezujqpbwjnosjfbvirzftifdhbtujapohhmzralbisoznmxeaqagmjqlffhuqpklzzaiplucophlfsxpyrjrsperz','ypwdhjmocge')
+;
+insert into t2(a,b) values ('ktquqrvihljonvbq','eeyflabajuvdaavieylcbpibezcoagzamebpbuapqjlyfklpbyqsevdpubsinwfsrvvsvosvcmkmcpkvlymdrvmnhmfstqfidtvosjqnrpntnzfuhoqdzl')
+;
+insert into t2(a,b) values ('vakvytdtvjhlclfyaixbqdhdmounakwcundgrpqdlieoqdzdvjhjelhmbncuaosjhfrabirmrcrkxjietwvpnogzeolenyfphckmfemgombxzhhxpmdemybnswxvnhwdsjnwfbcwwgxgentgtrwturzexwwcdnvubywfvpucltkebzyimguombzcaqtkhwuuiozbiqpfgmmtctjxfslxgmhhifg','')
+;
+insert into t2(a,b) values ('cqynhaemecmkiapzijdaexuabejncdtyqnktyfxpqquplccwt','uwfvkaxuibr')
+;
+insert into t2(a,b) values ('klqicnjoyvtjifqedlodegmqfthwawiudfbfehbiiulmbxywhoqewgrzjqndjwzhkfrrfdnffhrwcpqbvmbjppgdnffjhyzctttvhblyecrlnjh','mqxuafbpdtjbzgsmwkdkzrhctda')
+;
+insert into t2(a,b) values ('sgxlxxndikluhzwtuuvhinprvyngamkywcmuxsxoouqdjnsgbtpneuwrjqfygqktiphynrlwemhxdpcdjmfylahazjitbcvssqfzrkkprbqarhaawagqdhavrdryzfhxajekrsxbolyzsprfzsirlqtmzuq','vgspuvpjsitvsmpxrdftlvpmfnwifpwinngfuilkwycpfxmtidzjlmbyarkrldshpjfhdudwexxyvznavqxpwobvfwisievhpunodiftxbtkmayaexnwzhxggkpkvalshehwmaxcinkojkdwkgeebygwxqsfrhqjytozzvtrhstarfgrbiozdmveflgxg')
+;
+insert into t2(a,b) values ('kxmpsrgngqbvuraucbvmdfefuligujplqvhldzwucmamkbqxnfwuzxuocurebwkhewtfbjwdheopmepedckpcrntcqqhet','fzbdsmfprtmqvoldwplxyzcbsjgxmlpvprfwaoneorfllizmxejoiwiumxmcetppoclevghmvrqsvuolqopthmxnauxxfxzuqbhthjttkclwmjrcnwscxhkgubq')
+;
+insert into t2(a,b) values ('hcvxsdspfzzhmlphcomctladdlwzgmimsigblzlpnagcnobjvdxbhociiomterkxytkbhouo','xbzumcslbsndjtutzoowixonplztzcmyiezngbqtofadvnilyiffoswgesrcsyu')
+;
+insert into t2(a,b) values ('umkiqixukwudzdqncxownwlwqqsvytkuhsvgmuthzbbkuljvpmepcakknfmzhtrqtlchwnoawcbftjpgtmaelyxplgnpzbjrpokflfpnbfofuzoxrqdaolufuhhzpbhjtejiovuuvjvvszvo','hgvahffnnemeuyqjdzaxhnnigdoiteagtxvmxfizptokwam')
+;
+insert into t2(a,b) values ('imxilndvojlugahtvbtwiwxaiszbooppxzteboqenjmfuuwzhcgkojplmmyzmpnvzsnidsykscvnkwllkkwhrujgxowbhsveubowaaroylcpljkcu','tyepbtfllrtmvekwvypaasmtfngskwoyqflwnitncrlqnstbknganzauwxozxvxmmkejgockcrlhhstzypxcpejrvlzyoijejnrasziqsnudlinknnfrstsql')
+;
+insert into t2(a,b) values ('pwxq','hwmzecjberqiptymhylrhbijgwcawejbblnvpowyjsbooqjmwmrmfynbqfefaxnknsdokqaddiujoxqhntgprhzturbcvykstvojtcfsyoboqbnpesmhmmyklhxrwchkrvqpesdckfqzosnih')
+;
+insert into t2(a,b) values ('diushaliaeorjuuxucuavbekqvdspvuptjkydtisfqjdobbtmrtbotdfxkijgjnlqpmnbdsvmrdmmosfxmlxsebkcqsmuapacvrxfspzltehbtfpnsfregmaumznkgsrtaqjiggosvcyagpeywkwqbizrkgjoyqcdirdtddokc','cqatquvwmlwncgzutalhsbmnfimmougbpfjyinpdkafjnvtafshggznduybtiweutyulavwkbsmqgontapguojwydaxzafodqlhygpwcqpqepruuppckuabixzoojwpfzvuipziuojktjlglbljakrhsylownfoommqaa')
+;
+insert into t2(a,b) values ('yndpyhrbtbqihnxlywobhuftxbfnneqtzgzikabqflcxdwziquorqyifyiqoiqoftiglrhlxcamsqpqhfqrdsrfyrrfjbybrsqcbtzqmnckyupvhlkrkozpzdcgofwqmjeempxeuycewywxctfmmbmlwrcjebirsat','mjsohcfscetvqlmputwabinkgjsubdrutlepogdbzjmelmmtqzdpouwdutkwhsvudrnbyklumacdiabjkmocnxgnfsjstzydqxvayddedwhalbinkjksvqfynsmf')
+;
+insert into t2(a,b) values ('ufjlj','ivib')
+;
+insert into t2(a,b) values ('iiyqpsmrqeuigrmqfftbwwwhovouup','fdtwhzeumonxbwrczvzexqzshkmwfxse')
+;
+insert into t2(a,b) values ('rrnsocgeqrynzryoultfitglizzpetwnoqefnqephfbsm','xrlqtrdhgbcxvwfethgpvcvjfcxhbqqpkputxgeymxymbemkrqrwjfzeztkxxipuzhzlaxsovhecqelyzwyutsnzwqwtavgrpkxyjkpuyrlgrooqbjonpvxdnccktryhvmocszyirdcuhwxwwntubjjapxrcpmxhihoerraeugrystxsykcj')
+;
+insert into t2(a,b) values ('vkixpn','ellhugzdgcvrvsdlaklflvtuddihcvpdpvmgruzacqjfknlolgzezebqihlewjajgyphtbrmpbiiqoaiwowucgozlfjeofvykrduhkuplxrkudbolpigzfsjasewdvgvnttcauwjnkewziocpbhehwtzgrwqfoteospquhlrjnsxugtssrybdchcjnvdlglxxzz')
+;
+insert into t2(a,b) values ('tiiwwzdlsekyngoqnbaztjraspnu','cpnmvyqagdbqrndvcesyljeqireqahbxenanng')
+;
+insert into t2(a,b) values ('qtuadbpgnzigwocqcwxdfdzslyowracjnhdtszzfwlivqrezalncedvmtjcesornrzmzfqpwgamxttvabmaylkynyjaichaiihlhlrvvznjptbcrmfraefsnhimykmqcpbkdwlrjmaibzhxawmgcmdksjbmxqlwkkotfhordkqofdutdsabuhtvrpnibxhosualvgfpqkmsbsgpi','lnlufgubbqrkarqfwtceouyizkhvaklmbphtgfrqhxzoolaamuiarxgrpkbqilwbmmmhoeeiurntneclsbixxvzfqcavmkbmdzqvndbrrjcbcsgvhlwsjfx')
+;
+insert into t2(a,b) values ('ixogkpfkbc','ycwmgfbdxsuckbuwboaktlhpfprigmxfkfdsaguwaywjvxoijtctchqvlwcorbecybjbrwojoieeotuanopajtkhffacpsktfbjwvpbhzhpptfuzwyuugnflidqadkufxqijyokrlqatajwjitdegsxpkyefenpcywbbhqresnecaundazpdhpzbggwgnnlhdomuclvhyrxfsvtddrd')
+;
+insert into t2(a,b) values ('fhlyrykohenrdipjwdlbhauojqptdxydutfvbkvojgfrfrcohvjpzxeepqyfhxguolefsbooewucyqeuqlgwedzcomaqavoxhswpdzsdykyqvpofhfezgihcjdoerljmsjnwgtcwjctidbpltuzgllxcafpslvncipmmsclrgvfzcfgkbgrbwzvgtguwrebxdonofaaasprdm','edpvcbnuciwfciexjtfynsdjbdadztechbptdtneahsmovermkjbppigrcannwwpzdfbhmqsmpionjhnrzhyisnxuusawcerdanrkwjfzqatjoszlejesfnhbwhdlztlspdxitoetphdzedcofzhtgxbxtbavseojloibrhbbqjajwbxfnkhljwhdlfdtdjiryqkm')
+;
+insert into t2(a,b) values ('hoxlcgalssqitphzyykmubizecmnhvrndbwktmgpnsvghjqomzjszmyaaqjueexplknqzdmmewnprevvfsptlmguvdsgqstrwtwkhheooactcazdjxmhpyjnrzubbzdfrorgbdznmvfaqsmnhuljcnsefxxiihtrpscwzzkrbfunxclujcpzazhbnvffblntfulsanibaqatrvwoqdgvuluacbzuhfyzwu','eupsortglfpwdskrennkb')
+;
+insert into t2(a,b) values ('iwvcabctvpgjmoqgmtmnznneayilofflwdry','uxwfvtvxhcnbpfetobttuhopcdrviorrwjdyvkqkkgfwrzcctlhxmmvnlccgkajrircbvluhjnqetxzpsyahnreqhibquwmukillpalefqhparciprpsxxqiomtsmzudpkwgidlb')
+;
+insert into t2(a,b) values ('smuugululy','sskrwouigdviuyovblqabgswksmulfeyrahxpydgspmulwdvthkdzryxvrzxfvgipngmecghvxzvovcszccbokreeicarwalhz')
+;
+insert into t2(a,b) values ('wgxctfpaucofhsqxpqwxagbvdflnmoydkhxsrbjjezqwgtcxubxswpxciyzrywfdquqtrbewnxmzmzaklfalryzkzsnqmekhjrtypqxvxotfulfoekuqbiecrdfzihqhoswxlshismdxzetamsddtzlbjvhhoomflronodppfezaisxyjnlmlczwvnmkeilwildnhuxrgwrblrbsfaecyyjzfhynivkgokfgqvuutommoxrcnxgznlqjmbmh','ezezwmbnaatvgvzostvbtrfmvqeegwpukbxrusiryywcfkfiuwqwsuwgqfbssliwrxmwrsbrvqryscuxzqgwsnolwppezuzebgfsptftkxiyhudtsolwqhfcxwqpwtzmxhpuvftxyyfakwhamuiekkaukxqovuzzeczkfnwtfaqjgiiyjalykvylibxjypmyjexczbyuahck')
+;
+insert into t2(a,b) values ('ivptddcwqzyrmgxrkunogurhaolqnkpjuqjkjnkcbvkhpdyw','dofppmrabrqbvhhuhuszhkoaonusltipdrpvninyvgrmkkcvtzbanmjxyjhsoqiogtjrdkxqoexpxaufyopdvvnccdrmpqmrhtlqhoibzxibrlwovrbllwhuzhhqdrxyjbnjvzbtkhsptgllnlcxorlvdtmjyegyurjkvmrdxvhltaiwmhcyrzfegcyeihacyzjsxmxokfpgsglkuw')
+;
+insert into t2(a,b) values ('ztgineeszecdzttipmsajuxlqfbvtsscuhvzobeplwmprroxszpkrhjfwouilwpxokmwvhjttxppnvdtcbbugmdvpwwlfxlwlqaoumuplnligs','mrbr')
+;
+insert into t2(a,b) values ('jpxngregpdrucnpsaavaziawywkudmuakydadytvgaspvywcuvsoljajchyynfqiltunjlfksxjumqhpodizvjahtkqkyhbyujvxdkjqbefnviyzkssuvxmoxcvhdhjmkg','ejbggulrkrwrhjenpewqijrawftnrapmzendzycbeymaxjewnklhfhlmaenaygxzrgmczrfrsfmqodioopqlitqpglhhcqbbkzhajagrwkbivcaklgqceabdseiwwjibf')
+;
+insert into t2(a,b) values ('duyifqnooxdudsizclsnlewxfgoctvxbaizixjjeqephsumxkprtojvbjirtsbzyemmgyzgaxyoeejxngydksfnsjdelwhyenbbkrkszxcewgdhluwfxwqnstyfdksgzhguonmcbgkutzifnlmrrcypzcoydhyhvebaivvnzofjejboxwqvjt','tniegerrxlhendovxqxtwribfexaiygpzszayyciaxtmicdhzsdgmachwadj')
+;
+insert into t2(a,b) values ('mzowyraqowvypbmxmctizmiiroksvgslpfhkyayvhxghfvfmxvvntskgmnfdvspouyararkjanknnrcwsqjlrppupdwxuuroxcyulggbueyxiuenwrzbfarwmgiqrkbndvtmqqedasoxjxuibipwcierxtguj','iwogrsslpvgq')
+;
+insert into t2(a,b) values ('twuctlznoxthobemwedlfutvamsvujxwojsuvxpvazoiwksvxbuymbpjpcuvipdvvgxlgbbpgvenzbxbmbqwkechrxufkbsrhsgehgvntqvnwmhmyuvftavbxzkvquzuueaqzounvtyubtwgsbpdbpjwqxbmtlmbktxwxskdxhnykekbqcrgiwgjgdhgemcvwcifeuxncpqnfqneiypfhappmgenxdssymxg','axjwqfmfcimrrpvsejcdonesysvhxkbcvvjjtskbcpexycseodtioibixwshmrexinrmslwvxevrkwzjydntaegqxjrvqsnohtqmrqvniyjrbflrtjvntoyrzxsbbvoezwypngfrc')
+;
+insert into t2(a,b) values ('jgazhxdoajliscxkddfijmjfanacmxnhwiebkxuzmfxezrqynjwjodjfhdakxvrlibchonagpvckxtbesfpsetcrrmlaxahiikfujagycubxcecwliqbyrwewcqveulokisvgcssjhftobicxmcqkrtnpfolmswuutztavwwzeerusgkfbsikteyt','uxvwubzbuxxasgkcyrgmiyykyvczxvmljrbwzyjdelobgtbsacqohrhluomuqkcjahudgkjwxdpyimsgrfgajnyswhxguxpmsmpkolxskscsbmahynsskoyxfcruxlhkqpayhahwvslglncqztqvefjkwigovaebbflftnvxbbf')
+;
+insert into t2(a,b) values ('qfnwckrnclhnshq','mdwiiyeijppwluesjlnlubrefvitstnombapnzgsdnzetzmpspbuifmwcxmwkmednoazpwmjjcawdfqurajwxfkalsfykazghvxkzlgcesoelvbeoneryhhmzlptrdswaljfdovgevcfdmswofugjwpwucdkizsibwnivvrcdalltdtx')
+;
+insert into t2(a,b) values ('admnjpdobvmagafgtpzhgxxzipbwkxrwoscrbcausnstywthrvwspgkjyialcykefkbgbnymawnlsdnfwasvyqiuqxiwevaqsnmnteqxuewoeyzwxajdgnmyqymtmjdgjjlqagsvqpydhvvejljrttyfwzeecrdniwtwwrvogiqakjpkanklzgywjwmtzyuwpmbbyckxrstpkwzkwgzztemhtbzngfeitqeublw','hmdwrhjmkahhsrofbcorcwacouqxqvmmievicqxanmsnphcryavsuqjpalthklgbksvfeynbnirnmldipmdjoqdiptmfxrqocrrrfwgtlqqesqqxhguusrsfelvcvarfmknqispxrxrsacmkxhed')
+;
+insert into t2(a,b) values ('nfqfjulpyylintjnqqlhiqejqqebyqgybxvdtqcpacukmjmszjvoksqwuynvkrvaemuyysojxthikvkpprrboofobeqfgyxvqltpzdemphytxifklgopqypqdezkodlaieqngqugharqqrpgxqmoouncorstjufxchvtcxrpqrqimoxhprznfpugzdz','kefyznumanvyagzsbeqgepqhagucrjpokmqwvrjijeitizyequbrtycxdbuordvlevocobmeuetbfpsxmzocwvttevpdizwgwbewzjdzxjzcjpnjzznewoyvvulyhqdzswkmuhzyyiodfnwcxksejobbelhzpx')
+;
+insert into t2(a,b) values ('qustzvlkholqrjvyncdfhastemynkcufcrdevmwaljhazdbjpsjkzmbcizquxhoiwfaztftfmfatfbdagynnbbchdryzhbbxmbhzhdalluumwbtjwmyxufmmanjphtfohcxbqxxuxrxyacfcxhctplvfcvsmsbmamdrm','cygyryetiqrbdhneomstogvakekduuoymggvjuvfvafrnsjexcgxrsvuvjrtpwmclmwdmrspxbsrifuegvpsumtwpfojomqaparlvkvnfrnyehwbcfcavfwcctzqzghqvfjipyyxpcdom')
+;
+insert into t2(a,b) values ('evqohhyzhrtedveppslethenxlbivrawhstnkmznwvzakkbftzukmrqoglwngpoepdtdaumppvhymzvolgzlrqcynlbppaqaccqrisfxlyummzjfldvahnslqtotysvqpwehppgdfqrborexunbxeysmgdkzwsqzcxzbvqgaerynxxrguyzitzeyslirkcpzjdsblgivnmg','kziylaqchuplfbosvxmysxzszosvcblfemo')
+;
+insert into t2(a,b) values ('onogjzkatqlmwsfnlvebykwibfomxnyezsyyomwxusvjogjquvbqqnpbhaxnboqlvildwqgbhpqskfmlpoqlcg','pyibpsmikstloiebxittarqkdcioxcswvuvszorargvrvimhcdfrnehecjibemeiatjxnmsdsdithjnxygemtgbcftoidiziqbnifgpwkghljiktjcjzesxitblhekgvtoqwnzl')
+;
+insert into t2(a,b) values ('enjveckqjpfnslvptstzjnxlslhsslkdvcrzpsplvkgtqxarwgtwnromrcwyqznrnusicuotyhvbrenopzivwh','kpudzcrepdiyazkcsfptarlsgkltxmanjwsifotawkwnkqnfbfytogzimuuancrogadgmhvtjvlxbnafjofnnzaesx')
+;
+insert into t2(a,b) values ('dvdkcuyencvczyofogvripqgolsvrlzisuvnnswugwfgvbuaermlvwhptnlkemfsvyugbtdhmdavbdnoejzbizlselschqoazhxgzzjrkuqfgbbsqqlvziprgfdooqametfdsjvstgsquoqgiswtagcckrdmplxoyywemovflimvbitekmbelgzsapmnpguwdzdgnqqtyhhvzkbzcic','fllczyiumvujqjpmyxsqbupjldirrcbpltedciiskbqvkgcygcigymknsecyendobxjoegfbbtdgjrqecsbblbyknxz')
+;
+insert into t2(a,b) values ('leumkstiavjdzltfzcgkfrlvubcuqtkibkucpsirzdjhgcayipckwezrbw','upppwnhjxfnkysolcfdidwymrqfvhrcgosmqfudfbkcpyumhangnqhzp')
+;
+insert into t2(a,b) values ('jhwgdkbtltmgbqrdrroalmtuypiyamzjyzmtxhtudqqakargebqbbnemwtpbwpsxdugmzjnosufpcmcaxonhwyonmkoxaoeqblwnjslktoqfamoqmpfnpxqvvjelnhsvspcpmxwbilrxjsmgdzzfptifjuajrw','qqoiwaojhaqvlcdxzxajcsawhhjhoxifnyjbnumtpbqyfvzqffjqnhntfsfutkzxlhfgfmpqmhtdkdjeffahvrhtrimpzdorzsiybkf')
+;
+insert into t2(a,b) values ('nhmdsewadyamvorvqympanhdfitilfrygwlexmlrcdeexhctglhmesmcesitgwplsulupocbjaocjfatjrhbdcqcntgoyddnxlxosnyszhtwmlzwacrlkrmfphbqsxhdrdkypoufciaqwapicrbfdy','fjpyrcsuabyepjchtetwhcckuvlkfgkipkcevntiyyrbyjvzegwlwwstqhkwtpulhvqelurdvkcvrwsfsaipoklsxkzpgpcqnpuxjbsfhkexcjozpiyfjyuddufscagycpeamzjirslfbwilfrlgqgyitqwkfqoddoqzqdqbmpfvovfvmrqyokmmqbshzxxjcxuqbpcuktiogewruhctvlskpjrlljihix')
+;
+insert into t2(a,b) values ('neiotkropgwuiqixejybfvbpzpuzhrtncphbcphchtgnqmkmjkkmukkqwlqhtqbgvxlcbvbhdpfczgviamuuvreynmuuagouxuvnimshetssdrhmcmfdkvqwftgifeiqhh','kgbehclekmcuxp')
+;
+insert into t2(a,b) values ('lgulvkpevkiefcuhpxrlqzbgxtzejetydwlijyqnrqwcujrfusfaqqmdflxrbyicfmmhqzlxaizfjazrakjvjscswjadjvfofuhxifdgafmbarvzwceiqcujstdgkx','fstjynadyomfexyunopchyngxvnsnxuudtkhmrqrdgamsecevaowlnkxhblckuvmewlqceyqscalptjziwxeblosefjenijivusvmgtydbjxuiamzunaxriytvjckzdhtkdxgeokrcxymwizzfgflbyenmlclpxcghdimtojvamigvhvrxknucznaytsqokdhassdhuse')
+;
+insert into t2(a,b) values ('bcrkvqutvanhrxoubtropzwmhjplgrlbtptxexaryrfuuehuchnozhrekynmnfamjovwjcqaapvklkfxmcjwmvhvawzgtpglcmnuufifcbulegimgbpgzwkkyadhlvtoqfksomuqxotoawcwcdzkrfzzijlpuixolsbrlwctnukdxyutxrmynsvqhwzzkquodasluyxltorcimehdbzgvwumrc','kueyrbhcjwdhmbxdeyitymwbeksaobcpywohhgafrrvyazkgdwgsshnpmgytvyxacqmyxphimfpyfheyikzkcwodixgfszvxldvlupmznonololvgmwnnztirxswxuqlnupkljeulaqsaontwwhmifogbejpgtptlqsckvizphcosdn')
+;
+insert into t2(a,b) values ('pbscuxmenlppodsjwyfoweswrgiewgriizbfnjwdefjnukxfubmozaulgkdqrrfebwcybjqlnzyoziqjhbydfrgdoowlptzdikucqgnurghpkzdrcocbjpimfmykgsxlrccjtlluvdobrnwdjlxtyuqpwflfxbwqmeqelkypamlvgxexuplulwmwhe','xpxgogoleqzogesdihiomlqanaidkbntjxnwtdkgjjccinmftaanhzfjhgfiotowdibwgqxqtzkygycwbnjulszqwhvooqznzvlthxulgilydsuxkebfczxmdicnvyqlowtwopjmzfpxrmjmumucfxqeqeqqoeqdpdhdbronaqnvnuxsrwmneesdeyiripoidequxxbszbdtyoopbaeygqsycztqldeatqyv')
+;
+insert into t2(a,b) values ('wdnxneychioantkfxlkubgwuuctqtqeydpbouoksasibdhvhxfyjrvnpnlugsgzdsmbkotmqpkojebpbamyokqnprmfefwdpvrqmzjediumbadyvxyhufvjqxahmfdqtmelvmjvsmcvmugfwmgnijlzhvfhnrbglkcmnrilhijcgzjjldupsdzystaoedtpbrlyuiviubbkgnh','wkwqsgbgclentdhujiulgaiwwnlivgonvpcyxghdwitzjmljccbvkskkommcvntmbiaxadhdzhzbtkwzpsmdztqqqclb')
+;
+insert into t2(a,b) values ('icgclfjoqsbpffkmtqhvfdgvpmpfzgnoxzffdwliqwqirjfazchwbvkkspstbhqzriohcwknldknzdhonakxkoqioxqenpxcgvziymzhlnbpokxhgrbipqxlifwutfzvkaiajsyhkiegfabvkqgwvkiategzhkdgblityqazhxsldcearnzocwapivmenbzxtvkozoavpqlradqfaomtzagagoijegh','cnleimegwmhauyisiyhflrkwhwzgxgsjlfjlgsztdjgqaljydftmrqijwegokifnqzuggacziqodpjkuaecrvvadjsftfzgkcviqmhpypwkbkjbdlxvklbmcigwlqiypqvjdpojkxjljpofkrovfmafb')
+;
+insert into t2(a,b) values ('lyclyfulpbnmrzdhevpgebsvgkipgocmxcjwhegieymgaoxhwuyndutqwepezkjwgtfxwyltswicvmsvihoykprdoyrcbclgqgtuyszeavgrcdzeshybofdjjifnhxzrxlmalfdzc','kkwjbwbjoqwydkmhkcuxctbzecqiozcsntncgfbnkdyfeokwdwtsbvffxotxfjnmcxrmhavguaaxeeufonefzfosjcwgzquxghyrrovxjcmzumkyhnzpllzpmarzzkfq')
+;
+insert into t2(a,b) values ('hieiulacczmfrdkvemlwlhhlbihjavcovfpgarrdlgjuaftbfufrpuhtmrahmonyaqxzvzfmqwqjeuzrzkkdqfdiwrlaumqfyfjxtreyzeosknqtvlhiplftvpmljlyyzocskgaeckemvjmendxogfpgcfqedmvtylomialvqrqknxnwtehisbrthzayeqqsbmqsnfkadsvibid','wlbladldtewcgndmzoefxxuwqqztrbqanmvlfxigpiwjzsbrjoyfxbsskjlxosecauflmkdohsnvkxkaqtqeohwcajzdflxcvbcrpgxdhuxhkbuiwockbgowwdhkzchsyithjuptrfmecxlvuuwkemnsykbavwuttkyqldzulwnidvcvnakt')
+;
+insert into t2(a,b) values ('gmefgjnciyjusujbntpnitarcmccyctfwyiihnpcacugybmxsesiydkidiasixqmtrfjmutgobblsldlovcyyhrnbpkavzpzdttsclvkynsksjdktknmjarwyxbmgtyhgenvwumtwaklacdetfwtrkflervzrrgjpyiarnmqidoyudfircbrvmznylzadkdcambyulffxuioemsebkcawkliaonhdhnxrrlgfnaehafmeaualhctxrgsyzkrd','urrjluqisbewzewyaherfeikmbcawbemhnwvuxpufkgsjttavtkcazptosomfetmkhdzdlhqktcklxwlfwnotaemzjuaykoenigfkswiflq')
+;
+insert into t2(a,b) values ('tudkjjipvgupgrkivyehinxbsuxngspkznromrcglbwhjoznydfeonwkyuixnmrfwpkpnynujgxnkxyauzephcmaranjhbingcqlqgxwdbqtwjjhngksdbsmgnscuxarbiscdcsrbscsamyzlgorbryxvmazmskxpppqgdyseokvhwrhqahelsvgdbgewo','ynuzzjcpchmvmuzuobmxfruboycbobfchrbrclrtvauguwwdtbyrjewktvqgtaecrxrrypastluytpjpggvmzlwjcybmwaexfqxbxigncgykazwfkcqoeoanfhurzvtoglwrwzwonprmmndmnbbjifojnnqbqpvmz')
+;
+insert into t2(a,b) values ('owbzqai','iytkpyzfmesfsgjaoxkljzhpfyqigindmtjaeyejpjzsyainmzegwqhrdzodqkcggwbnpabrygygflwykkqvygyotxazpmyfhiiombgwwbnturkdekdxpxjq')
+;
+insert into t2(a,b) values ('fgesbampqkmqirylynwuzqkpdtduozcabcnwzidoiisohxlrdptvrndgsgddkusqnmkbfudwomxokltsiidvnrokgrvdeatybmuhmcwrgzkjadmebyogrznyygmksjjsykddhrmjigluytelfxcnkwcjkqnuyhamrumqgvsdxtdrooxzzxalnerzy','ppwpwxfiooytyinwyobyutfkckpithdsqivcsdmyoiyyyfynbvgdmvbvxhuibcfbscwlmmuljmjyqnktvnieqwpjmrgebxae')
+;
+insert into t2(a,b) values ('kfuvtqgxmmhwhyuriekwsoqlynmsrbyforyghsdcvbqphvegpsowvuywyizhtuxkfzzajerwvloahxcwadjsevdptjzoxllhggdngzqzfdwsquwosqsyxtvjegzpposydwtgsldzqvpsuhsoipyvbkvgxghflh','suxvydwnqxkubjrccksksrdpplwdqfahtjvhxsigcrnyybqisjhwavbxlfycgnlrvkndtrabealowltmwcafzzwdytvfjwdokvajqumvyimrwhycgitxhkhznv')
+;
+insert into t2(a,b) values ('pqdnkavcmuxnfpnbthpklqrzjfxxpyjqjrkhlleosfhpptrirwhpnlcaffcduyqtjcpqhckhtbgllgglwobpkegybvliihruakezwlxfsgbehrwyhpuqmollarvoxpbqyyrvkkgsweutdmlwpdmltdopajdkcqwezemjpnnisscdxzimpugdbtramxfaxzvybyaodsy','nlitarjxpqdgwedwwfbermzshuzfhvrsjejlqtprwttkqieptutulgoovdectchcbza')
+;
+insert into t2(a,b) values ('uoktkaiuyxlifphgfzklbllnktocoudnjvomvhlultorivlorznndmiqhsdyolnxvxucwumhichuqsknwtqtsnsbvlzi','dytkxlhqeyqtxnvp')
+;
+insert into t2(a,b) values ('azxxjnsdjtvwdqofwvtemoaavitnjfecslnsyrsuyortcvpznfgtghpikzonzclo','icjjxyxahmggawmzuvihrwsqjqsshzqhsruxicdosdqpfzspzzlxivozmtfkjpznfyegwgcxdpchbiffhwfijdufsyranfofvtjyhvzwnmgotqxukbumcwxabfeevldmqqfbwalt')
+;
+insert into t2(a,b) values ('kqufestcgpgzypqmcnaxrryhkbcghufeaurgqczjziumttzfvyqhrzgctkvtohmygsnykilfkstihocdcvxzswwlmkrdcmmhwrepyqehpzsm','crgmxixkffmxnmzt')
+;
+insert into t2(a,b) values ('sqbdinrbppksititurxwyevhatyrrcfuywfwudxwymmdpajygqzkyvsxdizvqhqkxiftjmvnckz','opxtzkyemopgswvkrgwxdifyccqdxnxbghehbrvbkhrtfpuvupahctwbjpjmdnvzrmockbsjdfejywdmlabjhlknzsltavpiqmmpntyduhyqdkgpofbforybhhkytlolaxszszdoqbfyerrbsbqjoofsqquhdpgcbkjrqzusofnbfuqpowbbdynjneyrwfdmsplojtncxinqdhvgrvjxpaftcscxjtuctpmmpmjxsxgwomoigbnqgbpkmoc')
+;
+insert into t2(a,b) values ('hmnuiplnglpecfuoqjjugxyolgbluiqthrqffjydmsfrxpxhbrwvofgsbmfpnhtysyljakpeobwdankwqxnlyywzinbtforvutlakbhzalznxqwsbroewbddyxqnhniygazffffatgeattpydzqgsezhfznwthqxouqhuxtzikayvxmwuvdymmgybfjeyerlckjygucfbrphlzgmoobclnioynecf','pagirfsuuayudkpgdzmnxuxgupndfrcaudisddvabrajmjnhwhsvqthjzjtqzvvvgbqejhcsnvmhzmumuwcaluasoojbmwoqvkleilntbxxkxlzqrrwehqbhvoxyecynkryewbjnptslhlfomqldnrgjrvdkeqdldlbqarzorgqeibbulhblrsifcsunuvqfqofsvwzrzwxejfsvmrcjkpmsireszzeuhqnalkmvnfhlpjkpf')
+;
+insert into t2(a,b) values ('dmyvjinklqrrzyfxuefwfsqamgocfhttofsohtoybtvmiaaykbvywunjctdlloirctxbopvsbvtxthxxogrrsepa','worcqepwmfjybwxxtstcgakszgooemcadoerunkxksozaineqawcfsqtyvlaljsminqifjkcfvhzms')
+;
+insert into t2(a,b) values ('tdjkneysxkwccjeaqcjyhcrfbnjgsbwxnawyzzxrpfrmooqlnrebdmqpgetinlqqybejnqzzzrxzpjiomgfqobkchudwnvnrpepkqku','wfoiiognhmeosukhhjahhzdph')
+;
+insert into t2(a,b) values ('dejiernwceiqtjudmhngmkbdicbzaogymjrojvxewgbdiuaxunmmvbssyaqrxvykqruxenqitbvcqnaedpcpcxeelurzjjfflamwcxzgku','lshjwqkaazpajrfrwl')
+;
+insert into t2(a,b) values ('dsmovuxarjswqpbmhmcpycelinfawpwtgughembtsbdwxahexhtgtayjluhyjvtbfksgcnuemdoeythenjlgodeyirxqylhooogmbdrckanrtsssyknqefbbmegsxmikcmhceqafmkioowpyfcgkdhxyepfrpgwhloiurabdrstbwnekaurygoyuebqewxgynkqbfgzjgimwbpijufqhnohlrzwyynqkul','tnrirgrwvmrhogxkeifaasgufvvnekpxvougbvcxebxnndeitgocfalxxxewcqbpddqbvrotoemkcqoevudvexasoqfozvmmhbtvkeajhcdrqbovkcgzfrccpskpbyumxpfadoecajyuvwsgwflclaurcmwparsihtumnowrdyjlyvpmexemzeqgfiqqdurp')
+;
+insert into t2(a,b) values ('ucsopgdzrfdiwailonqqaxlsxfysuhunwctbqiipbfsnrcrtydcbtyeqvddbqubcfsrncbchlnumyoufpchqxpldvplgzejbfoaapksekdpojcrq','ibamrrbbzwkuerwxzfywgpucadluqebahsnanczbwxsbslewxedicriyxxfmakarbdfjukcepnnukemjcmgwlhjnqossddhtgeidhtrsnjdxekavxnvcjkfwtbtftgqltvlksfwgllnryqaathhaoqebpaadqwwoqrwpmfujcbnkqjlhzehmhfrdnpxmsvptfcqaxvxhpmxscugzzhpdoldwqhfibeawvppdjszzjcoskuqubmtgisineim')
+;
+insert into t2(a,b) values ('vxtoiahijugxljpclwefzoebykdwvjogebpdqtsmwatgnjfmddnbylqqjmfbutcfffc','wsupzdkepxvnetkupzcinvqusakebrfxznrcyjheikqedlielychispctunyapsjfqsktlzevnvzoyqvxjazqedlulkvqhqmmlofrndogzhiqrfzflsrblcmcgtbqzwnqxsvcggvkbpoyesglcfnjnfgxqtfroocwzzzmfypnlczmfbsaxwscggnzqmsvnheefkfqeouwqducgsjftszrkycradru')
+;
+insert into t2(a,b) values ('sjfreujwfhqfqawlyqsosmcgwyzuggsnfponyxnwmftyuqhfkvxeghmybbdgvsmjyyjjilwseoropckminyttobydjbmgmzmedpfsnchgkfsnfnlhucljplcnhoabzlfjbepyqxfvqqdjdctxvsvurqufgvkwzcrztzavgzngwqyuevpuxnsvwpnvjrjfaml','fuoouvtoyavqaoxwpiqbyungwplpvtcgvjlapsqgjpirjpajgryblaunqjpmrrewcthxlqbvromgoceqdnvldyzsmwwrfbtsbzvztksyclnrpnjsszdpmyqqocbewtjvzo')
+;
+insert into t2(a,b) values ('imionwvbzlalcjryhjqioqswslfgbeaeefzxtttnpdqrrycikkbstczkdmxunvpssdjeqimfwjwsqzrcqky','wdacyggzorzjjfxfdyyrxrqaihmatqcbwzwhqficyjswcpeemmgukqhltdboqnhkqpldo')
+;
+insert into t2(a,b) values ('romlcxnqzyosiqybkgmdzhimtkhcqkchjorfzbxchkbulduiwtgkvovusinqumlhbrllbpahidmuasgyditisjqibzvhwqlmihlnbe','frczbwzweri')
+;
+insert into t2(a,b) values ('tsmllyrksguojdxgpcmyyrmlgyowmoizvtpuewisnugzvegtzsmkdnosgybasgvgszbanohaoklyohfgjzfaf','kvfyzdmoijxyrwwqsdfgdlxwfzfesyouyicuxyutprjnivmamycjewylvqraoadhwiqtansukkkclybphcqwzjgucxsxkrgqofzuuktjtdkwxmcusmnstramwryfxxlaksduevjopcvenrvaybjdtnzpaxtfayewnshqookxscdrkrwnnzxvwnnhohjklacwvkpkmtpclekdpzdpalcqjqexpwoylwlglvkjqvx')
+;
+insert into t2(a,b) values ('titmihbntckerzzberwfypewkmkrqwfussg','')
+;
+insert into t2(a,b) values ('axjelibqxnkcezwmrhxhbbpuwuhxoooptfjwoqnckkrmsbksowfzztqtwmzosmtlzamgqmywykgvataapvfghboflpmexoyyaaemikkajrqwvodbjiycjnkfrkidowxiatjbsnqpjkxdenwwiqwjfvheasnaggldsdvrvowusjtiyhfrhffbbalregzkhsbadkmygqqomqzlcajmk','ibrxeexhoyybdknlnqgebdfuocltjvrfilztzxffkdfaovpsohjngqcolewtqrlhytucabmfggucritppbdynkweezemscmqzdxnbpbmhiygwnptwwjlymnniraqlaiwwwwzwuruhzbytqzjfgaupwnisenatrmxuglsjtalujzsuqzxrjfobfcfxskyqrftigntttgmznzowhgssacsocegi')
+;
+insert into t2(a,b) values ('xoyprpcpqinrktybcofsglaxtbqprknyfgtuzxwxktvzpifjegtekfzruudabhwloiatgugqoocqcalescipplytwxpaitryiobbqnriypcsbdbiveafuubjyxgiygfwdeeq','aahdfxcqezyeiojfumhfnjekehpfhdjdmbcityc')
+;
+insert into t2(a,b) values ('pzkuqokzjzmxzwczafdbjxgncejourqrnngngwikbugmdxbsfezgxzggxosdvmhmbsnvgkahhqdtrtdqcxedwntjmiieqditfjzfogbszywxkwsbetmpstznmjqlikawftubnposlzkhkbnlqpuevwnihvuxqvtsscqjvnafscbbenlfmgpjaowozftxjc','kswanotomb')
+;
+insert into t2(a,b) values ('fnokbtnhrqixuiwlnbwpavjnrmipbfvgesffexcqzclwejljqvjywvflmwhvevpglpbxyaznqbwgwyzofpiiwyptn','ebqoyvmplyivelsqayofcvyynnckkjgrcvfhrxigjxlkhqamfjtattbaeumsfpbqqutyyhineyfvwrdlcijhvtnpbzzgjzqgispsusnclhphndhhqrhboooqdzfshjusyzivixjeunelmdtjgjawenrxiafbuyxzcrxbuseumgndiqfnkitidsydirwavymsnkuqtniafdkuonwjnjnwrtrwywwfkurzzdibgx')
+;
+insert into t2(a,b) values ('tjoithjdcocmdbjsrkywgak','jvhbmpoftsvcokncwoplskaycimiwrfhgelbubzxgldugsdzpvfvv')
+;
+insert into t2(a,b) values ('lszmovbwcdtylbrjgyaj','iqtfllbusntewgjbdeuxjecbyzqvzgyiddsglnblfqpfpqxcqfsnyhhlevgkbxptfjjoholthbylislurpfqurdepcvsakuqnavnvchrtgrrmwncxiqf')
+;
+insert into t2(a,b) values ('mzvnzfhrlmocxjcmljeufanykkjyeojkysegckzzaylzrrvllejqwufxep','owkstjwjvpletfuubwpzkdkmydrpjcqrzfslofuajivugdlaasqfocxxa')
+;
+insert into t2(a,b) values ('gevcsl','vvubguggdvhnqtwbesdjjhkgnfpkaxamtylgrmhvquuzkohkzsfmwlptcofedvuusqyiwknckophivxzbgejxllncezxbzqesvgszbe')
+;
+insert into t2(a,b) values ('qiutwdjqdiyhpvoiesjjffxfbyxqcbopvnfyltsinrkdkpesocleopthulcyxpzmbeciuckovyjfpyuqqcqipzfeflbteeggmysznhhukccvkqoeppedtpjnrlcbbhkdqbrnlzpwvszdcqirfkbtqbghmquudgatmcenfwghwmmbeqfbzlkwnfesdhqrmieixoopgkmpctglnidrhgcwxdneqanfymoadyjrq','gyqhlgzzlhmvmyfqvdbphjyntbgqgrazojcqwxdeabxphorpeshonbddoedikqphiryltpewtseuumxpuhziljkyhmjrzfwadbcwklmukhykkondrtzwqzqcoumnkqzdtiuoooqkbfetdyksckaiojrzliipghzzfjyclkhqypemhtabjplpwcjzytvobknoadswfyvolcgzfkcukxcaeinqzsubfyvoioimdeszwjvihbinpzixbtuts')
+;
+insert into t2(a,b) values ('dkxcktapqwzsulwfnjllnorriudutritenjujbzygsqkzszgssztblakltboemzaetcdpzdrzeoewqaaluyehqrhahdnetbweieoqok','cdnuxswckx')
+;
+insert into t2(a,b) values ('fiiujpgvmmfudksbbcjdhkxjwfrtuwxblmnusjqxajavsyircstkiekzxlkzgnjcpkuulgdftsbvrdyznpbvhvpjqywwjkkfgcmbyhekqg','oomxdxirgliyiikknstchriqwlcqejlqxclclsqbqshevhfihljprencdmfholnvxxqygcumpjleppgn')
+;
+insert into t2(a,b) values ('qiftwqrjxqmyardgvsecxtbwuxjxedomqnaqwiloahqotpfdlxopnghntpymqvnyfxkqdosr','quaihqlbejrhephhfapzocltdjaazdwskvycpk')
+;
+insert into t2(a,b) values ('unzvamekwsitcqkdzmdhlqhstrfvbzvegrdnhdvvcqlghbxhpkhkguernrhizcrpagauhywhfnneiuwztiyzzxmalfnbyxqsdqlwktiwzihdtzblabvisbalpmtixzijvlymaaqpcpaiejthjecvbbkoqjcqxgvllzvnywuakisbuiadonzwhptupxyamaywsspiujfgvfrqbyfplfjlnhfbfyhashmbcewm','nysniuoypgareholntmxeardbnswyrpxkakalcuwatwavhqsppnkyfgxzdxekyfbfcfgazyqwtauiyiknmpjyycdjmkpfnidqfrjfdtxkfxrlpgxehgylpxesnftpipjeyrydcpbkgzhisbkeuellykptrgi')
+;
+insert into t2(a,b) values ('wtmpvftbcdsmavgyipiwvsdggjmotqofituvkhiw','ozmoxxkvvfsjdvzggqalp')
+;
+insert into t2(a,b) values ('mnozaizhexzpqwgcompthxwasykvyttustmpkzpbvlvloyflfxysujdippvgljhvcrnbccxjeyystynhojxngukudhhbwhqxkcowuzepxrlpnilatqnarybcbmitewkyndjpaezjzlwkmdhyillyadxrtoyviyguyahnqpgspuvkcazpxwxbzesayvipyjgllljphpltoguuqzcclmi','hyhifqvphcplgybsbcntdumsotezytlbczdfwiflagrjszpmw')
+;
+insert into t2(a,b) values ('njgqkemyystvnevhslusuplkpwaxxaromgnvakcnghxiylfpvniyhrojvoqmvzqjbyrvyaubyqkhyepqvrhxbadakuwxkmipgwcceifchmolwojpcynoqkplwhyynukkjqmpdyfryqplkemnfckbqydwqjydttrpjrvuqldavevpafosqxlfbpgtoyumgeihhdnnlvfxwlciytwrqkszrzvysombouiefkoqkqkz','nxeaamkyyoibkwmjyjsnmjckrvixczksxjvorrgtpqncocmwkhthbfmuvqghrvzasqyvlrzidubvnzmuwunyjhlvhfwoylacpjprcudtzrjwxttncyvyavtwidlzdodnjqseryvmfpewywcnayqtlarejzzwwyjddireeisxgfojhlccmbbkeuzmkajhzblsojdgjiogrfgzcmxmwgmsvsxamfi')
+;
+insert into t2(a,b) values ('tumbsakoomsnqpmxkukngniurngttnpfpbekqsjyhtisayusnnegodoishfvvbgyobemmmpirnzjwgikunyiarmziwblcbyokgxddnnyvcbzhvdgzzjnjmdmxcvshsrpblozlndzmekqlozhtcnywfavcxntzgfrebhivbomugfhtc','fdmbdlkpuriuel')
+;
+insert into t2(a,b) values ('asurlcvgwzqkmqmfyzxqcniiaqmtwcoovwqjvnurejrrsitkcz','lrjzxuqdryxkbfudrcfwvvjbrueoxkko')
+;
+insert into t2(a,b) values ('qognltwueynxqqqooqletnzkuqttlooitklhzhtekjitlrrtkdncnkepgwfsgluqip','omheawczwncdtvelnieymtvoxfizbnadrllelmbkfmmsqfcimpjmecrokcfloilqsafbkfrkvajebcvrljzapsblmvwkybfjykjdzftbgozptdqxgivoakdvvhshpmnjxmflbgpjywfghoyaxnahwzcsfliuuvpgrxomocltjnysgtcugxgerxjxlmyldkzizbeydmajgmtbqxnnbqtyxhwxfxywjhkzgzkitlczfqkmfidbcvmophnjmkfo')
+;
+insert into t2(a,b) values ('qrbiwcjynxgtyzwobsayvqyomqmjlcyfsivtqwwivlyhsaeetbssklkvfyjqdazzrikrauilqfaepqzzgankgtuvubcuizhxmtoxktxznqiixltvzpdjphyyijdwkoyjgylguinafcekyeqniszvgqkcqgkvpuodfaqvdnlevwhjkovuldidhqdkv','cchqrgffiaspoirmaafnwuwabtdgiddhxijffw')
+;
+insert into t2(a,b) values ('zhbeidbtajgzhqbyhifsozrslcqlmkdnkmtkogtdfryaeoblwrgefzclcmvlugaeuoicwyg','fvejdxqfvgkemwvenzuczbccmmgithcsufprqivjtmtwjomqzctpzyxlxogbinblsbaqmjktgnlrkwmbffbmvacgdakckdmrjit')
+;
+insert into t2(a,b) values ('lyyggzvlwazvhctuiynskvuwcodiynepqkmiifdhlncgob','hyttckgipxetbdfjrqmevjlsfgngoyryjtwiifrlivbwoaoeyylsehxnacnxympyjswbrchatllqplgxaaxmnwkqwfegguqxhhrnykjaqedxbsueihsztxdasjpzlvmtrezavzvvogbdabjzhwgdfbtpuwgbdnatfkrpleeltwbbqpqlettbwcqhtnpkjgvrpelsznophzrukzvycrnvqm')
+;
+insert into t2(a,b) values ('jbxgrjnltcogudpkxzwbaqrsswxqcifwtsnzdshtwvtffnndqjmiursfujvilrkrvqqzmstgkophlzrrwyixglabnjyzkiclixclervxyvzttwdudybiccdqencntlvsphxbvpsxxvgbrhyhcxolcnucsomscpxljuvbzpwuaschsjt','tkhzxdykhburksafjwhepsuhzzmjlmwzkiblsoekbxjgufnaikalcfzbwsjenrwcrdqyaojbkllunnlseerzca')
+;
+insert into t2(a,b) values ('ctvfhmmbeqyjdxhspnedwtotyuaghpyavmbbopdimibducobhywbcrwfrefcvmzxtecdqhspqaawznkgbnojhhjkozjqesxtdjhvbpfgqbliyllwglljsyvtwjzdxfwglyicalexvbvkdpdsyifhtnaqbuhedgmkglnvnvxxdcthmzwcbrvjlfgbwmohwbhmveejcghhciye','owsmrvugpmnznltkxyuclyqkjvqinyevkxcerzyekmohztzzdrmcoetconswqcxohsiavsyhywbwdfpfzduxxqmdrwycjqfxugznxpfnefkspyynwzwaczyfleiyuikrnjmfuhwithuswzvrfnntlgngsfwtsgvigfzwplwvqkbvomlquxcsdzizvvlhudsuocmtdguwggiuawhnhdhltabegjv')
+;
+insert into t2(a,b) values ('ispsfuvbpyivtqnotrtundzuholwtggeasbuthnxsxspixyvnxuczuklojpprvzjtzbmqomocmriwamvswindwhyrgpcasbkdnzrdfyfmoccnbfjfmxrolasbghuxhrszrhnoqqrsnvbntarphvstepvvyrjsjosopyvhniifodnobrgmwxftamntpalrnzckkmkzooicimaodeniyfhgvsiayuhdpclunagauo','quqebglybfjbrrjuzhhfpoflxadlmldozuukwpygqweywwjcldqdqtzdclhzlhjryjgnmiygqfdusroaqgcyspmjzgawxgneordhwqivxmhiwhnaifocabbvzedineoobqpcxf')
+;
+insert into t2(a,b) values ('ooikwfceqxjuckauuvuntekfhbavacumfxmzzxwtuurovnewzlfuuxncaxggbuv','nsgco')
+;
+insert into t2(a,b) values ('uoyvjjwgrgeepuzboewaqbcsvahojnzgfbfemlzrvplbdvycpdcnnzqqmlobsivbnbpibzqqcbxxufyxjezzopyfomwpurhijrnvtxipcvbgsdcjgxaavewpngsonasmqdijkqngwqwkuiywnerkhsbksxwndkd','gjnsljwusnzkbegfcrluhoelezfqzhvobxngxfmoxcraloxxxrwenxvwdvrnxihyvpiypszwmzpayoqbbusdjzhsibwcnjjkoonulcjumbzedrcomesbqiy')
+;
+insert into t2(a,b) values ('hptcdzyupxyyataqfoyalygmemcaibaluowlswujipmhyhcfauqrszsnebdmngyvpaksqoreoxn','dgfxufqalmqksokebpmbxcuoacyxwihkibikqomvisybruqkalavsaznzryfmmvzyxmqfrqeifsirdlaszlfzhrmmginoyyebvasa')
+;
+insert into t2(a,b) values ('ubtbwfmqwlbxzsmvozlmbbhyxodgbfklgnivyxrloxwk','bidjzuszwzvc')
+;
+insert into t2(a,b) values ('zszhadzuztygvsndzqljllkezdhikbwwgiiroizptcytgbojfhbthckbudi','gudhmqkgcwuorvjeypmvhflbjifxedjbbhoibghwpgqhyanmmhoeyvgzhxrhxfhtrbxpkriulqhvrefebkixucluetmyejajokgfvlqy')
+;
+insert into t2(a,b) values ('lxtdjwejkxpzgvpceahnj','yxocdzjqivzyjysimiyzeqkuigxiespxmzddzjpmfmlcmursmnngxdpvlfmkyhiuumntbebgehiaq')
+;
+insert into t2(a,b) values ('jnnzjcoeomoxysfykjrphtzirvfnjaicbtfqqcixqwhdlfrvjdxzxewn','jwwktuuikjualtjaxrzitsepysuiugfciqznxaxdmgwqqdndzakfegbtrevokwxuxlhsngzcogepwxzsqezbbafpuifyoscggwlgseliavshwcojecobfecbjqxcdhymjxdieagsbznhceytnrfefpzsvkuomhlrslrookxoxlswzcsvjzhyhggugslzdcm')
+;
+insert into t2(a,b) values ('jylmorhxyvtwtsqsoikpywumaguzrnfgrwtseoguozvygcffujfhujplgjvvdswklmsmncpoaiicroefuymeiqxpzuzmdvryfonstqmzcspxbfg','fewjenirqcaxwipvzhmlaaofqpmmlcmp')
+;
+insert into t2(a,b) values ('ajykljfbpxbotbtqwpxvjpuuxvlrggxolcbvdangomlwbhbbnethhaiomjthrnhfatlkkeirewoecmdnqsmiuhrfwgnjbdidyituclbqzhbwmsribmddzmy','mopbdkubvjnhmvqrfreigcfvxtjkumtgyuuczyeddkpqxjbufodcdktcvf')
+;
+insert into t2(a,b) values ('wsxouemuajnwqqafhifkkadnwddduysdznskonysuwybuvekijhmipqlmtxzqdwncsimyqxmvcgcognlocxupxnppqaerttwqddztlkdhmjyzvuxmzvy','jsdiibcfjnuptohyqbapfwfbaaicyiylrdfdywtyvhequdyrwhlkeqrvenuaqjmteeqykdgjmzoslwfmnxixxbvdmhftwwwiamnlnocsddrwyicxbuarjlxptbnihillujcwzloggkvllmlybrbbtzrowwusdqxwpwkhkipvwmslauzyex')
+;
+insert into t2(a,b) values ('djnihqakhkoedaepo','falnvmbpenqkfpusindbuglvzilsbsbwirf')
+;
+insert into t2(a,b) values ('ccgjjelvvrqwfsceczuwnybkltnlqcmaofqrbxmxuewbkycgwswrzaemmumovkpwdycrotlstqdwyweyweetytnqzbmgiivguhogqunevjfvdqteiyiapnzcsphsdnagjktfmjiqzydlvcstolnbvtrtkivrchrn','duawvdkudlvhboutfexnrcavhotfinoczxiaqyjrmffouwytpvvonfiduynwjydlknduzujgasgbpnylrfqvzzllnwcbtmtbxhlklxaphbobujfxqzlbujlyfcddrhcquxzdqcrotaasuftwitixxgsrflneljvkfojtrhspyskiabikpryatnfsqjvhbrgzypnmnfwujzuysaebujvqopyzdlgrirptoieemrqaigxjkqzshl')
+;
+insert into t2(a,b) values ('loqrkcpzcdxnalagdnevyirpjiffnbdmcvcpreeygpymlmrsgvgaknrzlwujytwjfmhkljqtuooojlykeewgetmbsrhpkubyznvbmtxxhxzdtlkkbyqgrjajjow','yznihcrywtlroaejpnlptwvqubj')
+;
+insert into t2(a,b) values ('gdijxwthndefgnbhhhqdgyickrryzmtbvzvblgyuetwwbhlccesiqneyuxvovkvgivrismhcaorvadwabptjo','ybqqyzvgybkdufthrpgzskkliasrkoxvgrklvacvjutrvljwbajclpadqabupnbxaqlodgbeuzynnvqlesmwckkzkdqavuxejigejwiwrzawemcmcfmzgcfrvqyuxwivww')
+;
+insert into t2(a,b) values ('fdyzpkgwhojdbtvcnllrjaykqcdxttgrshsvythlqqcrxezbnfdpsznpubnoloozptuagfdrolmsowhamplralxehpuyrkfokajfdtwxolugjxvyzwcanumfhdwqtmvivrnoteopzhxdfedqvalieqobjfpyhcokfblffkhihcsjybdxurdbzwpidxyleemxtktaqzbtsyytccltvjntnglbmxxkfbvsktahrjfapzan','vorkzyqvjxtmcarkqgpzkhtfgupuucekpmboqqbzfkmigcuiorlhlljdgzrdnnxlwcmqbjwercwpuajyghillhasukioltbyzybqxvbhycbnebsqidatsvrijabphgzodqvbuxaudryxxyuwhsmydokyvirzznvnfnjruhcycvxutlcraijfrjbwtovj')
+;
+insert into t2(a,b) values ('uqkixagsvysjkatwfulvaepmaplziwrmcaifkmfxtrpcqyziohucxdpvpkuwpcxjulpgbefmfofrdscocjeyjhngdlleukkkgitbuvjoezebmdqqmydizaqauoqdhuvevtgnxbtofpmnpacqwuzsjcvmoxtoevvslfbxndagyxveogtysykpnmjqkrqmmirnmcmytqkebefyz','xqydbvuddgdnzcgwofaqkkmfcuptdwbgkgzvtkdhcluguqvidwpibbmnqgntcnzrrlwyitgcadshqbvjemuiekdpomqrsliywqklhobphigvigdopsdjvfo')
+;
+insert into t2(a,b) values ('yqmrmyimykcthfxukzcdclsqrxjrdcszdtncowrtelxzcbamfekmogirlcnoequkdeuafxnmkmqivtnmlzsvjrxkkwpwgovvexkqtkzpdbljepnaqokyjckyfcdzfbghe','nlxxxocjoartjziybprcsxybpvrvughgdircdtetpluslotplrlmoudicyltmqgsanwetgunbflzufpazvtrc')
+;
+insert into t2(a,b) values ('saixzzlywqkwpsmulitepymcjemhbyfedqqivlvqefwbwewtfl','mddnyoqqurtghjlqujdzpjhhagiiqvwnesaolxvkznalfvpuolzvoblvddqxgtqaijuvpjppdzitepupvdmhnsvwidlaztjvomnzsulutxcyminoesmkyxynygftbjtlztycmterltwavvpwirwovvycquyebjjebhvuiybjjrjcwimhktptyfavzsvopaqixvgzflibsynqxsbyky')
+;
+insert into t2(a,b) values ('ceyydkzbtudfvjhcxihkdwzypiocxbiltjvsqphtafojlisfhpkkbabogohduhaqebrmxwovfgwlwyegwwgoveajbscjotxfklydtusqfxptchbu','tkkzurxulxlgewpkgdbwjmxjgvxkkqrkuaqbdpegpnyrmlvtqwysdzduupgbnhvtgrqkmljonavlyemtkg')
+;
+insert into t2(a,b) values ('pbrjl','ckivzkkhfegtayzzyvisabkiziuiddcmnoenyuzhirysqzilcecokiekxcjqrjbqzhvgeuyqamcxbydypkegidaetuniwgtiqsajgehidqixlrytkqllunulzxusvnhpqcdby')
+;
+insert into t2(a,b) values ('subxhsuuiwogmcuepandweuseailusvbkfineka','wrlztkknkhvswojiocrkrmdganydofkibmijrmgolubpntmtmnebutulfyomxlngbssuslogcjjvtwrdrotcuqanztpcqbrxqaoudnedqakvdtlciighoxxveagiyhqllzbnfumrlgbyrywmrhxltiptbqxtbpswvojxwraokomojdgmqeenoyveklximlwbemsetbbgzvxanqucebnzejowmulc')
+;
+insert into t2(a,b) values ('slzsovmmfatpdgzltxdgbgidyzxtzjbqrtanqyotgegfifkkdiqhgiluaukujdzlpmdnqvqantghtvyleiavbhprlsaqaophuenxikehjkcyaephplqpxjzoswhcmkvvdxddtxsyeyhshiyriuchkosxokbwgrcwlvxtzslifgrjz','ngjkttkgntijmkheewotjsxyycyhkivsztnvvrvebvnmingggepsljqymtuuwyhthjzayroawcyihxrhtjmziygjotgrmwjgqbkizultuttayekxvnppbnpehzhshcfbanxrfgbeezxwiicjkcjpklnpbbxwbovkteigqxhtbmhqtpyffueewwgzjpzmlcymjrpgexqqhhzdtuifdcxamfhfdapispzrgbnxikfzdvzezol')
+;
+insert into t2(a,b) values ('mphhcgbkdsnyduszdzgubtnjucqfqqpfvipqdntzuhaiolsaecpstanalboieirxyxmtvxqbdbsoyinhzzjqdcmhhbhmgdocwhlbkwebrytffrmaegxwcetvozfvrvteohqyhbhmsgjttxuiqezfqqmnsuyhizdxwwefkaccrybzisdemlgbbeomexnffhvfurindbsxbstftzuicy','omrgwchqgziowncrvoynugggxkenmhaoacxv')
+;
+insert into t2(a,b) values ('onzrgpvfuxmcasiuiknmzentqokepzivzqsauunbmpvxgsepdbfbgqbdzlhtxcdngabqolypncvbe','ixqbxeoiwbu')
+;
+insert into t2(a,b) values ('hawxipfkodlorwzpeohqprffaccrgjiervxrjhjnmwvccpngzcnmeqgywuhxruwlpmlifpkiagaduiztbummkcqprevisnlozzgllwlhkmfcythwrdqtcqofj','uwochjihimmvyxvhkpikuhyvktrpxkdebuzlucloyuezoawqggfakmyanvpfsvprkpmkjaolatninedpfnyapexrsjiodqcwrmhfwduocjdtrccmuyjmyepkwzkdptfckklazfykbcivjxekaxafawlhivpikghxwbabrfxhdjidceub')
+;
+insert into t2(a,b) values ('z','hmrnazhqlvinhhvwvxizbpteebrhhxpakqpaxiyhnnjdrvrehpaqtxbyfrhrdbmjqbykayiudhgfykyfirfkilsvokgbqfkqvivxthozcyptovrljsyxxxdibeuvmgtrgeyronoprbfwwsycbxcctfbyzqittzeleuovpkkisvohtmoterxnalbqdnknmksl')
+;
+insert into t2(a,b) values ('dcciuwygjqaqlngrjjraiklgkgnyceoacckhjvvzqariljkscrlspspibogtyexilvlligkunufmjn','yeszmxverqbhcubglfwxhactujjwbqgptohmbfpnfedfmpgjizuykryibpxstpedjnlqsrnroobuvuwwnkawxbzhbuvtpevlqhwzincfyktpuojwivmfkpqxccckwkyygymbmrnfcblmnb')
+;
+insert into t2(a,b) values ('kgwipjpysmwiixkosxunmxsldibvthjrvwnkphksmkbujyknqbypwiapeyqjgpxctrzrclzhmuanommimwbvdxcapxbfszndckpkiugtxemmiynimgjegqoomvyecdmkqtcdqnrunoikrvgnbvztdiyoiagcbivlhnoalpkreqhf','enrajzis')
+;
+insert into t2(a,b) values ('bgwlxkdwrzaczxjsacegkjvlvysepfibxhvabkjppwmhrcakmhnxaxfpjxmvhcnyetxkrlfjarkurzhmytywfraogqsdjhifbgmfqxtidxlpltwwuypudwffrtsdndfbhlwmbxxcuvoasczfogimppgvetajwlwsagcixkosifvjmlbnjfbsvgtqqzngruywrxffbuzkk','lyvivjifxuyawtcintyjrypwltsxkkifhhehgapjnkybxmyrdeyckqegnbieizatckouarjyavncgudqzlrzajbmgxrmzuffysacxacwomixkyjhrwcdibooayvlzxbfpmgculxvawbwouyxfxqihsswzfuorwfjluojvsmcyajvrermfvbxcvmvxbfcrhgdajucvfothaufuzpohd')
+;
+insert into t2(a,b) values ('ahdyxntkwxtvcovaatgffydxphmuwxafcnfqupelyrtwxnuztav','wfxgrwfjrsceuwfhzzlmanfwtmginzazasnlxrapfbdfuhhmanhmpkxrfcvqexheaclxtvmsvstllk')
+;
+insert into t2(a,b) values ('cdnteijkchtfpvzhnwogrjwuturmzuotjtskrfzosswxzafvjfhirhmtgzcqtuywttudhk','pzvyhffrditgialgnbyxxwxmpphztpgevkprgqoiioorgqlazxgyrmjvsguheqrqjhbrytjgqesliqcrkphszgraidcnrdlmzffugtpbxvhauhmdoejyelmalardcojebwdkkpbhturpcdexot')
+;
+insert into t2(a,b) values ('jnozxgqqikhhaskszjdfcsbcqfkbuhprjokabzjicvmwkdtyriynexqttvnkddlqvotgkdtvpktwvkkgbtecmbuswbdhixpk','knqvtzitfznxirlcdyymxsicydmg')
+;
+insert into t2(a,b) values ('ooxuzgwtnjfjptxkwwrizjkpbwumsntplwkitqzhkjmwoqlfhbofqsbetnkzyhtalktlmqhwvsqprnyfshmiujkwrltnibgdykrpjulbuivuhiejjrgvqabkxurwvybfcisjlxqxzbsjudylsymdavxytcz','kvixkcsqsrwxflzeqpraflffuicouwqbayg')
+;
+insert into t2(a,b) values ('byoebhheylgvjxlniyyjvkulectzzfmnjvlkrgravqmiiouqfqvgefgtcjwmljtumgepqyvhehbqaxmpsinfazflpnkkpjgrrafletoazuyqqlndxipwqavnhuezzeluqcrhptjkcywwbgqgthdmnsifkbhxdqv','tvlarktpmmyupfhplrphkiuqgzxghsmxwejfwvwbizloefutamqzxnqpmglvahgqqqhdmeaxrofidepajrpkkluefjnuzrvdhjhfcggtpomty')
+;
+insert into t2(a,b) values ('mgvjdixkigwvbhyguwsficosxebiliakdnkjtrnugesmhtgnpsjfzygsnujofglcsodotnoejprxjhdhvnpdbfoemgncsoijqvzxoihqsyqmpyjuqyluubwppjuutivrxwostpoydcmfcyudlvixyxkb','nltwnvvaioogvdpxstpqrrhuwhpquqygfasszkmzauzgteaulxews')
+;
+insert into t2(a,b) values ('xrcaifmbflrqqxbphmdfvwyqqkqshasecdbqtoyfkmxfwsumazbkembgaijguvljijgbwfqocqdnzretsfgdwzqmmzhubmxutbs','xxgkmrjcociqmazrmsudbhqgcoxsoajhhqraynmchlzbeasjmxenkims')
+;
+insert into t2(a,b) values ('oidrjcvejflfnzjnvdohzamjxeopimlebcwxgidasjsvqifzgombfajhhrzfkcaofqkabnevdxevalwulenwiiysroyxrhvwwshlqndvuxurlsjdilkteigwpolmceickaexdhdqwrhbcatzeareyoztupsnytjfpitifodixgblstpigcn','vpzygcmvsilfqobcednffwsjzgjlugduiutwfdlttxruiahncqhkaqamwwkbbdasxcrwgablktpbprhxmhwqidilrrcsdqteiezujsvmmewoyhlzgqchuvxmazvmxoyjbigmbzvjxgcyqkfnwztlvugieiivlgzywcwijmbdkqxlkudeoxhusppznigcisibit')
+;
+insert into t2(a,b) values ('llfvllslvtfsciauwhrctqcgfziywtdpqmwmuolhswuztfyyiqrhyxknhhhzztxsmuurthdlmjfwkaxwnxlikapvhexuoahvrxdcgfowligwxnftyuryzthaeadbhzxemcqqxlqfnntkpxwulglrczyqivffzaobzhgfsxkajwroixniokqxgqvtqzvkiwaavonxgdpqcrpoxzaxkwxwnfppwydgkalfhngrrebahgf','zlxcxtqwdmxeecjxivqlgwzzsownvobpqsssjxbpemqfesotwqjtfxdsqfxqrepzamvsuzeofvsjxntuzqlvufllqahdkbqrccztgrlmscxitxsfmsdvhryqrchxckeerfnhtapclyihubxeymxpvvyymliucfjxxfbswuubdveihzzrrzldnxarrttqnadbsnzggrvut')
+;
+insert into t2(a,b) values ('tngdyndghlplnamhhvuvkfpecekkbdjknxqztxrgjkjreepkvoqmtysesyrjsmimhztjzulvrfeananzlsrpnbqlxntobveekaponzxcusyczmdevfaqixaqlyckjbojhdrptwqcumbjstisbkiaqbgdmqbmiizvajjotipdse','jpszsuyeavpypoysqmngofmrnelhgzdoxlfkaalrbyqmrkdnzkuxkhocsrblriaouypyoeefapixafeywreehqtjpxytknbxmpkrparovqyeljsbrvhspmfurlmmkfuxrpgeqgsfzmbdmgvrurxprfeqthmouauhzxieqttwpedsqqjvzhzadarflwispvqumozevbtpziyhfjjogeyxgbctctbvwuoshmpowrfqkfzqhkpmjj')
+;
+insert into t2(a,b) values ('vxkkwvgoqnrlwvqphqnocperoouvmenvrrxwfoojiwhqdvkpmrhtjhkfjrpzcsqssmyuuulbjbummolonnpzurnctkzqnjsmwwauzo','znrscqfdhtzeumfzrzirivskhanelqopgttywtzthm')
+;
+insert into t2(a,b) values ('cigeijfndtllugvdsrxrrydexdhnmuhodylljlwslpopwqzcyqekrmskveamkowmgfeowkjrfunetzpmpegqvilkfzzzipcqvtlhvuvdborlctfkrtwyclxexmtizqfccevxytjprbbevbxwutkcjgrqchgfkalztepgadzbspiqkbbyogpfpaegweqgtuvuxvsrdpvxogaseoisyqkxee','eiocenisvmxxadbaw')
+;
+insert into t2(a,b) values ('lirqauuijhtvwocivqqpyecivgrhjfojstntvypwqjjzcaoriyhvbrookytdxbifhxyqgrhznxkacixlmqpdretyjcdhfpooqbscncfdbpubdlmqqmoicqowmiodhsdkajmzsehuuyassqtspgreizsjrdxavwarxqqxtqdfbaxhpugkablxjaxuvqqeqenmygaugdzrqrjgeomhanmslantpydznaerdfnjnrjfqyahpamxkqyzya','lwlqfmfkljqmvbdjlesqujwtxrqyvukerthwbbfkoxghwpirwdeuionzbsifhtfjudvfsanbcuiikdnwwhjhssgfnqgttqtqpcktnnuwldcaaewv')
+;
+insert into t2(a,b) values ('sthryzoimybjbphrjnlrlfuy','ndltgdoujlkpoqufqzcaapbtpdovljtesvrmhekyigumknwtppykfomtggfsgazlicvvovsbxrosdgcbrqhrqmvigsiryiccqoooagsplxjeycgctcoovuupanukgrwzljnxoesnvbrkdpgrclqsswslxeaqqxvxrrfexneptrxnkuwpcjdamggevoxpk')
+;
+insert into t2(a,b) values ('gpfisbis','wigtabzqnbaviaufplinluzesowmafgjeulvkhfosvbcuuwcrkpvkgkrpjqxnfivvctdbiiosfmtewzioqhzdodgbqujczgkgoeojmfgmcylgvwatcitdwjxsbivrtgvzzekayoujlkjqxmyahtvwnvicvtcsqopmxhgldticoszgoeoeyfavgmrpphxmjcoxhahawoaqirancayzolgvdecgzobeipauzyizmmksnaehwwawvbksywiujlpu')
+;
+insert into t2(a,b) values ('anjvonripysoltdrqytlscnzmrdaogyggzjhwnqgpkaiqvcnldixwzycnlqqbjpyullqerjvqwwxnecvgjitpgwpskjqbmvyxvdxegkwhshqkatqmrcqtzvdruhzdyucapgnyzlxeytah','cjoiwkxpbyuiqplsnnmddziuwyhexudxpktswdaakutqkpxdaebpkzeusaqofsysqcozieynlsjltjprapuvmcspsaftivrprxlisutqsuuttnyfaoxaeqzkcicyqukendfetkxkkblbpkrekejixiszezrwinjnavyuaefszbnufhvxcxstwbeymappbvxuapwsgtlmnryjyiqvgzqgfzajmvucrnhhiikrlgogydvbdofibxymgp')
+;
+insert into t2(a,b) values ('gjhucpjepvzwixelgblcixuzgkgjteffapihvayvu','auqvpryqgaxhdnnzzoyltzzhwsepjqnfplebrvuroeygwkge')
+;
+insert into t2(a,b) values ('ktogweacatceundijqwcsasjloueplshxtpjnisrvkfbqswchdiyfqqwxlvqquqyhwfixxifdbesnibxfmgmafqlqtiwvonhcuphtnzqkiapolgdhvpfmaauukjlfofakhseydnzkeokmeohbcvrysismobwyvgfgxlwzwmwmphydmpdnbvuplmrqelpidgidbfcujypresyjenzjkgvswsbcqytaijwlnmpkxrlsnfgeywywuqcprbgzj','ctzmtnvacwuvfhuxtvtwcwfxuwfacocmhhsghfxmtbgedvfqvncojbizabpjtewrqyubakqnedlmbepwjftyjcwqhrdjnndcdomdxpbezvkoygfclifwtacopgouxjagyawmzjrlewmekhofdheeypuqcoei')
+;
+insert into t2(a,b) values ('bxxkjpbbayuvabqhgepahfsaprovsvlkiazqbduiyaheidcfsmnqxqqxwktevnlrcarkxobtjuwfflshgjkzjtwecedumbteheiiiffblfd','d')
+;
+insert into t2(a,b) values ('rbtyqynqzmfxfghrkotoqqxnpccnivaogskchkeqybgbwwgralovsooptcotwafazh','ldvdfnwvczsmnasegkdzsbkyrravotzqmvumxazewwbjrzzdzrujoyjaruhrrcmaaylhlxiiguuvdxbbbjkdnvefmkxljoyqkicvddwczsjmrzddbjcudpckjuknaotxnpzonigrvxzupndiwyuypsuubuttkuxaleecgxljbygmdaoyxxwmvtrqmvoaunijtklsnwnbnorluixqnqzrroqginsxqfhngznjiulryspvepjggmjxokbiffv')
+;
+insert into t2(a,b) values ('cqiftgywlwbywepqcsdsoehmlvacdrjgypdkspubzkdujyonfgyypymaqtdjfckafzthmouqmxftxkdnyhbnqebsetbyoeocfwrhjbeuqfdwrttoduyvzthdknbwrubkcmjiyyprouagomoogjvcspakcxvhircpzowoiyfkcrdfiiuxytcerkelij','fjleikofhabvxzzegfcrvbuplqlghtvfuxwympmiqykpezlxaxcknumzynuswemwdjuxkyhjdbrtbatvopqirpkroaplrqfdktgqmqjiknrbpozxzmviifqrstjkriikcvgmidvqoscoyzzinqhzgzfcvtqfkmlrspkfkpzoyeuvmejwfitcbgfjmnhbauzlj')
+;
+insert into t2(a,b) values ('nzunsfhkokanzugqaytxwdzhocupyvygkgpxmueevxbawjytpybwrlkoepqgxhycebpmqzwwrawsihlmcvwzlfduxscljljisoclluaqxizcveblcepjqvrtrkmqwduheobtnefidihjrepfmkqxcxyxfkxzzvojrhpusmirjfwuvrwfeqhvekcopevzodlvwknimszqjygalzbthtnoehoajvvfnfoahztgtxfjcsmehwjtwcmwie','ymjkjotlkeuwxbvlyaqfpxvhgnlreispwjshpthbfebqvydigoleipfotgvnvuhjpqfdpfdosfuyexffsocwkuuknwuwqplsjczrmkrbiluqvoqcudtmzkcgolqmbwpptjzdhabnrgozowysvarxqaanwewadzjbtealokcewwdjvdhvcxiqurybwbga')
+;
+insert into t2(a,b) values ('oaapemtljzfxeyuskclfrxosvdeulvnuwuzlrgthjhyrcjgkwveiusspciocxqjqvktqccsutltjrxammfyuxlqlarctnwbyfqvnfxfuoxjgztyafnqbucoynpemnteejtnvlrnvhjifphioyxjtxlabcnlssbtmspslpamvhhxbpmcu','kdjyszyrcvhwcomaxldmbbmpheqtyesezivopomsfkibpnlvmvcizogkjumnmdmjosqzyyvstapuxndqnggkxmomynzenbjkxcijqzwyhvpavgzaqvwliyjagvkofmajamavhzrvbtubvnfhufnhbsyyudxhlgemhqjzkjxmguwzksoulfsnbqbxmhcbbxskxtugeytqmcaknvblnwvbsxbbqrpykqyroepovzrqjiqus')
+;
+insert into t2(a,b) values ('sqi','pfaqrvtlygcyshzazwhvkljsgybmgymgcqcttlldwsvyctaugyrmomztsuxkisupxiggcxzrg')
+;
+insert into t2(a,b) values ('kzlnvsplgkipdlejajydthpeuybdjcvwmikxmramsyyorzoxuipjbesifdwfsjjespghcivuqftmnurrkjxnuizuxsjlynfugohlivmjobepmtcqijhlwghqsv','qyedgsuajlahmcfonjxjptsijnvjbiltkbfmajxmhiffhfciexcmalsztjdgcgpuvfvxodenklyzypvflruzbkulsnovnhtyrketmgqhhcbyscecwrhexcjaiixuhiefyxctnofhdcggxlsdpajekizidiapevttrqplighcdrygyqfnfaquqtidqbszzpjnidrstlzjfhdhzbfgpripprjvhbdgd')
+;
+insert into t2(a,b) values ('ncbendwybhsasvjyejtuiqzrziyfhsrwtmonnizpqtgnilmkeadvrngbadnlwrxabrwwmumreyuzpnrajyroqonxaxsoojnjshsusrnvjfzxjxrmsmhflapmzrljyrgwmpwlrfizyxwrxyskmdwkbtltwppoktrxptipcqcketlndqxyfysculcalmsdgymatxyjlwfzdyjozapxdshtsifeklzndcyddiqgxf','qzfsegcvhmadxbgkortkhzxmregpcvhaflpatkeztxscbtuhzbaxdqguuuemaqaknzuokkldohwvgestnvgwkychvqpmtjiukslxvjiwkhtxmlmemgjximlcuzzjtkaxdllzopzuwzujfoixnjuaynffai')
+;
+insert into t2(a,b) values ('mclijzvhtnkgwypmqextwqcyuwrovezdanpqpuafrjltecajymvnrqldsnydlzkfmnozlbvpjmrttpaxoavtyadtalbuwicusahucwiornqmoefexuofzzhhvabvdgfvgclczxdytiweslizuqyxxbllkrhlfcmorxbbarbhniaetdnlnmufjanisksxhotjrzfombsigxktsnaqhwdgrxtibqbditovqbiduievmsnnsghq','zgpcfrblemnuxhxg')
+;
+insert into t2(a,b) values ('jqseislgztywrgknxedzmcqfjxkypbyzuahgjvcuphrymcnfmizspiawnrustfalbdxasfxvolzajglqbagvvkpwnlrctdajickkkdi','skdzlcbqbadqybuafbcubexawcsszbkcaotilerozliuvnuyodzimdtilaajszmpodzfotcfzzdlgixhztwr')
+;
+insert into t2(a,b) values ('umsvpydptfsmpixueggazukbemwnydkfnpjnoispantuljpewvjbfxrdcuhrnrgpxabfcckrkflzmkiusedjypspnonsxcqpoxwvhssnbjtmhufxfooldwfcrprljgwdltjiyortiucotuzbtfnmbzzfdlztltbmsdrubiauxrepvumijwfexuvatcigybbagdetpfc','gbfvvalvwasnctuyedpvfevvujaqxupsuughlcfxpvpxvs')
+;
+insert into t2(a,b) values ('tmywyyyktmeuptvvtyywsxoozuiuyufofppmv','nnbujindqfhmrzqhbvoxmpbthbjbkwrhwstqlpmkduhneliskujeyhclcsioyylmdyrnasggkqohgrmmnrvogambhmnhfolkgpcxbpoyahxflqaptqcmtqpschxbrsbzifzxqvvgwzxzwpksohbvktbyvvl')
+;
+insert into t2(a,b) values ('lnpdsuibymzhyjwchqvsyaujtvfzwayiakyjkwjaexuqga','durabiuucveeevnjxupddthrwxfulwxdrhmiznapxtejdwusxnpoczwktsdnteltsjqqvwzggquklkhrhhoijzghtnzgecyoaerysutspzpcewwwfczciyvnieaazxgntsbyldelnidxdhlzhcxmrerhmypnirgworgfztidilzviaeletnushoztjhamjxbhnfikdptacevlaypyluvvcalxpwgwrvoomkyehviklwshifllmpafyuepcd')
+;
+insert into t2(a,b) values ('bx','ptzyofaebthkixyvrcgrkjagufbhcijwxmbroplfkvbjpziasafslrwfwweexzzxiaztmdekofxlnlx')
+;
+insert into t2(a,b) values ('ghondmhizkbpvvwctnuhhpatxsjzvshhxxrforcnvxfhbtcxfjnepctmbhbelrsffvylypvwmmeuvvdoaorymaziqiykczcxbrqfpognmmcaezhrnmemahketiacfjzbxjbemmbpelfmuaoaygcfnnkwzxkzslihjumybtikkxjbxecrakeuelkgzmnwlvcrzvmkdminlxfeddbftnbrdhmleqyqsrrbohsejemfp','hbujsnsyresywqzumaeslaaxptjlmjgtpjcehrwvsutysduadaxnlqpmsohfolfzswpyurdlkblvgbwmmthflfcsigicdcfonxqlpteomlffgevgmmwgdtpgkzjnnsprmhltshndrjmeizefjrhxuckyeuduunswfjqhmnmlfafogurwkdl')
+;
+insert into t2(a,b) values ('hplwjijdtvwspbaryiapxkrudmszvnkrpqodyqrtuigchtvcgptcgaetoxnlcgpcvbyqxpioeabjobtwxxfgcerniekmacajlyrwxpsbdfofezzoqisgbeqrhphcqgejnngahaohndlqwrzyhzjgdkcypyyxvruvkthamulokxitnkcrkahlhoxbzbucehmoytqvtprtcniaynrpxelksjjsv','sbkwhgtofdhocbwgcbstdipcdehppoaodxcbvizznrdsiovkvepxnryyvlxehsyxxfklnvzjhagzbvoruaucgscjtrwiqakplxpwjjbjzghqhwjxyinlaubc')
+;
+insert into t2(a,b) values ('fwczpjtvsqejnspjicvqajdgfepgfzjmsusfhhznhlhiapczzdwcbxeohcqmoqtajgopgiagjnphqifrhbfdjdwzueezqbmcskvndwwoiaqgnnwleflyzfgjqnpqbkolfgsmvexxxtkkywjkkmeopxrnsfpsrjoryznfpnyyezmxtbmehgmuladfohulxdrcbcitirjomubdncnyxqauaukbtn','cmllzatptyvlcqazmbmbklndlowgmtovihkbgthhiovktsjiwfjdilps')
+;
+insert into t2(a,b) values ('fbjriduyzpftllnpgtriqyhpfvkgxf','lzpinomjnslpcmsmbsfhbrtgoqlzvogkupbopcwygxcgncguhkruaqkifwtrtjjowsjsrgpmwrvhuleuqhmsdfkffhukuzmkokfarhclhrhlqnpyusljoknbniieogiddacvssrazq')
+;
+insert into t2(a,b) values ('dswdmmujhgzxtyauflfvtyipkxufcqccbbgdjptqjuunitzjqxoaadggjousuxrxutuvsoxomxpgeghnvlgpaipfheaiuigoulkaoxpabugaeibkuuaxcxgolmxyqfbefksurnywfrkogaqgysstiktzsyrrigduhlshjfhkwingxcksoxejryzouovcksougpyfduozmusdefqkpzauwpfxhzmoal','gxfwuqqkisftcgfdcvztgczwxengrsjveyhdevwtlmelbzyfphahjmvggliihicdwyiwqxsmjppeondpypffisbknkcqveszmudergtrporj')
+;
+insert into t2(a,b) values ('tducvepoymlyoaviyzbskkhyhfcpdfinlacjqmwsscdyvaucmaiepqubzqkkhnwqzdcnwqfinkxxfvbxiwngeunsqqxdyaatkfnuhccnyesnnxkvgzebhbgbnkrxunebxepyhuoxavsunnxtfveygclvcmsr','cbflrwmozdcaegjcuexletypbumglkcregisifnhrymlhyxoconiktzatgzobvddpfhlcrxshsumtmnwajrinwafulybzkgprieyvzdpostqpxjyootbeomjafnnaxbhfknbirxsuaoukzamlqqaytvtkujispjgrfwxqlgatnfqlkkhvukmefhjqazlusvqxoxbqqirbeyuruutossprwfhnebtwmdjumgxrgxvknusbbffm')
+;
+insert into t2(a,b) values ('xvpeypbngrngdroonexsqqmuspdyzavkgkkqydfwjqqaegtzwhcjvclzmdkpagtltycmuyfuclwdlidtmklcxmurbvkyhmjethomeghwwbugwskctdrkksujcvbzyvvfzfgqelcdmytvtyczhnoltualubwdhfjghmmstusoydsgnqolbhvlohsuwt','xjjrsqwrrditlezdfeo')
+;
+insert into t2(a,b) values ('oinejnkvxfefqcoxkhuivrweulbyazmpayjarfzjefmjlgnrfybsgtwbrkfjrlseccnkoftlewbjhqcbarurqokyozcinwyygyivffvlokqsi','dfzpuavwasvferiyytbworfduutrhnzmwviuofslwxookowobxtxpohftucxrshivyxksvgyjurlsplqssuiqehemddafrtzwopxypsaubhysrdavawltuhwjdtzewbvcjvbdsshqiutkrkpaaqpgmaktovitizlyygjajeszplqjsorzsoverzsqcmzjjcdvljeahyezgb')
+;
+insert into t2(a,b) values ('iouzfsrzhdfkxxspimlsscjxxneeklbuovubxvsiimtibojvrzdjwwuoxepivchglhyergzqvfhtzuetptljesquzqibouxbujurjvkaqjjlkjeclfghobbpqjhjzanubueuccncfadswatrilbavbeappipazbwendnbalfaekgzadqhzwjyabteaubvvzsvvldczhfxfkwdijmvupsxijaomehqvdwpykyqkxtljugw','oefhrfjjkaczwsdtgkvdnhtnvraeyrniwjgfaiiyievxzchouvipszggnhpuiiaojuwetaozmvfedwpnzwdtfmglbxffvruhtaydhvjxogbkpsmxhzrnngjmwqnnyzguuhktbpanmooneuhowegbh')
+;
+insert into t2(a,b) values ('kerueocbhzsekabiynlqvjrfnuistjsicfxxfogfwzjexogtnjidiqidbrxdainnvwgsaeklapfjymlndfdfxazqvrikfakytjlvnfiwwbtzwdpwpjfpxkpunovjyxvwkyanlsvdwfidylmhhvfpuikqqgescgoxrlwshtrnilfmgdgbprmrzycxtpucyurrlssgzhkbexfslvbinqfavklhefrpasszfdrxnwslrruakwlk','lxxzqxxsvmvxtrzmhlfnwgrabvqmsuy')
+;
+insert into t2(a,b) values ('fceftkorirnpgkpouhjkhbwhfsbxcytm','ytndowtqyexxvzdfejqwonhxufiggwzewfzbhyahmdytthimsvzyvvttvwbrjhxraqykutgwbvvvtuifsx')
+;
+insert into t2(a,b) values ('bcnlmztroakwiyqfaialjvddzbgwcnchtvixagqvklqlxnppzuheuqwgstejqnmkacidqnfpnubltexpflvxeozmmrpmgciilwhwtgcstyazdmuyoryrivozfkihlootgykrajkysgswrztdnztgkt','rjcccybclaemqvmomltasaeqkifvgrvjabmrloecmjbyhlauprcmaysgbvtlqzxiuigokwlhbyytxpzdtvcgvgixbmsixnkavrqgbsddcqqyngqeyuepmasfcbxcysyqhoxbkumktukmiijgxrpeernoyeae')
+;
+insert into t2(a,b) values ('dnwpejemudueqavwdgldvglcvulniztjizervcakuefxskthivcqehrodlagbxvacsehrtypjdjqleaegkvkrkieemshhngwmspisaykjixbqbqcplibsrurgcupegijmpbfhjqjigkavnnhiipbsdplzumxa','nddqokmhkuryizavwuakkrdzopwsmdlgftngdqujkdm')
+;
+insert into t2(a,b) values ('mjqiavizrgzclrqfvydyhuicephlyzftscwubtbtifhiangtpvzjiexbqmffnzwpfscdgewuuflabfymfqzxyuufxpachhoykceonuyzdfeyoijeswxxxyfqgtrzxdnlrxpgbdqmqfcitmikfpgkodhiwtyluyuxlkjbajttqkgrsye','ledtpthafxbjsclveezzugkmeqcujppystcbdxbfxgntgxjnhlqkbgnizkaliohmihmkabqdnbhdv')
+;
+insert into t2(a,b) values ('fbyqvaxpbmakebj','ssxldbwwbotrlgtfyrikawdnqvvlorapmkdhkitmdqwkpydbwjrkbttlahqftruxpoyebyvupjqxjumucylrobkearzlkxjywjmermeirskkdgbizuluxcqwiomstkwddeydrkwu')
+;
+insert into t2(a,b) values ('doviwhiidjiseoyfhpydtqppkfiawesbsdlhxkuxtozoeywutnazhwstqklhqwfhuequxxdditsiviampqngosumzbpipyqmbmeuqduaakjeredjdzlukpctvccwjrdjvbvieyctjhcdtmafkwxynlqkqjgzxwlpxplvzhmoykrywbkmdizebtrndkniqmqprjrwlorzdqaykuqebdgwvoctfp','xhqntuubplsqkpmgnttmsfndcgtdzislkfgogytpnksaolkasshvmgpencuvraupiqmqxiilwdpxmokfaqyauzipilaafgjrzbqlzqgxkuwntjnmnuaopzkpjnbaojdcdkioqegdatmiptmslnellywrvdcfhqzwfvbwbkwgezzemiqodlwonsioqjtsgfowpkm')
+;
+insert into t2(a,b) values ('ukgoqknv','rwqzugtheejwcvwknfelhqqcgsbwldiwcphafqevrvefeekwhzqbgtquvnmwwzsxjytgjfhstnuymgzrhjskkdyrjfsqtdoxdojzchktmymbwmeqcxyyfiwpdpphpyptyvndbrysnaxcwjypdskxtvlkktizdkmcrvlogchwmrnlsvhcjybiotoyzmdcfpgc')
+;
+insert into t2(a,b) values ('pducpoxihigovokrbvudjakouczdymcxlnybwrreczmibmgcvpvknmnxqbhhkzamjovahwwodwgpbsyxtkpljtlxjzqffzgkdgypwfg','ogrlxuzqvdnfhrbpbtdptdrutrhyzxhlbgpjknrpjjmyzwiqdmlxckrwyophinmtgtssuxnjpapzhsidsuemmebqyyexkhzuxvomwvthxxikpqpdvryi')
+;
+insert into t2(a,b) values ('rikxgrtojvnlcxunrwjhbooxsulyjiintfinufbloqgammpghphqutunaykotmvcaaet','bpopkznmkbcevibigyqmjbijrtdrtcttxdwlzylswamycrbyngoeihlcobcgpubgyvnlcsyqarbzwtpedrroyobmtyecsnjrfemipzzgfmkpcbsvrxulwijppvvahdtmmjcavbnpvgydqdqsrkspwiehbfdgboteegfa')
+;
+insert into t2(a,b) values ('pycpralbxgo','fqgxdgwfsfmjoiggurbwksadfzmdfmkivrrwpvyrmuvjlnsnditoiukxlutfhymynkvwhtodulvwmetceagjozkvidtthaomeamoiohqghciwnorvnaknnlovazhyyhtrxhfyqfcgshonuntwvnwipzgszyoltslirxzcyglntuncmqspsqiitunwlmdrjhbnnntmwshjqpqrbuyl')
+;
+insert into t2(a,b) values ('xrncvjnqfqwispudqmquncpsqptuppplywxtpplpfmkslwcnpucialbvasyovuxhaubvhbglpldgnnepovzujcupovniwsde','keitqgtnphibrfmxupnfbxbfsjfdujqczfqyganiryiniywuzuhxskjnxjpjbksgdpkclrntlevwi')
+;
+insert into t2(a,b) values ('aozjduvyipucrkxtowgjzdyfxmzqmiiemteaipzqseiwkwxaaafucfmwhytgpyaklmdkaxbgtoerndqcuphliogvvfwtczhjyhiompqniiiqzecdlvcxwhmasiheisceumvvkikescqnupqfxydmckqnxfvmjytnsbrdhs','uopwxsntowtammuyaglztooxqojzsthxauttyletouvljzoyrxjqgtyydsysrnvpeptbephzsqvspumbuhgrxklsufmjkllkcyqsuuzzcbthnmjpufwjrvrtjcshikucgiqqomajsq')
+;
+insert into t2(a,b) values ('jtbslezjvjafrejkhqxrzjmkzdxhdabxgmoxuvypbzxmuhsiyrndvrvgbeavvnxqngcrgpzhhklblanmycrnimaouhzxjrjumqpzbqwwfcvzrlqnyoogqyxhpgajctayeqauzmeem','jheycoiqpzrleyuisbeltgczwpsjhftlfracbrxxuyolbavbtqpdhhqxrtkqprsgyilkbrkxtvmecmhfhnujgpuysoobcjldvvnkvuvenctslgpmmbqssivlfniqldpnokytfcijhmgzhffaktoaggemfbodecxybsualtnmjhzakcolcnchohthbznlxnamwwuzumzuuqjlqdfbrrjwusiajurv')
+;
+insert into t2(a,b) values ('dxxvcdfgnkrkzfsystzoqpokvajkswgororbyqqvslnxyqajbcshxrjfndbcutwrhkqkrfiptxavquzjnabbxhljsrdwdmgswcfhvmlydwzpdtfojwtvytxqatxxolcjrhqtonkfsnctghohbqgokstziwlcwmirowlipeimhxxw','urgqzggmbvvulktoxgjlpulkgzxoowamckacg')
+;
+insert into t2(a,b) values ('sdklrarhhuxmrliwgsjqybarknpwxevrtgidbtoxlptkfbvsnwfcouvxliyppyjxrilsff','rzmidkqucmcukphpgupabaocpzunbtvjztwxaaihyhnhmqdobmmofcfwtaemsikbjnyycdmrtmyrfgfmqlbegebrtdvqoiokdfybnzrekqeoirpszyigecpwpxmirdgqrsybv')
+;
+insert into t2(a,b) values ('untmzcpvnavgoodmjhjsgqrjnqkeussvnirykvvbvmnaimcagpwaecxhlwnevsijcryuocpwvuynanagknddljsgdhhbckrgqgaxdexfzlylrmladuescjbhvlexmoexsvdhotrzllhxycbnlddrpmlihwvjgzgglyrmnlbnhjjzsjgupquvdvpyffavtrrgj','xuqhjjfhxyjrsvwuoksbihbzpixtepefnftqmdrhqlhzhdbawtaldaicddwblytgpvofbognojympfzfvxnxyjdmyhrroriobhybrheccpyzuftjpvrblzqfyftuwxhxzmll')
+;
+insert into t2(a,b) values ('mvqxe','ociyoksxupvmydxccgkzdqtxsctozpwkldsfcnrmqjdkbfhksvkbwjlwerazyamlvordyngjhsatojyzvtegcknmiqvthrreurrqzvilqeibuymaezmdrybmieykcrmirwjx')
+;
+insert into t2(a,b) values ('oglyylhwadhugshdewvvkwvynliiuaugxezhjcfuysqikxretkoeyujpinwjbbwjgfziwpwoasfdyzhrzhoyqxaeqrnftmjuiumgcijxeopcvojtbcvxtwekz','hiorhbyypjtwrnpofkjskdfixqkysxizzcjmktvgxzukzfswnuwxibtmszfcquptmljnwjxwvraacuelubobgbdmvfouztivuvfdkeeozfluh')
+;
+insert into t2(a,b) values ('jfkofhdnslskgoyxvwnzvqmghjtzxbabcmurmrvqigzjazyupspsmfbkhytynpbhktpflnzcddgpzhkyrbolrybmcpulcypzhvnahdnypuzpndbnbqwielhcswixdfrjnwekzwqsmbwnnckledlkwwzrzsjrfgthdsmtfjnmqmxnxzwcczlcmoaeyeryotszbuhaqdgaucauegeudsgfkzhcjjiyazdpmwv','nnvsfsgwqmntyrzuddbywqvvrgrlxphhfuvsnzolkhmrzywevgsuedvjhyaoihphkrvpoakaxdvzrkrxuezeuhackfyzhksmsssukdylrnsijmdttpfhtd')
+;
+insert into t2(a,b) values ('kcoogloaebmtoddgnwsgblfqrszgrzdgcqgbibezojabgkupchseumtohkpccdcvvnkirmztfnxudagozdpvwaegibaqenlzfyrdzsbrktipsgqkhtqdwdezjcetowsyvclejvcxaixhpzfqxxzgdhncnmerxemleewjtceglwkfedshfqcvbadbtqetjeszshajwvatawhpcwsxlimsiqpcgzouerxocwhzkpjicg','vxdadhoikwygbmnwelmqowjxizirrhzzounlprszjckpkcawphdefygyakovonxzzrfwdhjnadtdyrusksumvplrejzhimnxrttterilcifsarerbakykudrfqhjsuolwwvatiasrydyzcowmewzgwkorsfnsgtruchqgfzdpzjlwrpvxfagrlbp')
+;
+insert into t2(a,b) values ('pvzkztrb','soxfecjunxvazzlfsqfzsdovbsnmoirhfatnjsgdmoltaivsmtaxqdtvoqpdhljnvwvcccryzdpenfzdkgionudiiptigcrftiwhzunmnylwgkpxsnqltvohknledznnkmjtibmuytbbrovqhmznyavoxqhochhjofeoutausqpwsninanqvxhydgyldcsahmcizvujyfybbjlfxvet')
+;
+insert into t2(a,b) values ('skvwjmjzqallxkoiluwjndxrebrvetmzqwkdawuseqzomeqdeupsfpjtartemceqbgfpniimequcigfwobjwvkrpogjdtsjrgwljyouxmccqvkzzwmaszgulkwdstmdpntfmmdnambzrqf','smrsuvklmgxelwirsmtgvrlxwofkvcjzneibjzcpebmdhtmesihwcnnsfemegtptlvpqnsfhisaexeobvfhukscdtkxcwpdoerwdviliexrjxahzzkgvwlemgvxjqstsbamqmiwlwnlufdht')
+;
+insert into t2(a,b) values ('bzvcccfgdhvtwtzuqsotgbmspkskbwaeodpoehbbmpupwhvnxwgmaucsrduyqrhmvrasgwnuswr','aahfrjeggoxpfbvvflcrmelimwwwzysecwcznnxuzuazxtfvjyitwjwwswjselwrasvnvbxghm')
+;
+insert into t2(a,b) values ('fjjwyebajofx','lgkzxfdmzqbhtukmcnwueoxqgiwjhfyhzflroapjqqsafocexlbakgoyfahunkrdupfsidgcjgtqwxcmhdcl')
+;
+insert into t2(a,b) values ('zaukenfvlqmpfpzpgeuqtapwepkgqqhptavghgitpgfhnvcjrottuzellqpfrhirpwqpazdksxdglzwwgphbpqoutoaqjozelquplhjsiodrbhwinbyr','htszlxpmevjddfbknzvckpnstdpdqalzbfbqygundiurwetwrrsijksayjgmsflzwsztqwnntyzmdduedpfrbtwcjlvtjcdpwntmwzhiehgvokafrbzzjcbwebwwxtwseigcyetygtjqccjexdatgibpiwtggernxnkxmchyuleqwuihwbxzwjdnlkuxmgtfvkeegklparhecxmmcdgsj')
+;
+insert into t2(a,b) values ('vfiitfxdqxwtyqqlpya','ichysjkgzjtxqrpqgtsfbehcfwdhvkuskyudncewdrqaghdwsxtnkvcaawzrjtwuyjhyyrvupgytlowtapdqziuwvrklwdxjjuwfskevmxmcegetegpiytnoxhuhawslqc')
+;
+insert into t2(a,b) values ('wjbrbwfkgvpbsnlqzamciqojshptegcbqzmnfhhrxjmyikwdssdjiihhrpbxkruiqzedyaltecdlajfoolpecgmlijbtstpucgeyhavpiyhvdmkytfdmvzpslt','nbhsdfagzohzrfmwmcmenuxkunzddwnfeqegrxhjacfkbhiavtwpasxaxzokwyrucgpdslcvhzugkvvmxatfrtrbilcwpywayuupgvgizxepzevnkbtdnvoxhofnftsjmjxbtczsfjggirzllqvbvtxeamaahygf')
+;
+insert into t2(a,b) values ('bkmzazwpcxejxxrzasigbowovnmxvsrfcynjngqsapiecaahpzlsmzymhiiqsykhlmskiqsnaceaimmoiivzkgygazpubbkborghppzhuynkxvfalmufpvvvqdqqqnihqtzq','tljqpljootm')
+;
+insert into t2(a,b) values ('mfeuwlcdmrwjkpmvpmmvzhrmwatdynjdxwkmckottpwvdcjgskbzigwrkqnfiwilxjjijusoizarqwxagpxuraxgkqflhprttg','')
+;
+insert into t2(a,b) values ('ceisvjbkwzqtyfferjjzpvcoidlzpwzwitqxfqeosbmqruvekwfcwdasvwrqzlhunihlhhbpnxpfqqghhqtutrvolflvabxfskosowxaaykggxgnhiwqeqwfbjgkkplnulsurhqjoszpelityctpypjkvglbzdhbrggcieevjfz','lysebmaulbrtbuxtryzfwxmrcpkngazrqqbyobkvkhgjkegiosiwikixanxjizhybfefrrhrevjtybqijvzhjrzihqzefgzvsinamsrouwmelhrjyinbza')
+;
+insert into t2(a,b) values ('zhisljskwxyenazsokguburlvoshsftkzdkdilogwgkgpxeikiuhdcupwlaqdi','qvloixzgdsbcgepfuzlegjfrqzumxyiejalpfcloqmlzxfkuafesqrsqwudxreiywmxrptyjtvgiajrnhaumudqxpdivuyzprcwtzluewuzrykwwttvsffpkfzitbt')
+;
+insert into t2(a,b) values ('uuptmxrwyeeukxljcqmqbywyphztmaqqmdwwhqcfgobofkwngddrrcyvyhxjhnjwwlpbucmnerfnrutdouvewtsxgfjhpgqfgdjlutdpiqoljpuajqcmvxbwzhbyfwxbyslweodngxqasfnwqhzavllgrbmnkvmcdshhoaxmawpeyvdexurew','zuuyclyjilfeaxbyxzznzkhslsdzxqhlwctlqvxwcgaqqvfeikfqbrtoihbbhendmhjtsdybailjrqxfojgnlkcobdwctaoahxgsmpulhsqnnfee')
+;
+insert into t2(a,b) values ('llizwmfferbnsbzrwswgawoukpgmgnsjwdwvcyfxkpqzicztdczfqttiteamuoeljbfdyutsqlrrfaayuvbztsnyrdxzywqszstnnrpzosyvmmlflpeofhxnnczpbbkgzymnvosdhjhcvdtmmgxot','vbtyqjwhvkzdzvynxvwnqiwmsjpfstgriyie')
+;
+insert into t2(a,b) values ('zwnstwymgpnxvsvlftbuaumscckcingsyjtkfxwfeknxtfuntpwmildppyomcazjlkzowjwqcybalxthsezsxnxkzzxcwqoksfuusjklfzvxnhvqbacxnxjzotfevimeknychidqweqapouhnqtlctvlnwuwhtujbslthducktcrvazrtbgfcssssdgcgnvzouqaebpame','ddmdypmjkhheiejxrejlctprftyguiciuferajosqtbkfaqhznlthaifmhtjokckcthuhjnayjwodnogqgmlccgewtbntqgthkwtuyhrrpqdomakwvuymvlyexdxlmhfnnuffiudbwgnrsagxjkyghgjydhecudwyreuxgvotytakfcbvfezzgsfmvjhvbumuhuhqmntggducitpwklubatriknmdtwclhszzjsmwdsmr')
+;
+insert into t2(a,b) values ('jdjpntftczobvdaxdlitexchyvqhdfitcfgjuitajxkkvrbxvexhywuoscccftzgkordzihtjfpkfbhpiktqdjidgubigonnxtrtuxgquzdxieusk','ptamxmszeomvtfpkrjmhoczkpgdvta')
+;
+insert into t2(a,b) values ('qmiioxeegcfpxxbpumlclxxsshnlmuizdrfjzsifjtceqbdnzaoturkckgqogcvpdtkcsysdoklbnidgmwndngqkzybnhsk','nimzuzwdsgazlmqlbbmnygdrmsvkhvdwfncvjparbklkqvztnshwjgugnyozjohwsvwbvlstcmgshobxndkfehzbhctlbrozfwxvvfmytgqpbefvmhwnkwwofifuoytklxnwtcxfvloeaxjecnaovrgaewowuzwkupregogzdszlwjukrvxhlik')
+;
+insert into t2(a,b) values ('mnofiiowdkkrieztxwwdgpotbiqtawdz','viarjeoawugnzqgchwcppyoykwyiqyqizoevhudfvnmdreeemtxtaibbaywxvcmoaouzdzzxbkmljjqbahstgazehzjrcuirwwbhlcacqompoiezxhepgnlzdjblcnkffjqxkwwcetbbiagwlvuichemmjfdtusqoxnybkcoxbdefogafilrtbgshnqhwkstltbbkdarwytzqwgkvypoqbeegcikmsnngjhdkwhoihkmwvjltkndu')
+;
+insert into t2(a,b) values ('wluguhpjtyebjvuvlfgkjvjudbkexzcxpftxaywnlctgmyillqrkpqkqcxjuezeqjinrqcflgtiaxffecstfyeqcnyvbmkqhcmspndimuicyivplldvflahiyxbcwqcchfdxfyqjenlwgeznhlyugfwngrkfbrlddxdeyzzostxopxobswcyeafiqcfwcsppumzmhhxqfzfiuemagyi','uhzgjduysiuabcodumvuugicraokfbiekmvihyszhxzmvombvijmetpmmoxkqlxrcqtbdvjvsoqurgmcwppykghtipbeuifwamdsiaasii')
+;
+insert into t2(a,b) values ('ctbxtyirvyfvttsopphpximilvjwxxqvzxcolpynpixwdgxjbmeyrdflqxaxdzormpnsfxvfcknpwuvzxyuhrnfdjetzapkrykimousnwwgeslwgsokjbpkkqlormngauvyzdgsiiagkvyunjwxyg','wjtcoxnucrijiidbcjimcrybmhqyogydoxtddmysqofpbvdcnqsrgnamjwxdtansjgifqewxfractrvrqkfxbbnymycgwvxmaovctigkeaymozqiyzqmuliyemlvgnqztjumyfcsmrclaqqvvflcuwguysscujgkvpbynuzhcbcwdjrzbucwvrxoh')
+;
+insert into t2(a,b) values ('yjbydmfkuyojomgtknvgeolszhdbvgqggihxnfzffrrrvivzjfyqydkfiapbbkdvsnqlquvmbwaxbgdgxgfczjihhwqflgywmqcwyjeekcqgcfqqoaohxgxyjjubcfnvquwvouotybqlatoxlh','wsqlpukpxgjqmsxredrfeiij')
+;
+insert into t2(a,b) values ('iagwqmpattapapbysoitmrxqzlqtvoylvnojixxerktiaymjlszgpqxkvsfydqeukxweuevnozseztdghicusulgwgbrmwylftrdniqzrduhyzvzzrkopbupvwgftoabuu','dckvhlohjnhmiwesimlwuodjtfbprfednhuaaounmgcgtanrenbbinrzyicoizglh')
+;
+insert into t2(a,b) values ('klmxjeezxijdleetnqbmuzfrdtgowagwivbxymfxurrdtzevxxkeutihwwmgmownsnhzrqilcfzqfebyavwmfdnzqzsphopdenaykxzefpemugljhggzxcxjftjz','xyruubsornbfsprijqicexboozskddwxhzlffwmakjkilsjzbusnzjchcmlmnfwpcrezlbylekzfmvqxkfufftjlcclokcvwkrtfd')
+;
+insert into t2(a,b) values ('pvormmvtspcrfbasujpsnitcknswutwaiuoxjffgvgqxervfxokocrdeibknpvcguycurkhtkjmdkvahdzxqscetaxfmerzrijhoagploncqjnwcvcaebryjjmpbwupctjxtgmmjpqxiionivnxsjduttaof','enjkacgyxzojtfbljmsiwzdclmljguvpanakmssbovzzqokrxyrlmjktfhdeardnnclltcjzyphasdhozhtjueslapzrdngicywklgpwfmzlwmyrhxkaluyxtpvgogivsderamidqyuglzftivjxb')
+;
+insert into t2(a,b) values ('jwhkhtjabkiutyxuquqpyabvfydghmeaaraqisuiitnecomikqtojctjalwmaalpzjcfyjlwhnxxiccoofwntfeecburwdcjniosqkzbkxsjppvuikxlvngrjdhvqkjltfhrkpzwxxe','ttikbsdthqqyhdqzzeqdoilgkzphsbqhnktdcluosoofjhngmsfyqibnupbdvwyoqbhasbbhdlvffgnlgqbifanutuksykikqwxlqcnwyfyoaztedxltaiwftaxxqzgohqbugadccuvmwwgy')
+;
+insert into t2(a,b) values ('tcxztcknppslngidttoyfsaqsqgsaxbetzsdomoxwxcfvhigddmbmabaraksdkgcokkbvsplvtjrsrbqhllsnvapyflwrkqoxuuhbtzpttrkmgfettibfvboneealijsntvbfirhegtvgdmecfswttihofihundliwznkukgqljsheuqoxofbtxabteiwmopkfnwhsmjegcqlumsvazlvmrhxb','csbjcyqljywzfozkaxkvedwnvformrbttz')
+;
+insert into t2(a,b) values ('rnhmqtnjiiralaaoxqjittycvjdnwiulfypfxqpgsltaqjecreswgvyxnbntoplzfqrvzjjrizwxegzkmywgljuhk','azyiezfrjnongvpdepwywkfrxbidemqotvhkjcufxfwrunxc')
+;
+insert into t2(a,b) values ('kebfkptoilzpjbzmwqtisd','whoupjqtmvcsmbzdamrgzwkildbnzvaxnzvcekaxvkaaocrrrlmjyfdixfhfoecjgjubpimjuqkohcmloubwzosre')
+;
+insert into t2(a,b) values ('fmpgklvdxtymkdvnqmizghztairkmkemaqtcudedosopnuxlcecpskdumbnwnbdjbklhxlwkidbhnrryppfgzwfelcqlcssykoinshcepvzhm','xxlczfhtfkraktkcezsaahaczcvluizgqylywpfdiiccvgczmwmuagbmuehpiabkjfgvyxrciwaixzjvipyeujhropvfgkdhfgrclytetcqrmrexendirsdfujvqywplxtqqswgfbhfw')
+;
+insert into t2(a,b) values ('evcqfbpkjlpdychhbpdqtzoicvwophpcwceufdzhhbpedkycclainydkgqqeorhhzsauyjebojidrztweikxeswsorznxrdzlrdutdjuodsgjmznueagzgwqnbdecqyzrpxtkkybyplszrjdolkwsuzjyjquwtyggzjlvnxgdlbajysuwockgxkflykcikpacnajfnzwbpabmvd','cveigjpfyylthmaxylajreadewfdjuloryqncfikjoufzfgpoyfieoqtazxbmvjlqqwozaddvwfyzqnniqbhsaqmvxqhanezbtcejjydrmewycgxv')
+;
+insert into t2(a,b) values ('jhypeyfkhpvdyecdczwbduediuxctgopuauqmqgfqjmwftgpsbkczepgffcdtncazwiytwiiygfzhmpyxbhivgzurxywttqyodbekvxznbbqttfbkkzdurqxvdkokswomcganddtiqxfrywcpajusxpvwhdcynauodulfixcbuvblziqznyfxvmrjqpvbalxpddnspilnjfxffwlrvfmditevhhi','bnrzubhncldqsfyriveqpwsxuxvslxrfefpfhdnqedgjzcfpaokdahnyzdcsmrqgcuzbjitqqlwmdt')
+;
+insert into t2(a,b) values ('cxbkdsiwndljqcjqdhma','losspwomthoitqhbmivctixfyfkrffmlxeuftetdrhxnuokcuycrmcevjatrfyfoncahnppsiuvncpbhykgoaqfjmgpzyziozjophrxfyuovaphskzzfshkipteezktpyvaityvzdkmnxtlopoacbzdysuqtzlxvxafpshfuwurwlopxonqvbhlphmsfhiqdqiclwia')
+;
+insert into t2(a,b) values ('ehgqymhxxpsfgcoziedoneywvggqhbbblxthrjrvhcbwnlgezolncaicqushdyvafnzeqqzpbpugcecqfgkjvyjubasakzjpqllykitfihtuovmpjjvzpetrxkaqiprqxxcccitmudytdfrcwzkayncrjsyizwhfuhqmzrdscnstltnyfkdleudufbwtxksvrpxdauehkytwy','avpsfzwibwzxbraxjncnfxkbvnjovqdxawwhdikukxjhmwlcwzibhlctsoawefmtrfdwywcrabtzodlwmktlaeslppdyckwmmxmvdspxseuolpdtwsxarbqbuycnbvxeweymspdtnwyvjfupepkuqziqapxltniouunmmzsaandogptnznutznqtrixlixslbnycfxrg')
+;
+insert into t2(a,b) values ('nbgqimrhgtqbaticzxyggfnhanrkpyugysamxjulskrtxxbbe','xzfhmfsxrcenmgvpkraoijfaaukxivtenjvxkourwleijbteyjcckymyorpwjobdgkipvvgaggbayvbatffvddbatjuhfpdvquflnhwiebnapecvzukgssk')
+;
+insert into t2(a,b) values ('krnxtgzebrvbegrjjupzsqxuudocgvvvydlljwmcparzuiihbrkvxyhbaesqucpnpehhazkwgyageciijiumuihdqrrtkwwskkelvpmkvdqbeeubghqnoufmnbemubxzehwixktjzjqthgsoesonledqfpmfhsjwjgimglkducbytkuduzvfv','txmlpmjzewqgnsurtsvhxaczqnmtqlrpvtyqkpxiqgyynkatbmfxpyqnhgfublwdarsknqfhodtxfzmwgoukwiexcfklacroysxtxbwrcpru')
+;
+insert into t2(a,b) values ('tmhatrdndtrycouxmsfrtemwfucueuvuklkvzytegmunpfdoilrkxeobgutcgbjikiiroivrwdytmglzointhtcyvbmqkvkjcqptjljcgjaakbmahscuuvrzohfvhxqvsbayqhvuwfntjddpyyvavyrjajumkxznhlqkqutnasltowhrffkszhymxabzelglifyszbhtrwwcbcyrgendnmhbivceo','cgrsesrvsjrsnhkxkamcymvesususzgrkhakxymolkmepijkmjewdxqsjtfuecxvmgbbcvrjnrvstoiiijdwxfcxcohbfsqztxycpfwap')
+;
+insert into t2(a,b) values ('yfcfbkobpxyyoipvgwgbbieiwmrdmhglpvrnwnboxmoffsywcfvgvgpcwpkgwngtucrxomkxzythcusjgmztyihbjjchqgxzzajuwgwoueizsxnlsfjwyiqdevqalgoacppnmzvalvipryaaptqhgspusiizwyahwrvxbvwmynwpofjxzrrmweqjvtjxterrjouspxzqdldkzywzixrwudwarzvzkqcgcksvkdldnuuhqlalbwz','bdeodofkqowqcsipipwrliwsgxfudsnpzrkapankcb')
+;
+insert into t2(a,b) values ('ozikgojarossliqlxtipixwyhekbltrdimrajblauwzimthglbcjvnqfvtcdqtavkzihrbhnrhkrxispbegzfdwzbwzugrcvpubjlzkqt','ecvzf')
+;
+insert into t2(a,b) values ('qllnzpkurxtkqsrrilabltbhdcnrdzywabkyzfrctwelqtfoflipxpiliovvuafxpajezavvsmoitoufodwrnrlijxicihwrawipsvtbvmxozvtgaksfqjzcxuhjmysbwkgjkjmbarktcptghdffypicqptykberajurlcnkw','wbulnukevnoyxusuyhohuygzgrmetcdgcgotfbicpmyvjhkehmzskqqrnosdhffckddcxnwmfssyftjlhffbtouuxhmpsmlkufatjlpamazpgwfigazogdlvgoucyhvlljys')
+;
+insert into t2(a,b) values ('vnnxvihxldbcjuwvbfprvgezbhkmmeokmqqzymgohegnstsepbjovmrbrezcffhrdurfipuopqtmkdqucehbqkwqxngqpzpqruuanvjpmsykxdkeinyhmsdjofbukmzswpagva','mavihgilaqpryaarepmoqbulwtmvafcbstcetbnlfogbdmxdvted')
+;
+insert into t2(a,b) values ('kgppnccsgevlcpitjbiufzvivbxbqicsmayglfkkwlzkztisehmmhnyuvtrhkggmfckrldhgrslfcxvttgofirqmotwkjyyiyoyoffuyitbrzkwllvsijpocxiflqslrqymkwmyreqwesnzlzkkxpchkrhgwdteqsiiekwzhztpyjgbzoblsunlhnadxyulkgwofscrmdfhlourdlhjadwxntahymtwrbnkfwbtuxwfbxsnzn','odkwmuxwkhkzaqnhbcpgehfk')
+;
+insert into t2(a,b) values ('wupgcsbgxeqkpkyfhkaip','inqlpzpurnuxutfjrxjynubeqbfzndlpatodhccmvjlvyebkmuzernozecopxdysakhlyeblfixyvnkwaupcybwaexykpvssungvzvagsjsedsesaugyxmjrleze')
+;
+insert into t2(a,b) values ('rjltuulflfobyveczknptdntwvhdsstaaqvwkaybsndcxcseultljolsrwqptlneanlfusloafatgvajdgeifmqfizqbwsdfnignonjukcymukinswsvtifhvncwxdvldegdxlziioxksnvafyiriwyadqnhlmmekwsvxlufltmkhkfompuxhgfwwgbabielgfdffqlnbcbuiwgmspqbrglsf','nbmyyizafhbqmqkndwbwkztihygxjunqzuszhgqcrbwzsjimsddoikwnvvdsgfbrdhtizyjnwotfocrofggmzheyqzfurdrwxoccxojgigyzdtvclcsncsqwzmnpftfpzjiqibznaqnfrpupnccxjoioctvkjirrxycbonxuyzfhokajnmhnmjqdvqtcbajlarqfaqzkmndfkhqwjohhz')
+;
+insert into t2(a,b) values ('quknwutmjakcpkppjbksvphrruaptevddjuonvynxaphywzwhlweqnfomylleuxpwhvtojcvlmqpafzrzzmllgfflobmdkoownvgkpmfkueyrywhdhohqtmlfuhwmagjoaidhgyckkailrqxqdvbsqtyzmylgaftlalx','sqbvrhxmfeoneyxofjjcylkmwlzytjpsifhguwyktmoxfqefjukkjvgmxdccitbbciijssgblfvjqoydypfnbardwmkcxiytlbgitcjkmaqjoqtvqoscfyuldnscsryrzljsbfuwdxxrfshcyzettxjvntwznuamnfqjnhmyutyucwkllahvc')
+;
+insert into t2(a,b) values ('eeobrecdwwrxwmrlbilhiunuqdntjioktxovwsiszehgqnzvsxzwxb','aymtcdxsutriiwjsjspwalvjnwlvgpotuqwkfusbxnuvspvxcfgmompclumkfdplgneezmbscfhzivhjodclklwdmtwabcauwlchpbashvojwrmpewpuxxzgkygljbjamkueaqwvotratdjrbuxphdtnyiswpybnimqqcupbolwxztfkp')
+;
+insert into t2(a,b) values ('sxmfxknzdfmpzmkqrbjckqfitbbxdonuepmtfzeebqwvybhteuxbpqtsjsrggiwclqmzalkhohauctbnclng','jprhzodngrhrmhxrscxwfbanlkzgxpwiepbaduxzearcshwuicefsijknzqfbhyfmhtvcrpaiyb')
+;
+insert into t2(a,b) values ('rvycpwxzvvlaignozyfffpzbgmbiesagqpvvpzwgmvbtevjahsthjtdgtqxcnnuzltmahlhbnvzmlfdgcfwubkprocmogwnsmhdqkknjbjjsgdhoqyrdr','ecrtevpzbukkdofdqtdezmnulrkzlfuphbtxqdnzojtjatfzzuygyaynpuquhituboevnxsveofwjhndabfdozxvocsqcsocvqlztlnsnmlrqpbltymxayrjwpptefxbrhxdrsboxpcovqpxkqshecumsnoxiqsodsoajmwrnlvy')
+;
+insert into t2(a,b) values ('olftuncnoitvqbzmpxxq','qhoqpnvdux')
+;
+insert into t2(a,b) values ('kgyuekrefsbrkieefjsvdqfjjmppnlyytuchdfxtzfbyfhmajrtludcvsdqdfpaffdymulndbhrctmh','gkacohixvwlvuawtrkvlelprjyzqkqasxtfgauimdszuhjymmirmhwnchgsszrdgjjvjiyamrifylzllmpjdyfdjfgfozzxgrpekcdbqjma')
+;
+insert into t2(a,b) values ('lsoqexviyhoqwhehbkjjatkqywhiiedazzhqwbdwrmreulzawcwwkmwwlyaaguhzxqchyhxxabqlcdmxgtqllyodigmsnpyzabuupgvxsepqexldbabvyhmrmdekj','tpaokcmgsbwmozxbftlrykazahdnszkqalkxidbtbtlwfgeaaagpolkhkcgqmzspvhzurddmnpbnxlembwgzxyogqovgbmvycqvqcltccmunsfqrmdnowjtmctmagbexwgqeuqnnttfxbaoxxyfrltgjshnlnikncfqrdhrwcnzmpscrmqsuunyeyzkaqmwqwuvciawzvhyjkhh')
+;
+insert into t2(a,b) values ('dyesuogkpufyzytoavngdoxoaoghcuvsjaonummsiluhoprzkwayrkkiwhtvcenhdtcsooqhpyfybzenvseifiymwqiycjbplxoihimzmgga','fmijmofziiwmeargnlfpfovhcua')
+;
+insert into t2(a,b) values ('npnofsiqkojpmcmqjdthohddysjngsyxacnvlcnwfawvijmvjeulomwzohygekdufqeozfxwbzrpdgnkyfnzryzmdqgmypcsvbfuvoveydlah','fmxknakjvrxocvpcewbaapbqqlpjlkahhywnufzlvywcjrbtohvrfvldistoffqmngamryqquwwjjjhmfnhigarqbynsflvblzkgtecmpvkqxlrdjsobfslzwjqaalaiowhmpcoexfiu')
+;
+insert into t2(a,b) values ('hsftpebevztnkcbnzpnqlpbiwrnbwlslrjmthjywyhcchksghlpzqjmrgodechnrdtydagreypebtqxidkwsbuotcdaqrwjasvigettfmcruhvaveijvigpxrtvbgtsiudlknwegwyjqeezsffvqxgyaqhkssolgyiatlopvzwvcwgi','ybmwvimrowfahwlnmabegbqktbnmxuoooqwkaxikhvxuekyusxzzqamuqsfmrzshxaxbxrgxyngsccstsleeenxltiiawuvqwtuilkjqpszk')
+;
+insert into t2(a,b) values ('jdeiygdrzgcrjgcgprykcwcivdbdfhoqhvfkpypgdqcrcvbdfaayxiejdpuyaoosdegcndrclspffrhlhwjmflrmncyioevblswkulxieopuaivzhfqagonpwzwialpvovmoutizlbjqalxanekmpbzvtubstkqfrm','usqewhtnntyqmbvxykwkbccsjieuscjxltjuwcktztbcgsfugcwhhoukgxkxclbjsyjddvhhgrhpvoaqafwqmtzzcxvmsasbrbhykbibxbwmgrmikibchpzalrfhvsledcvferkomsmhwdghxnazzuuscd')
+;
+insert into t2(a,b) values ('sfvtnbahmicsheg','rafoyixdszaoxwpmeoexhqwhevskkjxualefasijppozubawyorcitkgpjbsnhivpqdkktbhmfcitchlcsrsuyaizmsuoqhhzxeypuwfspterhjexvpavazqqwhmudimewmcifyhfzmpclkofsodyyrlqfxctr')
+;
+insert into t2(a,b) values ('hgikjdjgbssvqvvhrungonvibkejpynmtteyvxrhdkodvlrruldepttoiqaymqagnueukvdulewjplubpetjykwtkrvzkcgsafghsoaqquicaamtglnvrwmoyjurfbotudwrhkofzumzinjfntqmynaxpdfqnyfhdbhzhewiwrnfbxgrdqqhrqgxfbqexdxzwxpdwlxkgpsrmhjjglvkyhuekxkixzmg','itarjxpqdgwedw')
+;
+insert into t2(a,b) values ('mvgnyvhidtwugmhorseoxbppuftndwddffuiapckqaitxqwdjjfwvflsgsllpdxatcrijyubkcxdcdrylentutdoelynfdrjpodsiaybiflbnjwndmpafpbqznbynsfnnlyszbqzxbbecfzzygxqclmcanfmurncpqutquyl','lpiqdkf')
+;
+insert into t2(a,b) values ('kcaeduvgbgxpzfcyrulzszdmjnajcnbjwnjr','pkgopiwpqlmtyjzptzplxcwhkwtllshbcyiasobhvrtxffreqhvkctnxtzushnewsvrnaqcokefoppqhnoxsadbnkmtpqdjhhkxsxszoeesftlmugmvondpqnpdjubfuczlnbb')
+;
+insert into t2(a,b) values ('uvcrafguwxundojnkwgpaaoeeibviokclirkheczuhhvtxtfwupoijgsycvligyunpqymoodmydsibfhfiokkvyyuqxutwxqusyuoxfqpizrywtjfiymdqeouahisjyzamayxtczpqcfglqtqxltdvzgshxiitxvwveqo','nqemmplzwnkmeivhhtzpsfowdpbahhuqahgmwdjqgtunkrracmdlnbpaqgafkmveqvgbiioaanzblihpmyjnkxlkyqsbtgytocrdedpdivuoocgegljlmaxfwvlfbjzhbiiklrgtulrdsafgywsiayfcxdteriughfyxopptwrsvihtfnlvgcqdfhyvqephwizwtzaubvtywewqxljjb')
+;
+insert into t2(a,b) values ('xxxacgljqeqynoocerpzkcisqxhoqdhrcxogqjzrekjxsfplahcqqqwaatftnswwancirtnapkxnbbczgzgrcsqmkxekklxqnormenhloccmqqyikvsorlqtgxadmqqpzdijwxiaqwymwwvbebkkhjjjsudymrrbjemxvlaiodxsuoibzcmjesgoxatuxehzvrkm','ltfircowtsiegwxahfeazqehavzfuc')
+;
+insert into t2(a,b) values ('lwkrufoyigxnsytnxdwiltuxnyopugkrndbfbdhdgosvbyfgmrygdatjdzmycphyilaaengqvzvaoqykvfjfhuqyvpjciqwzokwjwewqorftnrokwsvljzcssneyqulpwkwylgtwxjjikxvhvhvctxfdeigsfymunbhcztayikhlljywnqfvlgcunoeqkzszbxwtplpfwrqtqvlgjoscqedwpwfrvilheqygjnvjobabj','cgkctmgmmlxqzyxnssymuuqeddqpqcpsndpgvntthzfxnvphvavebbhimeifjtsioayhixzuanztvkfjjdpswcmeqlchmdofcppiuvitafocdryvjewlekxmfkkguqhgewttrxyanaeapkzjrzxftouwkckvhpyjeiqkwokpfnhlxirkduhqnigzznoqrtymltqjtdyqxanezbknqfrpzridtzotyxpmpzsnfud')
+;
+insert into t2(a,b) values ('mrurexazipevuhlswuqmpbug','mukttqnuryrkgxmrtrzisudhklbtqdgiuxgxrernhfvgbvnxzsbrjnjdzvvrydnqqbvngfqrgzpidaipeamyagdfphkjzznainxqzpphgvrqmsobquedypqggsckkbscolgjpewpdfxclqvbwpfxvmdoybpqsqwgagtdjcofpggaiolcxrizgbshrwkairtuicicszanmrin')
+;
+insert into t2(a,b) values ('wzhnvdeem','crdudnzbhjmptqbzxepttgwzkbvuxnstozrymannklwxbqmjyqfsygealyghkdfylxzwpidhlgdzcgqxjegvcjxttpyzswqylowuhobourpzyikkcmyasdiygajirduzgaqeubjbiuynfyf')
+;
+insert into t2(a,b) values ('broqupmfvdeknpkrcqkzucctycivhccpqodhtqtxthwbeqknvpaxaznmbzkrdinxrtpivnejritlnrgiyslowhzlzktlltpwrjttbkebeqobpiheiyozyccvqeeebwwumrklahmxwvuwsrmpvmqyujizeufczkzjlngprbqzgylfzuvqyquaxzlddyggquyeauqyfyagqfxladolbiqgvaavcrqjrmnuddowtkbed','rsauxdlpknzzbzihkltuanqowqxtevjnvnqfbgyndcjahpojgaiwuncma')
+;
+insert into t2(a,b) values ('nlxxqnhtdwbgdcdmukgcsiemjxbyolatwehlkyuqhhsskafksspdpnyvkcvcqdlsekfhevikrmysnwmsnrwpdxixmzumpsbqbctbmpqtkdbrwwksxxakhwhlfbayzoanqgxtovmukoxubxjdhlmpwcdekpdjwspuyrcnmftdsssxybkylcctbmtruvozseoccjseqahmtrpkbagdueqgapkgecuge','tcgbvwttfanodcjyvsdeuosdwleqtuhpuednjdqdrsnghaowxpywegasbbdabvzfbukrapyjnznwkfkyxzqbjfkhtkgwwdhagfdwbhzovthfxhhqrlfvrixwnasmxwvjiposhtiicuglknmnbjygoyfvfbnmjhkvkocbahjfwptimgbxxdzfakgirxoyckhdrogqncqexosbcpxfhlcocnhubervhmszpjmcvcctiiybbrnuspscwgtaqlp')
+;
+insert into t2(a,b) values ('nqosmjsqbnytwegenplhvhudypjegwapayjdhxkyccpbepqezjcybibvutemltbbcdbncobojsqmz','rrnecxlkqojkottarcibenqzbvguugeghaxlbawhdxlrbvrgqoapqwpvsjkiidjrqgghclypgthcrtnuowryocfjhaxmspowc')
+;
+insert into t2(a,b) values ('obangjgjjyppskmkknrgjjqwgwsebqyjyvsmuourgmekhrerkmtzxdtmsbrmzwiloxtmixyjlxjfqynrbezygxneupxpbhhujlszqmnydduwscnuzpuzboyacokdyabvokeueazjlkjkro','jmrlrtygvclijztkkwxtkstgkxvptwzjfyihuwxvbuavlokfondpzgyzhxocnauxwumtuitcwavapwokeuwmsuwgfmzyxfbtmcgtoialbijvermieptiwnjulqrytmmlmwlhiusdssswnilge')
+;
+insert into t2(a,b) values ('pvuphisomdnrlmhytvttipoaydefxfurbnueeiwvjizuvlvwuwbcdg','jgsexdtpqovauxzelfihqupueylnrtzoawppwbnqeymlwjvusbjpwdwfvbqtgbneopyiymlhwwgl')
+;
+insert into t2(a,b) values ('zudhyvibpfvnjeozpwmxmgedooqgkfitctddzvhqodqhbvfmyzaxanuajdslfqyetduarpohbljnqivylucivaggwhcw','nmkqxckomyxxqyhswscyidfsdxmoda')
+;
+insert into t2(a,b) values ('jrhpcrpajgzxxihttqyqoeeeyflabajuvdaavieylcbpibezcoagzamebpbuapqjlyfklpbyqsevdpubsinwfsrvvsvosvcmkmcpkvlymdrvmnhmfstqfidtvosjqnrpntnzfuhoqdzllumlgvpmjvszvxzzzjgtlofcyxvacfioglos','lnckusuamyfrbrjyxotrwztiafxvponfsyrmysuheydmxtvnccnvzrnqvcphjojqwxilpdiraxjodmtlzedrvwjdjvywfvomepugjlsgauiuhmetexvqzzcfitiy')
+;
+insert into t2(a,b) values ('xqqvzzvgrlfewcgpktnwjlisvpnuytovjepjrcn','scqxhabmskjgjsprdbvnsapmlcxbzkoysijhhrnxgyczraehjioxnindxuxmzgcpcbscjvxrezeeulhybsrqyhrkvjhdrccvxdqdanieftjlyeqdqqmqsopuvtcgvprbsdjicbfvrnynmtdzmssc')
+;
+insert into t2(a,b) values ('chiuvrjkvuveyzeniwxkjsgdezmjfgdnzfgipzthtmgcerpjcdhvfeofaxvgnmctygibymcolzzwxaqyrwxanaiccehuusgofzlhlrqaqhignvvjvkxuahusmfvvjhgbikwwjwmixgowdjvhuyknhqhccwhjlnphhvuuvdkzpflcmalfdjafzhribzkmgovnsq','aggwvkgwewhwawgczzyijskkywwshermwvnaczgslmcxewwetatkubuwhopeyfhupuknvrdeylwguzbyvnzldbpvwmsbwnireyvubzcwzitkstpewmsgmcdprv')
+;
+insert into t2(a,b) values ('ysmvnmoqbchrhmsudkqabflfvowgdxpsndwt','cvmzlifmmubhtflkohxcqxblaebhygzfpyxdkatnhnpgvxgfczntlpispkzyeynrsvt')
+;
+insert into t2(a,b) values ('htjwyfvqfrpoijuhhcxhujnttsxfvckjdfrzjrgqzuxuxsdxdqofabkdh','oibhdfbijmtuypuvimqaugrrzpuuonhjlodfzqkpuocspnkedlxehnbrkvlscjiljeaajhtaavagjlnurycyvpoluwhgtnhutrfiacqqhsduqpdsvpekznfjrphmumgnk')
+;
+insert into t2(a,b) values ('lgzfrtzyahrflvsoeknwujoqdtgjqbflawudrlodacfrotazhfynjpfovuveicamtejkrwugrbgrjuxdcyjlgnkxxeqdvz','pqhqdupxbqupxfrftlgfyjdporrsjyenuu')
+;
+insert into t2(a,b) values ('iyjwvuurgbrbafjjmkfzxvhtzfjocqz','rajjcmiqsmsatkdvxuwbyhvdxhlvtolyyacfdhnadecmdmnpxivsdebufdleibcitwiymmltcctjrmyhaqunmehfhdgzbdhdv')
+;
+insert into t2(a,b) values ('gzibfwmcvfbampaurfdmjiesrbojacrifnnghtxwgykqbajwwfnidxoixrrrnnzsesqjwrbouhawjnouzccrawnejimmftwmbcbbghwhbjxzbjlgbokrkokjckiiwkuocbdyoysxecdaaj','vplmqnzmyxslkwljkpymjjotfpse')
+;
+insert into t2(a,b) values ('rktngazhdphfzsvlkpjphcqfohowplokcbwedjtvcuyeqci','qeghzlnjkuoejgwewelwbufggpbgyvtuhlucjxnhpdcxsayikdeidflciyzuyowzwnksycokwwocvbqw')
+;
+insert into t2(a,b) values ('xtegajqhtzhnndxlcparzmebrggevtcqjevkhcfhtnecujnympgocmdrbwfktpooelzaosvuosyauvpgduazddficbigxwciqamtcbhemfjqosqnjnxtyllcugtlaxsejgifdbrrcjowcysjkfxowhgbljiapgacjmxmfmfomygxoerfmbvdpnuctsffxzpjkb','gvhdnvumbihvwyuxgorzuvggfjmlvyeucalecyloejbydivrnmlokicetmmcyoeufmktkrynckirsqtuyyuwxgsbsrtaxzieihwcljmwbhbjwsphyaiivfamhwttkevfmxxjxdgtcuwgjhaxlgvesuhavbxdawfuojkf')
+;
+insert into t2(a,b) values ('bgfvjhapqqhzzndcxbrmvhapfypjswwbjexmtkpqzsakxvmlrhrpvurlpegdqgxexcgjkdmgfjxipiejxn','laattsrcpekvsyguuyinqyuwnvjbtotftmjzsiztcsrwbwedtigtpyrdweenxhfekylfvfwuaubwfyeujlvjqlchdrywoiwwusgxhbprqahiczrxklrslqjvvckclrcebmcactzsuuglbelcouvizsgbanocdjzbhijgodvmejfktywmhstpaevlucxoazprxaejzeunhewrkccfutnwg')
+;
+insert into t2(a,b) values ('gdbampubnzoamfotfomgtosljlvdobkshqovxoegkfepxuxbfuqhumhydjvmuycksnovcgppbgcmuxyjizfcmbfynllnlibibotxfudteutvinxiggqmq','hhkpunzajnqfjxnimbfwpypfolkzordulccvhuonobahzjgabkktjowydoztwthlevswyvcbdtagmmfftgrbri')
+;
+insert into t2(a,b) values ('pgcquqggovnxifpujubadxvrfqgvukvzmwdmdfjjeojakamgjdelmnviffmgcobxtmndafmqtuvcdidopdcojobkmlsmxqhotxogyzpetemjzziyzmntklql','rlroxllvwkmnizixvneamdkgjroqmahrjpmmsgnmvnnbufeqfjgisodietxifmaulmekkdkcqkmxxpbblzdpmryahjmqndwtdbaeulgmucaihbfolhgkzcjhknzkeqnaxhniczjlpikvjawzinmbhkhapodbzelpkijqcylxxgeuaiypuekwprkpbjtapcszarrbxh')
+;
+insert into t2(a,b) values ('awotdf','hoxrowspvhxzklrweltqxskdfoyqcmmvodd')
+;
+insert into t2(a,b) values ('xvawqgoraymbstqlndcfxxlxrghzjtifpyzcooozyoxvjnvunqqgnxddbpxbfufbkipobygjtyystuinliuhbhotrjrajiofdtzatledlizkdwwqeenlwuxpiiozkfrwtapztluhobjernvhuoglesphbtii','laoadxkxuqwcubyoemlgnogjupuunfaxcmizpwyzloguqaakmexygrrwybxeqxwdxspzbbgiyhujykouzwtvwfwkodeywqaqnaxdkmbicenwnmondoawbxjpnocurcx')
+;
+insert into t2(a,b) values ('hrgqsxymlthtrba','jcpmfrtcvbycxwiikcofxtgpdttaegnufhmtrbkthrvnzxljoschshczvgmsebylvdkfizhsxmshtuqmrglzfxapsqolaaggdavkpapbbzgsecsbxujphymnusxsjptspmtxqmxi')
+;
+insert into t2(a,b) values ('qlkkgthluxsbodcijrjduzreqthacwsvdrxjedndpxmwcoygoisopligvznfjoszuexbhousuotekzjqwbszzaydlvbthypggiyqvgukmhbmrmtmefkbxblmgyeiplpyxvyjzgrzjkeuslletifffigfabqzsxnyekfnugijyyecalkembxvlsabkbnlcthka','egjlxxagbvfgiicpzixooezmexefzazledxwffsdv')
+;
+insert into t2(a,b) values ('uecurskpslijnalmbzhicdjlktpjfejtfqnohickrxfiabfepbnaxwlzdcawthfjjrfhonlghekuapcpxojnvjtuubmrjkmmlpgli','yyslumznpyngqhcrspemxbzdadrdavgdtjjjaymmwreyxcjfcbalffjwubormgzyfchfwkmxlirnbpnwnrtetokprutczdxdjaxadvykrtrudodkowqgddoambcfvfgoixkkkprfrnoqcpdvipjidmrro')
+;
+insert into t2(a,b) values ('iutahdexhnydbraaqun','vmdcbkvopyvbjrvteclrxlqk')
+;
+insert into t2(a,b) values ('pdzehwhlqsqhiaxqhrnjcjflwtaebhlmvwmuiz','qicrndudtgqvfrxhrklngkrdrdmpwenupxlbqgmdwotdnotbsascxbypolhyhdzjcasmmjmlyflvvojkpvodefhnxlngrdupwhrecjlducyxuzfldlypkfxbg')
+;
+insert into t2(a,b) values ('owpnvhxtrkfambdijtslesbflliznqcxwkzmdhbfwervllplfdqeexoqzuttvwgdijrakfkxjpkmzztopmcdzgmuwmflgmvqstjvcijikrgwfnbcjpxs','so')
+;
+insert into t2(a,b) values ('yshpkdugejibjutzatmsgarcysbgkgyeesndaivrxtfsogiavwtdib','hpfzvjhpxnfyocbjmmaaxaqptejuuslgcdfgmonlfpouwbphcozobcapokqnmrotmrgetagohtvigokewldkoidjflejuircavwndfelwuadsmbgexacfwiqmhszxbdfayxtvboltchpqypdijkavsuykdqxbvplzkpdukuamgzyoejobpgmeqwhyak')
+;
+insert into t2(a,b) values ('snoqwbgfsvqilaexfqerfnmorxzvcwmbeomqpfnmzcgryftvcwvtpttuxvqjpddfcwjmgzhkakhojfjvsqxbjdmpgkjjzezchzcjvzalrtkfehqtyerzqnbxbmolzmfuusmzrosqthuvvuzqfqxrvscnhlyxzpkzogr','nmovrfnegyzfrcewfzaseaasrwxrbgwilxhdrjnauhxdmiqsjjhdduofzcqnafzjeaqeiccusqmxdhoofeckdegdfevemmlbsgivplqqpjlhctwcpoqozkaoheimcclnccbwjrbdhlgegqwxxsewrabfok')
+;
+insert into t2(a,b) values ('uetayhtistwdyihgivpeooeysbqgxwakhptjevgbnngazahszsdnwzoebxwfxcesqfvfyqupptqanptnlveiudtkatafrjvhnntlmbgqlifyqntwnwbmhacitacrpblsgvmkczwgvyctcszhejwnbhfqfqqxqplouxcpsxmivruqoxoqgvlcovvxxvaavsnaqcldqtzc','bvyhjlmpiiengbfaqjaydsbmjdradamprikaq')
+;
+insert into t2(a,b) values ('pjyvaigereszvcdhytvjpsvkihattqrflymzctpqwhbuffijvqwzjqiwkdxwnktbxkycrkkqgmssomcxsldxkqprkpjtfiaqlyqrvmmxaqbmcfrtmbyyjwjflxmtgvnsiffdvddcewnsoozrdmhkamiqgkmfmiwbfafkxfaxzvqevuwohesfpkbrxgstmvmhczvfvtspitdtycixhkqwisxhdgcldjusohlsygjarmncmcaubolm','emtntswnmvmforluysqhemtomrrxkdwmosjtddwtiswnkkzvrezkvoizcncndbyjaessoqajbknhyyrejghilfffqionujsnmvsyfxgobyzgbgiroqjjnjjfyfbnsque')
+;
+insert into t2(a,b) values ('ydjhudibblsxxramseymguatnvswyagvdldcwezcqriqfrdhfodqsfjbirosqehfddaxiljsmsjxvtjinqbzgejlaccxpsmptajyhyqrncftcqmlrivysdyzcvbhoczxqpfiazjiumpskbbglxigwqrlhgmfizjffilwzngcybkmpoqdxkpcqucmpa','tgbokducapesnikujzcggaekorkjcirchslhsnfpydnwfvgbfekzhyatbjcrixztlromvtymsmfdhfhktzyxmkltgbttqmyfamflronmpfbgfqfhbohglpuddag')
+;
+insert into t2(a,b) values ('ecpesxegdomnruvlwwvkahyrzdceulgxopirggvfjokcbsmxyuusshlvxxjr','jkiwvzqbtkkfvgduvhlzdmhvtgfipmltgqptykfgctxtaxubgyeswbpugepotktjdoyelpctpdnaojfjsjlfxzcndpobhrsjrzfnromhokjjtgfllikluoyer')
+;
+insert into t2(a,b) values ('lisdckydkhxmdsrsxdvmppcgbhwejmoooeauersmwrdarhabanegtuywfbilkzlbbzjuggiojfehtvznbtbbdfyipdsuttidjwopbkcippsimugogsvuvzgkftsirnypajwgsrzkgdwrmemdqyqpuvozgbhzdhgrsmughybcpghuakfxgblwjyyuiguiwiebzpvjntmhbdt','phjbhdnxmsmctghjqoyptsaqmsoapvidtmotmkbthjiuphmcfjqtqzy')
+;
+insert into t2(a,b) values ('sfttobikmdmmryzcttnwkujmjwlbfwndejipamfemmrgbsrzplxczydxbhzeqolcognpkogycczjfcheptwuvyysdnrvldaqasnxflfgniivnofubemaoqqilrkkyqhhpcifiwqfiwuqzqgcdzcuxxdxipaupeqezllhmqaezinordbrlybiceyimxulyzunypszybtcxdhta','lglgutcjdtkrxfteacsqvtpzjnaikhzruyhqajwawhghizyxutymplwovxfqubdbjbcftebtxkaxzmrfzqiznnejseobncifcfaxqdvtyydzrdvxvucfmgiobrrtapwirydebkspqunjrgvgyvighdawwcfymvhiueixbvfqqsuboyntxhrgfwryjhwufxiszddei')
+;
+insert into t2(a,b) values ('gyhdbavgramhstiuemikruvqwkufypkwfoebzahlkbejffsnjngoukmenpkzilusorpxqzjuqpbiy','pevupjkhmnpgsblyoghrffdvxdqnznyiftodyfqvzbxwkwmxystonjejmzgwktyqiuvjkaxudjhqhpxrskhtutgfpohgcgprvcjlpgurcovrkopeiladwjvfgupdpplpbwvmqotanxhcfxnxkiiefqzcylbykoflzaovpufobidomunbmbutppunqhdyvflfy')
+;
+insert into t2(a,b) values ('ysipvfhvucqtqhvcebfppwoqbngoavapwczrnvqtpnxb','sikoozwuhmnfcbzypswblzthlbbeewlfuyjteglinqochgciruumgmsqbhoqzbntlrtwlyiejvejsybrzqkancoqgdvqgscqhewhdifqiohcgvcbxznsiadjsyxoijireobrnilpieohbkizsojggushoxhkrlzuskukfxjuwuxebcfipeuyrnokhzzzpushnnwunb')
+;
+insert into t2(a,b) values ('kjuzvlzgkmltcicnwgcxcbfmeuliwnzauayocvnwwpxbafdwqbaqwpffxqelmiakajpedzkghepspajdgasijcncipvzbtekbkagsmchjjvicbebmwzjospylzhrhurcsqnhvacjqwjozm','ahbppmruhwalywkpljzmqvkpruxbecuaklwwvfbihxfuwngcxuwknqlfohglithdxaqjwsfgqpladaxyjdzdehxnbrpqtosawkozmkbcojpxvhkyrpfjccpltjbidnlisrekjtnhhtpnywqbarqjlldtbgbqtkattlgxrlqwtuxkxenpsnhgzeaybgcucozqtyfwsdsmummldrthjwcmnecjyaeletwklczvqxea')
+;
+insert into t2(a,b) values ('sbztsfotnhdclkglrnuaawwcrqsgcgheluutmaffimmfeaibrqeeqgca','gwiqrvtralahomcqqxszdxhfxuzwlknkpexmbkwniqqgjrxtqmbnjpieulbaebpycfrjpwydqqyecgjdmheihclegyjtluxxlewqarkxudoxxrtftpvtoieccxuwrkwezfmtjdhbrmuyasrojbgmoaotsunxpylcixmtfywabcnsejgkepcucxafzuda')
+;
+insert into t2(a,b) values ('koxrjvthavwrojruyppcydjajenpomlzgxxpgyuimncyvqutmsowtspckitolmqqpgsvqfuxyxsenihgapvpqjbrgaocrsebyzpclmzvqxsempxinckbvnykolxlmtaupudwjgzytetcokitfqtiq','ufnmfwqnycmvkmehgtkzlezryifkqr')
+;
+insert into t2(a,b) values ('exxztyrbiwhwmdgjwivmkooybymikmkpedgbazswwjrpuszfinzpycivgcyjnnrlrfdqzazzsgtngarqkrokdabrjynblbjunvlshlangrfoobcqnljndymhzxayzzjekiurxykqgszoqymcpoecusl','ymedhsvfosvpbbhpioqdmgajrxksawihxjnczmautcjgwzqbidllwgvysmzaplghozgfjbmqkdhqnxivlfdriusxwvuvjhfaapzpsdsypxtwphtnnbmsrfhgjwamyoyobjbyqgyyzvthcldtlbsxsjedfcojtkojwqlbeyqomczkxbzzpudlesmlvzulnprejilrtzvjbpztiqjxepxokftsdwsqlefpn')
+;
+insert into t2(a,b) values ('fmkxftyfklddmyhwcsxonlnsnazfpiweawsswyxpqivbpsddh','gzhzjozarzbzyfrlsncgrkgoogtkwicxtemtfmudzvplxjvuyozlidgsummmbocjyskoypfiv')
+;
+insert into t2(a,b) values ('tiwzcbnxoxppjcasuwdbnddragyrdrgcxgsjokgnixsfunixcmlroqzfxuklllnhchhyjpfgcfngfftiovllwziywlvaqtqtelitbheethxnbzpgspoyiixfnrixwmzsxitawlcqrtlmxmmhqornsgokjysrjkuqutvptyyysloyzjvjjexclofhawxnuqznbasnexfwugjenjkhzxdnyrdtflohzrzlkowxxj','oboolupujinnrgsvffloqzgdcrosx')
+;
+insert into t2(a,b) values ('hczugiosctkyoreicltoorsxlpmbjvwkmaagaauxobtifrcrfjsmqemoyfsirjcupgtksearoujhllvqcxjmxvlysbjvkyvjpidzjnugjkaehefossrvmblergsjrvdbcoazdtkwubsnvlcetogcgiogdcqhojqwgfrennkaehuydigrtwbnltrobblfysafpxphjablnkhudwxqknaimcogudwhiyzvjvgdczjyfmxsb','zxwakwqfjrhhnrtbpladjjfcsizstywpjnwrnwjidqybmnumrponudkjgpfypfakjbgukqieayvaccyeoahawuguvbgnqhpwhmtrhekclischoxwnqzqbhbeyzwngimuzruffzpqhpcrch')
+;
+insert into t2(a,b) values ('suunyeyzkaqmwqwuvciawzvhyjkhhpcpmaoxulizrtvgnokzbphpszvdgblavjibxqkgtbybktwdybkiophgnrhvrruzpzmkvguhatgwnopugrbxovserlzczqusjn','jjentodwreymgjaqwejnfircdbuikxdbsnqbszvjuophtfnrjapebvcszepxrgpluczebbhpaonknmrahxkjqifhejzifwxycasrwcyeijqykfgujqevozobhuepgwftxuqjgsksxauzjvbrsiuzymlgmlltdnaaafanpkpbyjun')
+;
+insert into t2(a,b) values ('ysnyrmnjzqykdqfowbiirtctpwtktesgegzgeoozezfpwdsopougyarogicwqmrjpdpjarzfpzjtxmhbzajtijxqcryvxfrmfsijzgdylzicrluavwqizoacesjjygjyoyoqmtlqrfaotaisfgwdtiausauqjoqhiysmbnkvclloohfvqpngcuqlftfjvhybhbbxavncakwvoqqdxjutwmrtbbzvkxawtp','blcpmirdzqkqpwgjvphtjbchjexlwxlpmkzsvvpzsrzqnegbttfuqgsuqkcbbohvxujeazqpczabxsnriqdpjyztvgwgmrkqlfisxqxcgzveyilrjnrzukmivfrosheyietszogmvjymtdllcqghakekivycxujfgsjaacqbclbccaxnczloojjjxjiawlqchrsdyybagcsawntnt')
+;
+insert into t2(a,b) values ('abiuyayiintssfwuj','vrxpfeosjpwzedbkisbbjuncbkyhmdxfkjfsdbhdeprofafvnwxgbjptghqwxnwlhzbekhoeaavn')
+;
+insert into t2(a,b) values ('djgigdhsiynuljnclhudjbjwdnolozftxzycuymfjtukfvcgvaxancghfdoikwxiwokungrasvbqbvlvswjicwsixmkfdcmlmfcexmxpztvwlxdxtugycgwzvimvbisxyupvalwqazyezyysbr','ihtiqkvwqrvngvsjcdqylkwtfgwvspqszmxrujrlgzvahekxvypaiitzffinblgtxnyzelrwdufprsldqeuqgaeupsmrtbjlqhqgifmcxdxnavoyfapmeefwdfetejvmzukrxzqfnfpvqjychvjsjivrfgmuafkygcwhhrlmozaiypllscnwcebyekzncypjgstxxrkxgsoimplucojkgcpvgbofbobqpaschphaalspxv')
+;
+insert into t2(a,b) values ('ffdxtovwscfncigiocsfwbcaxlcttfougqqohhpysipwalikkiqfqzixuwfievhpfwojoizormjuvqcgeehpfzvjhpxnfyocbjmmaaxaqptejuuslgcdfgmonlfpouwbphcozobcapokqnmrotmrgetagohtvigokewldkoidjflejuircavwndfelwuadsmbgexacfwiqmhszxbdfayxtvboltchpqypdijkavsuykdqxbvplzkpdu','ktqvclptaaltezrqhccrsmlglsswpeomcirzycieunmlxmnytqghdyqhawpqeebnsisgukrmjesetpznsstdtlicwpoojngvoivaodwgbifoezktvjhquvoqcktqlyrwlyinehkizwbrqczkdauvvcvxgvvsurkawcpsfqeeosswbrjzuiuaiooslufkoyewx')
+;
+insert into t2(a,b) values ('wvbcyfuotxwkdrynrohgkjpoqrbheulysmnyoxwqprdttavwrmnsapmavbualmnsgotrpxqaejcalzfuzkggerklowyqktnxrbyunmautjjwiadxbiwbtroznzyfdeumseuklcqyvdyamubdydzhwlzakowagbarqzwqtykitpalxpukbuczhkjwqsirlmbdpcptfcrwcyckybihzhoxqhinlnnnajkskwzeckvcl','haozprztldywrhyqlkcqhvmbcfuluhmuxhyqpapeejjiicfuaqhuitcrvqpleptcvlbvbkxlowyfzs')
+;
+insert into t2(a,b) values ('fqbnoovqpzyauzpgdeszjvklwqgtzoftzwtjryvrazsehshamkneifhlztldlrmawzqyagycycrpeekmbmonoxqgjtpknpiemxkvfedgxgvrgfhbyovoqinzrrirtrxljktotsnzsaknwofsxmgmsdjxjjtnmbmwfystgvcpn','qexkupntbjszpdrizzcqsvizobqnujsvioxynvgzwqlmtyymyshjgsdmxqqxbexlygydrsvwnfapifyqkaujfoijbjuthuyimgozcmoekqojwdpzshnhfyretpebgtgtzukwkebxtfigkowemlwlwpyupcrxpyuemodbkcbdmaobloatbogmpoerbmgcuevcevarikoqcxnmpojtric')
+;
+insert into t2(a,b) values ('ehxlbnaxebdoymworlrokibcvvigopttujjipksirhbjqybveellqfdgkkwaopnnapyipwmywreblvkxqfoypfqyfdrekxrowftvqomzbeidwvkdxakvccronsbirjtbkycizinygyfggnmwrrtxnwrtdmqogjylcbjvuyxohbjsskbsxvfqsccsyswysrvfaoqrchqqyszkrdtwdsi','cnvwwzhhccdit')
+;
+insert into t2(a,b) values ('atvcpkudkrhfaldipckvenxmbzomoeqyozpjpvmqjatzousfmnatjgcolfuheiwlmncimqcfslifogdatoxfmjrvbdmflnigimcizpjuqefpdomawnxqknbtnpjxtchottyxuufruquibzhkxmbppfxzrkcseubyhwhoqfkottkemziidqkzhehmixdwcomqqtlpvfpfqraojqlrwunnyyhtruwparhkillr','agbzrlviwxyeabaoixkgcajdjxolcgysrhlmioyvyubzbmowomtllkwipmkwwqggmrtkhwwufkytydn')
+;
+insert into t2(a,b) values ('mrxbfusyicckepiqklgpqqfgkomvwjhiitdzlexfeudokggcwdklofmtnzdowiihi','ptufrzfcjncturnnfigpjillxrdzwkifvybszbdzojzasikvqapvayccnlucprcjzskjjhrsreuvepnrjjvzhgxxhndmwwsikjruztgtppwxpdmqyorxvqbreedhpzqgjdqxlrwkyavatqfgcdmlulqxuvrciukrwpumvwqrwoynumeyovvfuysqauurudk')
+;
+insert into t2(a,b) values ('fnxjlretakjnhvben','fgzsantpsndsuhwznaudcknppvjkftnibfcypklaecrinjvnfcnvnvrvhwxjinqnclfdofjmxfdbriddetaetaehztubvkgftokoahlugjhlnagzrslmatzuyrqmamqripvdtcebiynwhptgvqeouvtebrgreqpfmsxarmmdafmuviywuggphinehejsbcyfwcnjeoungyyzxfcnjlhrjfrwiexnzzrquqjwrlbmmlnsdbcd')
+;
+insert into t2(a,b) values ('mtsyvuawmrfvzwwelmflxlbaxyuwamffxcmgviakehyxdumbloxefpqsodpeilagahvundeypi','nyzfqhthalfrgdrpnvyazzavgkwmemlzbfloevndqpwclftmfifckpylbtjywphutkawnuxjcfczljvfizfgawsfidajstukclknzyrevzdcpomxgfeuqzrltdchlfojpgyinkrbyxenbgwhmvs')
+;
+insert into t2(a,b) values ('wrmculyahrnlhacwlduiiebqpkdeuhbkrmaplotqztxqljnixspkmemamovrkvryklfcxmnxhhqtzuwgqrchontdvaqnhcfacdcotbbaplikjdldnfuiiavmcmzgwfzcxeyqqsxrjovdifewagdlohwmwivoxeazefkwuxtucgigqefvozxyrwviylvxezridgyyryvtzxzbhecrnxnocgrrzhecssnjeafrni','aniimisczjhvyibqhelydkeoohobhbntucysdzpkjfszzyewujixrhokmyjluvgufvebwudlutspwurvweaffgdebsqqrnuuygdtzzemxrdtzbyvojfsqvfsypazyumxtgsixbilldcbmmgfqpomcezvbdazgkdiwimbgjdpdbtdhoswfzhqgvlhxojvyuzpyiigdzkhidtrgyzwdjagvztowwvvibrkxwzzkfwpefninwdccpqinn')
+;
+insert into t2(a,b) values ('fsqmyylnqafeftzjkaxgocgojbsvbpevmtgnjkvahiearmliunsdsfwlyrflerduwdlkryrijbggwwioqrigchlsvpdlueereasngoemgqgyvrdzziwfwtruostxilefivakzwwraxpvdogcqbqfexrykpznmibhjlqrpkyializywwyrhpolhreetchkdpdsynjc','hqnjtrseiosalrojiuxgnfwopyucwlsnbxxfbxxlibsvtzbggorjmcywddzsyxcbbjnuveevoawfpfiosefkwderqlcxiyrocfubzrqwqrzwwixhmkjxvrzfaepyucwlkswypyplopymzozwbwikedzugdmjqxznxhnvd')
+;
+insert into t2(a,b) values ('cijbfhgwsrwtogdqjcswqzawwoujctvpexekieznxfxmquyxblsmtpusvmmvxursiomjjezeicevofwudingwuzrbwfxbbiqikbdwmsddmzfztas','ttonhhaftjjfsxctgmeyoojvufyockdbobslwzbyyneozzzoipvgutaysoexvkrcpjdibpnhwtfjdvhnhhnjwgtgdrcgjleuteteaexoaqmgebhnwqtpbosgsqkzpgiuiesxrriaygdetvvpvlfevkpjzqtraoxrqrthqfbcnhjnqegtmbckhkepdvtupkdmamwommnvtvmebpjo')
+;
+insert into t2(a,b) values ('kwcipolfoxrmjeidqcvnjpfljdtfwrdgzkuhcghndrdanikqxpvqlbdwxfdzhytxokdglvqkuobgskovkdogzxlhifprgsufcwvvwoiimleupdsmadf','uzadhdnmhflhxwnhrebtalpsbmfgoxtkhfikaxtelvhrunhaausypddwvtejfaqygcxrhklicxwavqxgrgxooolhlfqnhmqobwqifpnhvvhcwbqcbfotqrgpbztulmnrthtdgudcfgyrmiqyhiotqalrjfvyjqtsvvsajjuyloooyekdfpskjrrqfpvtaihyxrwbldxeefrdpwvdpshqzobfuw')
+;
+insert into t2(a,b) values ('vddohwtyumbmvivhttjdnzufnblyxdnosnqlewnicfhhspdqiyqvornrpxtxgxwdmfatjziryx','pciopqcxlsfyxtalgqkxpnujnkgitvbokgwxyjeepprlbxgexwghtezdwpmtemczjaamkkcbmonyoiwhjehpwlqbeaoiahd')
+;
+insert into t2(a,b) values ('gxcudznzxbpfnemcrqzmvrertcjfcfaibojhnlwqhjzsnpuhntbvzagaczsvctnkbehyrsaxexrjgxhdoyfgigowalhd','ftxrhhwpdxjyjjoriyuotoezpblnctqsoxnrxrzdlhmzfcqdizmwbxmgwvyyvtcurljydldlwhauvtzlodbcphcfwriswwezfaqrziwqtenjmdkrnndenkzzyvvflqmavgkbxzximjmbykieadsbx')
+;
+insert into t2(a,b) values ('vpejaodmvnaauyjaxojeegtggioruptuqrwqdyhmmgifhpkdwciyjfoxlsmxrmbbimrzuakjeabrvfokhsdjqrwpmlhbwrrdybiefgkhmjvjyzcwdyhunndnebytzprucklozvfpnpxfzuvyilobpdjcnspxcgmecjurnalqcjzzvojofhennujgvcclhjmfnabvxswtrhbgmgvtcgqmticgnseedhedhhvrekdgdouycvboqqvog','eehtqzvwolpsocckudtxnarjqquqooirrxkaxnbhtftuunuqjnqmanrqupngulmpvigykbmiiugczugolupdmkakgdyvrugqaneaogylynfdywbzqaeauhyrshuwykpymonogoukgqwdinjflqgzfuvkvpkbetdxmlbiuasgsmacrhtjuhgrdmjvzekzzrsseytqswmfefoa')
+;
+insert into t2(a,b) values ('qypoytuamjwqofmheueofuihnhzddgvtntcpqjtlsrfboakjzrgauuxmpdgpxphledvqdtcytlhkanpywgmwidxolmhfgpmxupcxbpcfzvsaiieksujahne','taktvwuxmmnnrjaehnihjwyniaglibjhrrtlsggvtoapksw')
+;
+insert into t2(a,b) values ('tmtrqllzojchvfdhatwqexowaraonmjemduotyebezwfsxigewdtlcpqvtpdsbkcwghfxrmobkmnuwivmzdzirmwpgeeuqxqtpuonrrvbqinzdawrwotottsndjmlthknmzwvivetoiyxdczkskudsfvu','xwbqwsxofrsxisxqlvmmagxlppnlvyyrqamjcefmrwnrbzwblpegswbueioqgdqmfctoucurhkkveuexwurfzesifhctvqdikkjggtgpvelmhxtjxwhmosyltwsvemccvphvxhncxzjqtuwshdfdhkdqdzlwujphlsuvcolkpykriknkikweaotgzghgaxzyutyfzrovmiopqxwoqpblglkexfsdgkmsn')
+;
+insert into t2(a,b) values ('ueylzmftviotjjnejxezwpoxajxctmhvevhcdicowsgoumwigsmofihloewwemidrldpoxarzfagbtoqbnfiilhwuuraxuojzkyjzxzspybdqkudgaydvmtrocbmumuomaimqmswvrcbkothpldlzqsbiiminpgjdywybjidceamvbotvfodtjwie','cvxtidmfrumyewgumlavgwiwdcpbmvqemnskqinapbhjoohjliciuosnknthjwyorqoefacelhaqsffplalmodbdtcawzionchllntlhkyhgldnjnudfaiqeljcduny')
+;
+insert into t2(a,b) values ('xgnhysgaymikdh','kloahmhnbdqdphsvxfdfdtmaxrewemiflbxzafwcxeklcqzcewocpewzlhgaepvgdxzzeikkhynroysyxlncxrjibrvwwbhrvdlpxclacdbavunqnydutcvlkbxxwnkczdmwwciamttsjleuwvui')
+;
+insert into t2(a,b) values ('vguttfogok','wydfqeffsxoslckkoxzvmniddnporoqfmpfncjnhvtrqzeahfkzrxwlenhsizvfasgqchthqrezwhnljvewwgmgltqbpteaejodmxehankisniajuahuzokqgytseincgtrbwpczyhfvh')
+;
+insert into t2(a,b) values ('ysodlapneevwtcjjfgowffrgotpbvizjraejuqnzgrsyroszdxydtoojxviemrnenmpvufqyapxbgjvkucwxskebrnjgfgvnjrgjjfigjdvrxvbemtkeelmlwctpxbiyroqffcwpxdbfvqmwuruobxfnfxnwginpuumcicknvwzjawbzfeaxnie','qqhjpuxituistmvajtjzttvpcppnfwhpfqktypuopiedpzodhmqqctaxtxrdhjcrozetanvbinebljnycbufvlexpwltjfiidouldkdzvoyawlsapxvmzcnwpwproxeglfowkpkomhlcuwqwwtepbajqpqlppgoiiykrcprvaqyfqkibpsirfevwgtlllgtsemggvor')
+;
+insert into t2(a,b) values ('sjxutfrzmwmxioyjvmrsolkdpzhzpghtscguglsoibkxpffwfqlxfvhwpqjglxuqrnaowhahlcbdqcuegoisrqsvqu','uigedstltxnenqfrpvfh')
+;
+insert into t2(a,b) values ('jqgenvoyhsoqhvcuknknxtmcpnszwfoxqsejnwecswiszlabtl','ebkdbfvevtuegnfbzjgdkhmzpalpkadzxdirpqypomyqejsrnhxnovuutyappvivzjnsqnblpugyujjfkvjqbbbmfmxzmqezwkeewepuhyjdnjdjwlscrvrjbhmhdngobgfeoqwvooxvmkknmbniyqcatlzlonppfijdmnlstpeisjvsligztepswjkftxukjmbskurhrfuxbcllokdvfmwhgfxsvhfafjsrmkjamzrtbfngyrzoeyc')
+;
+insert into t2(a,b) values ('fovetwgizrcpnlrqkdlbsfalvoohrleihupeqqrbabauonbwhespbqqlgiikkqgadgirvgibqhpjgdszbemsdzpdufnworoqgwzkjexwkgzxussiygosaubbcjpbbdpalnficgcqwtgrldvpojokwoqpuoeubwzogixkoetdsaqeyxthqxctrilhdrczlqvzyzsxxckjoopxxmetjaapsydrdpbehqghqdmdwuvtobndhsodjfgrrsofjll','rgmbxaerypswbtwwxzyhomvjecdrdbtahgjfazhubvjpqarpsthsiutrohqwjosmzsyvqahbojifyhjkjwokvrxiisd')
+;
+insert into t2(a,b) values ('oxwyisyocyhpulklslcnwnmlanroumstjjvslhlctmjyqgsyihrprualjazmumpylzypvvcgsyzyfdxukimxhacubmmwlgxqgpvavkxqxlggsztvltwccuzguogxrgyzvddzsfcdgvzsaxfzfuragaprvtinyrlwsdqhzivlulduhppisglbccklgap','qnyfjganitcbjlydwewzrpoyvdqsrpwvbvwgwwwcdtsidbagdypgcnanmolkaovkayzpeyvncamnopllvgfhbwiyktkclxpruveh')
+;
+insert into t2(a,b) values ('xfbskkvgsdamdqgjbnzmemzojzpwlmpvfvomywglvwwivwsrqrzepcnuulvjziajuovwzklljzupjmqquqmzl','joebtvdsoohzlfucsanxayppdshzghmnscttawgnzbalwyhbpqzpamxbdjhdzraeaiuimhxtktujgmluzjfuiyjigallwyngjintljdeapzcotrrlfzsuhjssdfjpjwkvrhoaxnmpzftcferqxlzhkmfpmxwaodcbnbwjrupuhvlqwnmmdmnikazksbakqgbbetobsibfqenkylpxfwxhnqnagnknighczszojvvmakxwpybwgixro')
+;
+insert into t2(a,b) values ('curludotpvpwkgrjhlsauyxagkgzfhthxblcmifgdxmrxowurrnrhqqnyluphyoxakiffzh','qlxbxbozcoayqkkygxywdvsterwnnollmsikqgrimlgmfqcuctscyscnckgjiswurqburylmfbyejhyajayhcvadhhdvvcsehlulbnsuifauqswukbjgquucuhnaucdmxqtgwdtbebeeilhdwzibmpaovprdyrjwepnsokozjvrdgv')
+;
+insert into t2(a,b) values ('tuthbotdzeplpuksarzjsebgiudubhsrahicscmjrthpdvprjmtepywudwffjwlrktxjssiyszbgfnnvxwpdecuvcwzphlxzbraneaxmfiphxmciawcgguflliqioktvg','cnyqrpansbzdcuuuzgrmlvwuurothvojnkuctfebwduictcnfmgkuwsvqbwzwnptjmsaypghzpqyscmnqnaxdglwkudogkqhazgavmzzhuihurdagmvrvuddwakqaiyhosjcelecednsbiwaoxeqbmtpyqecfjppjtdvuqduugvszbkvyrohgwxcqbjyikhccgpxhxcflwmlhojkrzemtvvuukciwffvtiuqbpodfnvgxgprfewhfkksolnlg')
+;
+insert into t2(a,b) values ('vscktf','fbofzovatnmlkrngwytulpgwwxilrxuwrfzkiozrnjrxhgfkpomxymgyexfxnnffzrdbydbciomqytypkzrikeihtuvpylvpovrfrectusvptxpzdviblmqdlnhujmhytmnnhajrpyygzzpzddolqpdmxiynqpeqwekiwtyyofhnocoezhvcfuauqxsntcxnw')
+;
+insert into t2(a,b) values ('rvcncgxzazbrpwcgxndmjlnvngfsip','pzhulvoicjepqqyvxdngtyellkewsasxtyqbrtvqyqmoknvkdyodsqlwzqznzacdimxildrebkmnmpunrexzkagqmnixlqrhcipnbltqotryl')
+;
+insert into t2(a,b) values ('cwlhrrowimksbbluvxunclwpgsmmduzzyjufkghcljwuctngdkvkxyssjhintvnfabblmhqmsmiiteyeryrfllbnpdpftphwztygplaohmvzkjyexapwcahevfmcwfedjsuzefdubkifmancrxbicrndmyfvqqxnhmenrpvgzkolnhnuvrsnxtwcdobxjjokglsjpzoxgslnrxcixnjypewcsfgmzxdszqpggnyqxvucojlyhggejwwqupves','lhrzzibrmeitdmhjgmawljpnezanfrtopacujczjfezzvwkcmonzanqlxfqeuhehgtwbnnledkdknsweohyndhleiscsjdovxcufxwqibdmcxntgnbu')
+;
+insert into t2(a,b) values ('tydxcvkgqnwisanvpnjmuuwaapddaoyjnypjcbthmfgbijefsrrwozluimbjksuewnusxioqxlekhqwyrtg','xigbkmzomxynstpxlxzxumevgqbxlyucvcfmlwggkkbrxhpzyosbokjsjcrahrlcwhzhvehrfiuqlfhmzejrefalausxsudbwxweastiqofi')
+;
+insert into t2(a,b) values ('lhquyjlgylcejpuwiqamwdwokzbowesflefzwpmufpprnyyudwxieesjuppxurvyqrczghypsguqmfqlcqxueerkwlfbliqzefoxbleszfufctcmleqkqamudwguwxrffbqxbxevnoefpkutivkyndcwhjqfnamkvpvdcoaxdfpgguuhwdmoenhjrapgfjnawguwmycyjxdzpuixqghfrgfdirqbljiqgjxiuvqgkebla','mfncuihukibftjnumjbctcmahrazsademom')
+;
+insert into t2(a,b) values ('vdbemvyotelvrzifvbsstnzsoomnulgrmptaaofzmpzdqqgsrzzgmqndbiwrtffajtpcmjozergbcrsohltluekbrtkahutznztgdtajiwydyxxalvlfdhqlyfsvftkrctogcrquuidenvwmurnhcn','epagzcvryqgtdkqfczivtnueiysiauoqmknnntcvqmjzuzwasqkvldalwvdhvoqutpvcfn')
+;
+insert into t2(a,b) values ('gmznzeednfnvssfikylytwjyacygubnjtvoxzrkktrqvotopsknuyfejpifdskmieqelggrrmlrbpsofhgrsymxricfbyhgcnbavoxttnwcppknnvdsstewsxufuzyyytyggwvizwjivzyyqtgxaoplnivealjyuvuvjoaycbddexbjnwidqyhcdckdqgxjdxtplocpyuduuqehkxptgbcdwqymgfmhsrlgvdlxcflwooewkogdz','zkbfeigwvcxopsnrhuhvyuigpxgthelblgawwybmfojnkkxdcvornigltgivsnhwclvwqcaejodcmzoshomykbtkilcarjvgmlmjdchpjmppwppsejojgrsmxibplcgyrblojemeqssysxusdxyssbcwgelzmzjwbznlyrxanojkmyynwzimoatobclibxksqsrbdksgvksp')
+;
+insert into t2(a,b) values ('pophkyqrwriltmxqllozxgnrobzgtttoqsieiipaukyshqcmcxnbfaeaoxjloxuuteghlvbofrnfsuzgutyqburkwazzcelhlrgppxdtsimwybuurwomjkovnfnondsfsycjwhhjxqjmzmowmvqulpufglfqlivndbrqpljerwzcvjmjugvtiiesklbqwpmauwmoajhenbfnqqkjzmywerp','bfsfongfothupcoljwekxsschzeouswcvaldklqfilrhkyomuwfqzrzgusdcsmvteqzbajeqxjtxcxkumogngpzfyfdttmi')
+;
+insert into t2(a,b) values ('zbjxluvhpplhrbrhzoebnuyyyuagwanjylbzcojsjsdyhejusjovxzqnwfxkwdidvrshhfsjtgdwlysnrfbsurfylsulfbwwlzdqcfmpuywitxhhdzqmbhzskixbxxfoxsbuqlvicbqjkwfszpxvltqyhpkrujcqhdeaqprhuxzemouejqeyrsvybdpkbdjtdnqzrvbyxrqdciashqolbjfjufwogrlxlbjptvobjacbehyizpqa','pmvyigylaqhrjdxjaomwaynxhpcartmydjncsmrxbodnpzyvcxcawncqasopcumibwhwdwdcamsezpzpnlekidsiljmhglwrzotmvgdpdnzyihtqtpoihvonwkogznaarhowdfxnnbzjzvctbvwkqrrzrrmxujdiwvliqdgtvootpdvxrsoaeifvxefgusifevmubhakvaqnonvtnlvcnvlnmpvzyiparenbhgylkoxydskeniutqiuwmtjm')
+;
+insert into t2(a,b) values ('gwnhanjgkgpqydxxrhxtzgwiqcdidpbwvfsosiixwuuxilknmnmnewjpsqdgkbljxueyetmmhgfplxiwqyjufrdmhfsxmbvjmrfbmosqsimoigmyyngdamtfsrsattxvdpvqufavgegrr','fypmkkxrtggxroxtxnmylzfnwkbmxndghqvryvavjicaemvsvruinhgwrubvvmnyunfeqndqfvakwqxrucphowbxkztzsngqdbsrchdvkkjhbwfmlmrhaielfsmydquongmpfponzeznqsrs')
+;
+insert into t2(a,b) values ('diyoatfgzffqawkgadmlopxiiivlkugklqppoqteungjibavtboxmxinftqlwwffyeygxknyliievdwrfxfcentgqbioufjexcvoitkjpxextllsdbraaizvcxbnuypihebepiizlzqcvxbraoqngizblwjgjflbwfskovwgowvkhmvinzyogqblojsbnlexvbomcunzxn','ahluawbivnwlwweypaxuobzqeoeawhxhgxppoqgdolfvnfbzrcbvreezcjsknogwjhufxbwzlowrgigprybqhofeywkkrohgcwfjjggvbfrloqaphgayzpzsevhpsvi')
+;
+insert into t2(a,b) values ('mtuygmob','focvxmvgbgfmozxnbetqvjmwkmwtlqxrrhlrsaes')
+;
+insert into t2(a,b) values ('tjvkuqkoyycfdgzqseptignxkxznbncxatjkxzbjkmukhlg','pdiiduxgurldiarxqmjnltjeovkkepfrsyfztkbglxyilftpbqqsbfnszmbkrzogyppknbiqfsvktfexoqecsyoltfzuubfzgqwylzcbiswxwktczzenbaztqhxazfcrejpkrzufvqtzawwjnxbauuyvhpwqpgnfgqeagvnebtnqo')
+;
+insert into t2(a,b) values ('miculgqhsktqywmnpvdouozsfjhbhmxqsgkgrpvmmyriikgpstnuivdatcdjeoennuejauwpxwphuqpmmvqajduiimwkdflsgxaeliyylrfnqxekpzmfhciodocsiwcpbwdfmeydndvxsnrhbuhqw','ofaugxroygacutpdhycymkpivhfmgwpqaksesgbaqdflqkxisyrfxqlmgujokdvwuhuzmwyqpxlkdjflonxpnhbekvonednfsanomjgept')
+;
+insert into t2(a,b) values ('qybap','wphhcrimmbwfvqlefcznkogigspdxawqmvmrweiuwwuwhivitxokezrzk')
+;
+insert into t2(a,b) values ('zredbcndqscmkxjamutyznvgcngkupudsfakjlopowbiuppdesaudigqnndxjvlauokujuvfnboqusteuiwcrdrtkuewgwdzeqidpfvzlgtvmmkklulyholxljfnpjsdkqxvkomevwmdmkdxrjpifppzgnsslkfbfsrpnnrlsqxwrjdgjrzixinwudmnozlzacxh','fnztltrtyqcdzmbmnxikblzpssjdxvmdpxwkaghsjfunfaqvznacvqpbevthkrrrkkneeqpavkjjidotirscbqxqvuqcvntxuelpgrgaicntsfdytp')
+;
+insert into t2(a,b) values ('tbzlhzatjjxwcmhurmhzfygczwmzrgkeaddhtewukzelnfpulmsjjukiipaepjyhmiezuaqitciqecfzpxhtrfhivscztcmljuhlvyeypiokueodhvidxkynspxkhd','owrlcymqsmfrvokffgiuygdryejape')
+;
+insert into t2(a,b) values ('ajrtfqyfcplsxhegeyovmyxhrgfjhuqrcklgikxgpxavkrefprncoduktgyjvmnmngzrpxmdvbrbfutiyamicdcavcwxdhfxoentfveyfffnxcpjtmcnsyrxprhpphiwkhihajbtxzboncpemhnzczbrgizkdafynxmlzajwqkbgmiwojcdifoetisowmxlrdlfumsjechukylorimjsnxgvcmjsyombsyupgtjparcnxmvlvfkfmyplcsgjtd','wgxghezulvschwllstlmwzvwvbfyygizxlduqhelreuhkdlaadfpznlrhnfbomjxfwfrbmalwoxdefdsdykemochoykvuosdbeetsyhhmuktcbdcekrqmootiorbznixt')
+;
+insert into t2(a,b) values ('uhahhoeoomnytvsknufjpgwbmlnlpvxowidtvztyzjeimdlbfjnjbnipuhpswjijfgjlglcukancrczxmfhhqhwmsnahwjlldxrpynqimtmratswmcbrbkkoyviaewhuwbxhdnedo','evwdbshyhmxjkklfxraocnjhis')
+;
+insert into t2(a,b) values ('usjbvjmhcvrfplfbylnbphzbzzjrcgvbuwucsukearvizlnuqdkruhejcvwoluxtvgfwzjesjqddturntqrlyxaxushhpxkqjhwbcclttmcppfeitwfemwmvthjjvuarxxyeyxxdxhojsrsstpysjstogvwplrrjbqajbkhydkitnwcenbharjqmamulkainqp','iornmx')
+;
+insert into t2(a,b) values ('kcnugfwvvqrfzzmcyfsebcdlohmjdzpbnpqvbbuscimrhfnadtctfpzxsniagxurtimjuwvtqcizyskyctakpzbric','tgpkdctskusrqjkczarfyfxrzgcnaryneavdiwlbmwbvpeejrfeewsxvpgbhvqoeeuqkkuhiufhlarhnufohwcglihsnaxjbouhfjiikyirrpshwuresoieqznoswpqlxkhxmgipwdycuechhaqmysoxqufcgtppfgtigukkenhsoygpzcptnecwnuewgkpjqsqfxssarjnpzzzkqlgbpnxunfkocnyqxtjarrvzlydlxpdyiaoyejjcxiab')
+;
+insert into t2(a,b) values ('parvudqblykjivjkyjdocscchtrupgwpizntkzckstviorfvqzycjdiliyeovntcmkqutrljwljgaobunlcqnwuwaqrjfwxrhwdbqvblnhnnlrtygroldixntfqhztfffezwvzjjvvbsqubvbrnefmsanicpasleslivplnwwmdahrtjouzlzneuhauabndogpoxcgcshegxihuyepskutpjnbjn','koygtzlotynrluwxpprlmnhdygfcubhvcfbakquaiqcdnrzdanomspwqlxfvbojvdqbybexonkvpsehrgxvwwqeznrnqv')
+;
+insert into t2(a,b) values ('ioqntdwofqrianvxguwpihedtmdoocncwlmoekryyhuteeqncjsimmxmxzkyxweoqzrklvfjmqudrssowxcoy','ozmycfazwqariijjoddxzwpseasd')
+;
+insert into t2(a,b) values ('kziwzxydrkoryuyczeaccssuswckpbppigkucfgeersudglwgmbqllxvlmkotdpbafr','emllqbnshtiyxgnpswcrvwiejdeydvsjzpmjm')
+;
+insert into t2(a,b) values ('atqvgmgefktzihmcahuysemsnyfreozwckjmtiihzacetxppbewiledyrqiyukzvjdvxmgjuaabtvktgvgdsrgxltadpohxgbodhvttqjdlqdngcsjqtqzgygayalwvmsfguhnaq','uginejuxvkbsytrnznsyapszkgavatyupcbvtjyzbpolakhdtpboqhhhaszgjbrawjlfhmdauixfumfbrzovvplghykkh')
+;
+insert into t2(a,b) values ('jzravmiurevubjnvhnzzvizlgurwzqpgyrpcvlfxjewpizbjvylqdzbhwejhqlkomxjvnnzooxzhhlfjohdleehrufdsyotpxqaxmzuspigxhdgwucahmreajtoeopotnimxdqbrevofjugfzgyiselrfgsuzwfjkxhhqgpgwthvznxmkixhpbgjxlwscixtxdnatro','taljajholvqbtgryiujxfffohmtnzagesplbjroxkeitplvgeycwlpaavamluyrbprhrlpqvmivkqknysoarwktdmqkunxsspfbedbaxoeappstmjktopzzjnrerfjwwaypxsyeiijuljshohgacfuwqgjuboudjtfjmocukfmkufegtviitjwuznfaydclnebsi')
+;
+insert into t2(a,b) values ('ejbqzvstucahqbjnkpmlyqkarbbuoyzpznpoecevmelhbwwfkzjfqlifjjdijnqdwbktdfncottldjwjnyakvcnwxfdngmpggslhxlvxgpqcndhxsfqojcttxngxzdobqiujvomkgcvrhzfjiiqvldaggvodnhlmleqmiekpxdqevoromgkucxooqmfcdxdroo','rgnfauhzlgbhmrcfxrqhccwirzkassanlemvkweonlqshmejucrfuvaaftvysdhrwabbwqhmgapodgiptwrkowustmcdkkefafgrxlxocrd')
+;
+insert into t2(a,b) values ('cmeyvoudoyutkrgycwjpmsqgybqyozfcasrersactugcpdjknbsxfxcceofmbmfzutveoyganszfaxtotsabadqbdbypjatcjbwrqxturfbccsdtwnourifbmsddcwqwcidejbhiapedhrjlylfpwtymihwdvjnwnddnoztxjgahemcdqxzhfbxwsisnanwsdcyikgkobsvqpuuqfvylbqmidvmzmsltg','ejsaazptgixhqajtvwbcnvsglxbxtvcgxnznzojdchrygdzoofq')
+;
+insert into t2(a,b) values ('gcxlnroksrxhzqasttgurssstlyrtouhfclhwpiypzoascm','wykkboimwagrjgymscfdxkmjxzranwkhqyjzyrdlsqkrqlstxjyepdb')
+;
+insert into t2(a,b) values ('dklyngkcrcooacdqihugxdzjfrqvzwnbrplwwfstcqdyjbagbntbiwxqdjcoijdragmlwgldrerlidgjcgveklybizfkoeckhlobqmjsavqztbnlzoljthkohmtnkasvoogjsfmrwqzypmxacnuopjukwlklrfhgz','muarciralpczjafnberpbqvowyuhdprprzlmavdjaqfwlakwwbjzhwjimveotqrrnitnogoussjsclwneahlyrqgajiqamdqtdcpirphsjdwb')
+;
+insert into t2(a,b) values ('fvxctjgqyaqbnwmbdfoykbwkmwubielapyhhiqgwijfmaxvberfyxdqtwmocnkynyrkoqrhyltvwitrwxmjsvgpsmtkochpgyvcriwbbfrwadme','rlvnbkhsvzjjldvakekzkhdfqseummjzfhbjytfxrrbwlgubifvvghqcwcjzgplblxeoernozkdldxpydesbheowaopjevqhxexohvfjmelyzfijahcxnxpxjyumgthomshgcchrszorxlyaenthkjbvkwgngimmmlkyvgvpqkbxazwjyyvpcndwsavmtleagvmabgxfsq')
+;
+insert into t2(a,b) values ('qzkjgnjqfkrpowhbquqlhhzdhdlajrdkunvmtcdknfrnmqaadymlkdzivmhkgidmkkijhoebqvldgtzjvcktvyfihjypaekfzvkbhzoohsgfxsencopofypxbokvpvvvvvqhymifsfxdsvhzbsieujitaitpswudvzgcrbchenupsuqvdojupvtspyjdszddnaa','ykobnfodrhvloqnxxmslqijrwgznzzhhswrsxwsjcmfaeudwgzwiccwchtkycitdenoakpnarzjwiklvtaqmxqksoufipcamhhiudmrwvlpgxilcwgcqihgbsuecehxikxqrrthpuimhfvmgbhnbborxehwhzgvylhieqgjvpxqbebctvnyhcrzdgepmc')
+;
+insert into t2(a,b) values ('rmmypyqorcsxijyjywisedzrdciekabkfkruyvynjywsancgrkrasyewdblwzrsjagixwapafphzzxmxatwwzkjhcankwovfygetwhgsftldbcdnbhsnoiudxswplntlumvbqfdpoinnevjydywdfqimchvqfbuaomxtldgplorqkjujmxlorhmnofqegsfrjajtxcrlrbxrqmzhqpvdpjojpuxblcfqzpzqj','jmo')
+;
+insert into t2(a,b) values ('fswwhvvdbreiijmopxiuflzllhlrcmonfqoxkhmucoucfztyniovmbwbietpdcumoitoaedkylwlpibwjhlynpduohjjzbbtsrluaxfnnjoyhipucrtftxbghwaknpslsssfobtbqxyiqbyavcyasrjjwhismoluxwsqilujwvmisqtheoiekujjwlfuwszrfaxmtohhxvnxfrrbpyfxniorvxppnenamjxcs','zjnyfgjtufdllqumszjmqkhgyctvwjkdydsqydlsmtewgtvecd')
+;
+insert into t2(a,b) values ('qwuuzknieeaaeorugumjyfkjeqiracfokynqdomrrvvryywvvlqfnhwptjhrfircqgfqejrqrnllrwoievdlzuzvknpfmgkgwuqbfpiyrigtvvllrnfkukfvusnutoxawltjekjxxauamjxkr','sisyawzmjmohjurwsbptwnjbhtidctpdtmfbtidveyiojxkegoctpslxxivvdknvltoaoivsnddrocalrxjwptci')
+;
+insert into t2(a,b) values ('vbybamubwlfawmhozrjpsjawmtwqzkrrklovlxniqmznoyctqoglidtswsfkuptekko','redziueuuybgeryc')
+;
+insert into t2(a,b) values ('fflexydmmdmlibnxrc','akdzgfyxvhwlpiszdbsntughyuauvqowngzthciocnrihgwrmasrkhsvkalqfozkriuytghvusudbrcmcxgtdbjekbjddaxvtqseoqiahuqgofvohqaroizfaeuyedxgyqvugazeotjvwvmjctaicgtnhtoryzixwhgiythifmpslvkkszkwnzsxasnsypcuikyatuidemxbcvakpfrhpfqltkpgokoozkdzvbovhgdypn')
+;
+insert into t2(a,b) values ('eyxdbiiinwmlsbjqoloneddguzsnygjaevvvygpfbkmijigxvsxpdxmxdjleecyehjihaoykboielwjvrxpbbenwcsbfixompowlkyujdyyfbhxvmpohgmdnrtcvsvcbmmuhwuvpyabywrlprsulfhtvgnxwkytdtkyeueiyxfpxmetlvzgmyfivsicmneciunnsmgulxecftcsta','ltwpjcvkflbwovdnukhhbycgtasqncsgtducgagbdgzaynlpkvlucdgvximjwsjnxzropnvutdkshurkayvkprnhlkdfxltnrijlatuzyxljoljejhhjxihdkjowvqe')
+;
+insert into t2(a,b) values ('cqxeosyranzeawtraohhczoxxddwgojwiydnflffg','rlvweujljsgxpjeczwdieqsoumpdvrfbcdhqqqiwcgdfvywazlzubmggavzshnfopvkmsqgopckllpjjjhheuhplznneizddspwdxqlfrrptvghoirkepqiafgbblfckrtcsulrgdyqbujllqaenplxvrutplrvhroqxushnreebopblunpuzhnankuwsxspurprazllcktvtev')
+;
+insert into t2(a,b) values ('igcctffpxbqxmalqalodvyjmrthodbtuynnlmcwamwfhoeuvbadifvbyrqxyopjakcsfplyexokwdkfpayflqtfwbxhtmnieqysbuqycvymesmalqlkxjkvbfzxkafmtfcynyramrrkjbgvmhlposuacugqhgjvyzefawoprtdxayycdntlzackecagrggchobvcminppldbqcqzjmdunwmiosglzae','lbwnu')
+;
+insert into t2(a,b) values ('gqhxvhadreqjuimhzatujwziwgqsvhhqodrnxjuzfiahugyxzaexgpsunyteztmdqgdei','tamuguprzidgbcejeeobnxxhiagmujfupxmhrnovzbclyrtkprvovmlhuyimxkkjifspjwzmtvzkenxtkjffhmfljirslyiolhnycvtcxjhuhcxvtumkbddrdzvvmldypsyuqnkfj')
+;
+insert into t2(a,b) values ('ebgojnfswzyalqadoatevepifijejgmcphblgtukojhihakwjeoijjdtvvvbhhjinkzrbuvqddafyqgvsqzlzmhpnxjtjdvbvaheaoztvvqaecrkbiulufzircmzaxcaorebdvbfbznoagjhlaovweclstfxwjnczganliqyzlzsehpdirypqtiinbychtmwdyohgpvoqaavegant','kkpsflkzqlwdndhkipghszlxgwbueetpewlgxfdslbmokjetnblv')
+;
+insert into t2(a,b) values ('eikpqstkaniaihnatogakvyirgxfecqunltddpfteuzceynclvqxulaxocpwyfvcssliokvrvzkhnqslzetyzfowpxzewquicznrlkqirdyjrddulixxlikjnuwye','clsndzhnfugeoapcsvdvwjcocxzngstehhvzrumgupumttvutyqniroonqezgmuqerjsobfmwwstedwmrjejsinihksornzunrvv')
+;
+insert into t2(a,b) values ('bhybfxqwwpioyeeyzvnjyaflhd','rluxbekqxbssknoyzeruaadsddopxoiybrotfcelhdbvrwywrmibcqugcktqtxcpdjwsgromkgikemgufndjmbxmazfcubibfllounfkaqzighcjfaklvuodkjydjwhmbjgegxsnesahedcrcqtzensapkuuzuxyywe')
+;
+insert into t2(a,b) values ('uisgafmbesxhafwszznpnvlmqfyvoswvtlqoawznvtxribxmyzunmtbxfycitkextpwknkqbbezuoeqamhakanddvsilwevtzpghfktyayahlqnrxsjqctztkdeihkvlimsftgdeakqpyraqjjypkurogtjwqiyulfjizzojfqlycweqh','estjxlvsinlwppokaqjlrvoahunziwgfyrbpimnxvdaklsogjycikabijjivtcfnntilbrrlzxqfvnisridnndznaejbjuolcaqowwdrwuxasvfzjsulzevtzoeyddjzdmloleyhogyjbsbiuablffkfofyfbsrkojbmycaonddtqjo')
+;
+insert into t2(a,b) values ('smquvibitlocioqrreazumpzeqslcrirunacnsckfknaajipviofv','vwqagfjfcjonnbvndiekfdarvngzvzubgiaincziuygvyvuslbslbbrkexdhrfnlgsgtsaffewmcdnroeeyzaxdu')
+;
+insert into t2(a,b) values ('episyqkkujjvqgpfqdqtxqgqaabwsjzzeqqyekvvsviqxfoznyftgfnocluwfnsxdghykspvxajclixijxwukzzxgvfgpdtlbwiwwicafibylioizveregvvhdlhuwjchlxoqiasfpapvzceteinziaqewnkgkqevfxlqmrbawteobxvtsfgcuwspmwslvwitrvtwnfvxmldgshzoantuiahtwagrcpwllqu','gzsrkzgwvabvwqwtdxyxqohqtllredtmugcounzihmvtulhixkvsysynmliorepashyjpvdzolalrtgovaacootwgooexgktdndvouwftfmywjlzjtwvp')
+;
+insert into t2(a,b) values ('tpfsfycdoxcoflkbkxudomyzgwrbzxasfyqgpwersonmabjebirxddctekzelpaylyvyzwejtikepseefjemrxrbxeidshmiyvtoffksvgsneawmgwmnmnhnmcfmncgoijsiywcktwxkzthqinexmgondqvp','wfriysvdtlkclaxhyrqkpfpqdagizrphhiyvdjkoouiylefrxesvtbhhflwtatpuwhqsqjtlvbdyiqlpfsvfixfldpwlcfcfrulniumgxtapnctafufsppzzvwiqgqscucimvfzkklxthanfegrebtpwjbqmrllauqexhvigerzqlmbhexzdsvejkjepzahvfiqsndpjrtmevdhyaqozelvyjvyzsegnextburtwt')
+;
+insert into t2(a,b) values ('mfqhywovoyclrcayoawkvgurzaemsgfxcbwnvwwiq','drsvnwqjslxeffgivutaeanydkwqlxgpgvpewbbttglfokoxssskhiobrjhwgygelqfzffyjsmoxjlzfzllmflzsudqyqxkyjlxuchhvmrjjgpoxxmjxneenxzrnvnztwtnwqlbwhcfboudjazztujoclkbunoyiudvcyeuwkuqir')
+;
+insert into t2(a,b) values ('cnjmdiuaumsjqcjqwnopmdhn','gzkhghslefawpthccknuxbphilnpsgwqvwywrofptpoaacdfymqjbnvsabkptticeitzdfqxaaipzldnopaqgcsojzcylupmnhlomgyuviqevigmiplyfgyfctfjdnncebzzvdyvzyxpimvpsdifpftkqkrgairsxnzvgaspujtjrcbmlivutqvhdxzynbscpgdkzxbvkbsitsyadtotwki')
+;
+insert into t2(a,b) values ('gkuqxhuurerhvqbysxeupzivrtvzmwgblpmwztvygzij','dcynkdp')
+;
+insert into t2(a,b) values ('yrudpdxuhhmbqhqrvewleqbdchtlgtocoalaswfistthbucgpcimhqhjdsbimzgrkdyyhxjdbxomwhhxxobmvbrjpxnxsxwdoqbzlaiundpdinqnvuphastgiycqqvtzdatxgtlhwxobwgqarrsojlopczjmgnduzayikkyflsrorfy','yzkdgvnaokuaaomyjykhbubkhhqwnvpoqxbnwpxcntyhxrveiactgnbrwdutayheihzeljinoeymdbkzlycfppgjebot')
+;
+insert into t2(a,b) values ('rosgimiqxvcvlhpyxyfgnuaoilnqasqunfdrodmuiuukkbpcgvntpnzvooncenhvzarewyslkfzqjqsqbipzxmzbmrzyokoxomfhknvqcdkmquurceksikjvhkmwejeoxjennxzupvgnytzciqooaldjpieycybysstcrovrqree','tsfeyzrusqe')
+;
+insert into t2(a,b) values ('czgstlmhudsiwkgxzkckcavljtkhdklbcqfghoechhzysanynzigvctqiwjueoozixkbvdplclalevfxkyngyvkedjmkjelgalnuiqmbqajrllkl','mzilqdkyurcixkwwgkncgzaljqftceungkjvoopxfnwmpxsuuujheilwzhucddatbzvbmzamwulrordknewshyzhpjcafsudwrreqnhytunfefyzrqljjphhgqjqlcrurivlmbxmsvrdivntuyovakeousoufbviysispbdofgsulhqktoilysrvlkthjyzwymeogasvmzunneusijbodtaqiwq')
+;
+insert into t2(a,b) values ('biiyqzbzjkkslkdlrytfyzslvcelfvcatgmhcckrwqsedmlaqxibhhkdokdqsmvmwvhzhrwugiebksebqis','armbckhxjpfaiavvuowhgsswfwgirikroyyhudugbtxbexfmmkojuxuobhkiqyokquqmmxxeocedxkfrubuahtzofwuysmavtpioyvpjlarltwtcggmzxnphpfzvrrfagjvqguiwvpofuhdyzpgqjeftzeexriekytnvewphbvsfwyjtlqijspxfmlxyabxogvfnuaxjmyhtqfsepzdbn')
+;
+insert into t2(a,b) values ('iolspikxvpfstwznldklpfklunbtywmqsboxxwpnyzzwghguyjbzhislyjdvebscqhwbhzalmleyeudinsfcqtngdvtpmnbttttmbrtpryqskfweavmdrizlmhictizooeoxfyrcknitvszrxuzwijspjdg','xwgwcaqschxtetokfianjztyeoqpbrctcenqpdtzwwgsfazdchcgjojiipabyohdyfgnbyqcjaxwfhledraauofwtcbnciyvoanjajspvugytotnidizyzqhqajnbyculyuqfwzgfetnzehmqtglgypnmpyqvckflavyizwfbakfczuacourwmxcbafevdtgfxiaunacjowwmldwcorfehgbhfqnppisksudeuqhw')
+;
+insert into t2(a,b) values ('yucgnyacyoctixwxnfqovgvacezxarjqnfqjkvjtsktawirokjanevivscgwkzncdxzcyxysespveewgpyvuvdzdwvlktxxsrqdptjtwbqswrkcmdkqduzy','vjalqwulrupzchimzznhuwwcfmqrrpgvogtbgfmgumvbgawqcwfzhlprhezgctqwlwkxiqfaubmxhpuwcmgzsfyeixjfpacummpgjdlouoytfjxnschhifdcdlgciiigwuhmvtcjjtszxxvublwsvbvbywplyaehqgpunhtsepmtebsvesummmtcusztzngotlllxynmctsxivzvgprlxelwxfkakwedfpltqpnrmnnaipxqe')
+;
+insert into t2(a,b) values ('nvzqxgvwgzslxjcvdgztzysuedlvykokewlyzx','ljwikkcwiqhbhoiffxehdcrhjumdpdfhgqcokpybwavumxnsfjwktdyvjzzlcfqzqiedmnsyeiyvzj')
+;
+insert into t2(a,b) values ('whuifxjuepurpssnhbcjlkohvosueqiuarnnsrkodcvtzjrtnlkkjlsabvbouosphtqsjpmmuubyakgtoewmlxcfsxzwcwmqibwnjnuzuaiiczgqdtsfrnrumfywcxluighjiucsalrvzhvkufkonpggwtfygpjcdmfekjdinlmidsfwivsjtxgmraoarzhngqcggwepxakebldjdycptduetnbhsiili','zdzxeekcmowyzsnupwhflhgtcspivhzfezwotozudlwdxkcyomeaqjtsohfajusfpcmhzhxhuedzmcieopcbcyoiceyryeqwtxjrvxqccmlsttbbdjrtulsmjpnblipttmtoahipjseyftryppvqgdoktojcwzevhpbftiiyqebxqszjmqfkgychvgwyyvyvkbrarquicespygub')
+;
+insert into t2(a,b) values ('lxzrioojndutkqtfuqvgxteajppsmukizzjrzoehawcwnjxxtnkcxmbjhrjglgctxayvzgtdmuftksietdrfjhmlglpywbbqageutxietsjttppivmqkhwqstfkcdyetqdmkhbykqgatdlpnnvuykkboypqoaavsheamjiyxosbsrhbp','zxuhngwhjnuzcgwmxuqjbecnnipgiundibfyyzetylbjsiaphveabltfclvtewremdjetcorcgbftgrlakhbncegjfkhappgjcqallridjiyiyjemcrjlxitwvnnhgldxqgrvdhhtlumniqsdgdcgjbrz')
+;
+insert into t2(a,b) values ('ogllnhmnebjuaoeyxpdkhunggglhwzrpmuzevruhqkagenpeizcnotrycpecmfovmnuglkuipvnmnbdbnstykvwusr','r')
+;
+insert into t2(a,b) values ('cbajhcnfuzkdasoofuqpgcwfoziecaiqbttgrlxihvdomverntcqbzpuzuzzcckuykosvttaalfexigcywzdwooiyjevsbeklmlcrtbryckbrrpgdjzblqkewvtqgmnintaibczeqqzhsfvsjizqppuifaqyoijjmdwymnewdrdwsygotlxoxnpgykyoqblovgervodksvsrhxtheofqjmzajfpkqcqncmsloekuyonltnjwximoyy','mqxgtdxnvbeahchvbzkyflgdvezsprgiufhjhvoqkrkudimexzpgrobppduuyolnhgowjkxhevyxoswnehtysgiepogmtnclbkmskk')
+;
+insert into t2(a,b) values ('yqsblacfiplrlpmorcibjqbpkobhokvfrb','hglxvlltfeygbijpezetluaeaakfqnomykyrvlbdguguwvtsdjgfljhttsfydswnrkexhxcnigzvdwjykqphtpiqyrnbptyfhqvklmvvweqtrmeryglopuoiuozgvpwkmnwdxxcaobxqqltpvdjfjicxithgmyljufxhcreqnrfqjnrtfhkhhmrwesuypldgdqjidjntvyvcpvoznwejnnmjsljtujwninmtqpqvkpzookacn')
+;
+insert into t2(a,b) values ('heexmfchqqdtlsrfiqkwyeitjtgoltlcmgenfvklhtktbcvdnlgoiizundqvtdaykxzvntdpzdxoj','ydtyvwymwnyumavfpynpdccbldxpsfwwpexypfgtfosfbncdmqnpipsdjlfejwrmqlvlzcigksrlvfssqtxdtdweubenafqcsykhfhwsycqmruhldcmnnmunvcprvirzvggaiakmfbgqeuxzzbfohxqpnsumtcsxkokkxctcnainiiwzlnpausdragesbynvsywrgfxzyslpyxomotco')
+;
+insert into t2(a,b) values ('gwptnwwfwacfreipmnvuqfpcgyccueicikjtixmnmxsdvtphaufpkomcietiqbkrexucqzigqsklsebejvhqvhrrirbylqscudbvjdxlkwqskvbhvakutzfbepigzklvucyojnpakwaishgstibzmrgdyajytjoocremvqmwtotutrsmywsrwnpk','gtwydoydgakdgatephbxdpmnjzlgidypsdzhuoefquyihtlkwonfffrhyzdhehwvrounhjciynaxefgmlikjlaaxoubcfvsqcojvblfwowvvcvdzcvolyfuxraoniizoyyuacavtbuapxulzhntqxiawaxffycelxgrajytzhtrft')
+;
+insert into t2(a,b) values ('fuyvtbjooeosxkymlgmnbgulufcbyhfzubpxalmusgsuwburdjzxkvcchdeqcfwecmejutybfhmcpttbnrohyvrfwykadzcksnvdvdfehobsokneygxysstjvriswjlcjxfyhekfaxsrdxrpioucaymcaefklczjvsnomoneabkeivfdjzgi','macxhburxbtulicnzaxgmzvrsokxegsbcwodrooicxbrkuwafzlsabzxdvfdmblgdaqtqppyzppbvjrrpbavxsxui')
+;
+insert into t2(a,b) values ('oridexswhzekngzcgjzcachski','wgaaiou')
+;
+insert into t2(a,b) values ('pdioewgzcakwowlcpkrkmsonmovukbnnygfopczvwyhsstnrqwbqugjeiwqnojsrvbuapriokxsablbmsurktkeabatecoxyjffewfgyzubbzovratmubogozmacpanarcwhtmhoilwqdyslsxqmlhkicbdnhscqaatqploneepkeopakcfvagfqtbgcngvkpbytubtfydtcaldgvdzppbgywoe','evxzbwuiftkgzdkuvyblgfzvzrhydlgngwsnopcskjzdszqltpixeyrgrrkfgenwjwytfxu')
+;
+insert into t2(a,b) values ('ifopkkurvhfwmgtilrafofgcsxurxsvbxlduvsmlnoeabmifirqvkxcyarbqnyeguckysvyjfkusutzqtwahiavsqgoiqahqipqdlqclfuldnmnpiyughvnxcmyxqhfbkhtajgtzacvffcufomdkeehgiccvkrcyfirtnidcmzmkylkotvxbraakkyfysa','ixgtiptwxignxasmghatzyfuayhnlkufyytwjsdrflaxphlotvoehktmgevwuashutslomuqyoqqahrogclvstuqefujobgcfrjqirxsywudqgfurwmejrlogbofyxmskpykwnekjuhivrouhkjmhjlhq')
+;
+insert into t2(a,b) values ('vyhqlbrosdybaxddpvxuymsprqamaioocpluxtaxnpzzfmkzdkcrfryukkmomjlogqbkoewojzgxnhadhtzyvozrabdtmnhhuzzcjfsmmxhhjlcegkoltzauerrzorejdcfrojpyrppulpwkbplwmhqbawrfowqukfmcfdpoismszdtipmjjkznfwigbqywpgyeasdgtmushlagftrjyqvyspoqusfvjmisxj','ikbnvwiffikvshwpbmgzqulnslszfoleuinlchljamaerrtbfhfswldtyykeqxzwmuttkiuixrfalavhbcxmjejskbaopkhljohauejuztkprpvktppxuemiomzlbklzuympzaaxkiilpdjcfgs')
+;
+insert into t2(a,b) values ('jdeeuikdoculflmoagemjhfqbbakopyrjkghktskzysgorcuwppmshvxdlkrdwpaivbtxjfxaumypzuyjijxfxjdtcxvebdgwspvidkukimztltkbymphurafwhawpeotvygbkbvlaqhrdibvgclgwensbjwcjfmzvpyeqovqvjweozmjbotrxhtgrleurt','nmxtnluotswihmwcjahngrybmjhhyzsyghnvzptlqrwyvvfpidjqmmohmjuhqhsuubwyullssouewtnbnmgaaoxirbviwopckyaosopyeprlcklcecbnhidecwtgedfsaravgmkabzvqvltloxnhlfdeefgvsvddekvyqnaijfwfvptxzhzwcorbikcolwiytzlqlmuhkfqgetgwvuhvliwzaquplvykekuuchsszeqkbubhzglviafxxfbsjd')
+;
+insert into t2(a,b) values ('mhlgfjuojlvlgnbmcpjplkyuulpbdatpamkmshojchigbjuktbussbjclwujntmteuhuikgudgckqctmkaoiftfcouws','qfcttroailudszpnxhnbhoahirhioqcxlufpamsornksgtjvcqlfdfcmdrozxhfwtupqhgocalpkplu')
+;
+insert into t2(a,b) values ('jfuwhttfpqklsmffliccgybyojjmuzebngglzdxzrqtemgssxiseofrmxuxqidqtzvruyawernlsvhsbnabfbkoawnpglirrpwkxohalkztgievtcqwbaueamhkkcxzdrawfefddopviisyofzlagrltbyvezkxjwcloxbwuzijeycvysqxgxgfxxhfzbmsnugln','yxgjjoemivwcpuhqvmlwntgrhzcobdplvomlhyrjizdivyxqiaewwoxfdchbomcdrridgpgdblvvusiwiaxln')
+;
+insert into t2(a,b) values ('tpfwrfvqfiymlmlpupstgfnsocaqmzfzoweynybquaqce','olpwibippvsktdlirgppmnzfjhnijqupwjpqyot')
+;
+insert into t2(a,b) values ('yihctkksivctsmnhirbrbogxrhzvhfosudcmdbwymgpblacmajqnzqmxrjviztplqxhmrqrdozeklibdyycvexdbueaegigfykadhmxfrszklvnrfrjkmxnvfhhbuypmnjhnlczscc','vbwwqkuivjgpegtphwmmpetagxbtvmyfkeyedoqssyafuyfzequzuccpgxdnmtuvmclhjzmafdigrwsaqxeepmgwdjcdefqxruyupnkayoibxitamgjnhlwqekiyznabywpvmbxnibntewqkksisarcsofmjaxsrowtpqdadguvhfsx')
+;
+insert into t2(a,b) values ('vjckqoclouqwxqn','jkkmsbzbxlaqviqyencfrhygpeypuichsoeiwvoopauujuhwyquuzdpuhsp')
+;
+insert into t2(a,b) values ('mpejokotkyzlxpkuaidxxuzykwhngmnmapembsrqb','sgkceqyvosmcyjeaydsqxacnwdnxnivtvjhhxbaxmidipawcjmooumyirwfgjxzznkmhbkttdzxrfmbsyrrlyhyfjqucvndmobmhxycrrkxttyqogjahqlfduvolamxdzqkzufnazbzgliqnferqrhvqjpwqbcmrklatkuafohxiyhmzyeoasrlrfalnpyvfxmctkkwxpqfdzishtiypjrnxmqwrpfkkynbrdvonvkuyrnxrkrdljnidlfpg')
+;
+insert into t2(a,b) values ('nluwfnkexaatvokxbtsilfdnxjnxihuajzictlwwdijcfzlwsr','tkuvnvwybyelbbozbvsvdhnbrxatfgaeeccjacyeanarrelpmkhrxixgsacepaziewmldrgesvctmuershgezclgfemhdklydzwzvepgniqbtrgorrrsmgfspidqmeqglhzjlverpabreglblybldiyxujfqxrxfmgwlxehrfefuczgbatjhjevvbvhcxivuzpuduodrzsciuvgxdyqlusolvcsoxxyqybrnhbdqjxlsxiwjy')
+;
+insert into t2(a,b) values ('xhoojehiiuvhvqucfyuwgaqunkrosldbczpzfzmgreliwfokfadwiy','rzwhjpehhwhmxqpnpjpoggmbvdflipyzmvritaabbflqz')
+;
+insert into t2(a,b) values ('asujzjmundvulvlsraibrdtcgrtyngkmldontaobzxmxakthhshjnknrpfnuthbduxxhxpxupgteqhfpnysyrvjcuujeqqkkslxdzgtsujcbjfoxegmojnvxrfipamsbdsjhrwnmrqtmmgoffcnfluezxv','iwybasdkwqqbczpqoycveqydeentghuvjwzekkzftivzmietjhykciburukzhztbxckzmyrvsvtavwhyocdzummooyfsctwkyottolvsrsbsessqbpuoywfhzhvhocstokbx')
+;
+insert into t2(a,b) values ('','bigsgjiaojmkkqytsdajskdepbevbgbqkuyyhamwzxkkyxzcgwogmustnyosfnepyhkg')
+;
+insert into t2(a,b) values ('tayhizqujtqwnzeogygsalghgmkexdzekqnepiqgyufpuyldmpxaipvdtwnrbrxhudcanlhuaqczyipqcvzjebdopswedbjwtrnjmzjowkveekbgltklhdpdtirfzuqczik','aauvitagmfjhwhxrgmxvvnaruwfuzotixtbzxecxmltmax')
+;
+insert into t2(a,b) values ('vjqkmqsprqmhliabcstnyiczucjig','tfscjpmkhcrgdauxlzdcqcfiwezdsnvdashmuyoy')
+;
+insert into t2(a,b) values ('qhhlgrqsvelvqdnhhvyypbghrtuvlkpwungntiqryukbasetndssctqvaggepahkmcwvrmavthoihrucyzgueazsmprjjczetlaujixwcrzjwxfyfkdotpobpptifwbsjomrjqehsafbrpizpwzzbb','walsrkqtqyoervjnkedxwgxxwrglfgwrwdvvkvmfezthddqreeoqtnjxluccsyncbripurzkjkoelydyhtqtbdksujrykcixjiwcqcvflrtrkornxgruhfbxphblkbrneznduzvnxompslycqjbjknnrcdyfbvgguyzhzzxpvdfnsthioqtofiaberpm')
+;
+insert into t2(a,b) values ('ljspnvdyujwciukisvjthgugagrxxbmksfyychcaeykmchvbevxrdnqjaxqdyaqlfdivvzmxqzvcczgxkhaepxznffankvilslwrvgormthhqieswgeucslgzwfdxiqbtkigaoefwkfyzobmywxztygdgpocbreldrxprfshclpxngjxdgzubzeuwnonzw','fpzzihdgghvyneuvjefxnkypnvveischzqpeclpvzjbqzxabtdmudibwkfmkboyjcyozqwdyij')
+;
+insert into t2(a,b) values ('laxmlvviybyuwohqkgzlqaadvqnzvutywxhkzmtzxxckitganauoywrgobyzusypdxaurvnuqermabmgekssjdswf','dsxvsgrvtjndqtiymde')
+;
+insert into t2(a,b) values ('qzdntwnqcjpplclsenzivxwadeypsurygabxaukcddrua','gvfczqmfwjuomfwuyvmizrltcwymjdpobnlnajhffbwyiazhxrkvoowqnyhqnyzgltrqoqqhptdlkvdmtkarqfsiibekdkecrieclozhnpodmssmunevnhnbgyqcfacmzttaunwzosqafvpcgvhriobyrwpabsgrlrzdbvjpelvygfwhgapdgykxdisqzaqreobgasutlfpezigq')
+;
+insert into t2(a,b) values ('ernjxwbgqwemiubsjkcqbacbfwgzckqdounuuowtblipavnynzuecajqtklvfzttbgicipjgamtqdloyrijqnrorxmnwecnmwzwjqjqrmybkncyykvmofzutbsesnlkvcgbepppephnhlnbzvnenjnfoeqtoleezrokhhzaanagbluhdsyefmdlozdcmpen','bxmyrlirkmkightbqfjlkqqzvlycuqxoplnuxrxkpcxufoficuttwwpqipmvnwvlgpafdruvbzfzaonfxtjcbgwbqxwltyatfynlyrdrmovjrhvpotgftzyuoidlwqkcbxzwfhconsh')
+;
+insert into t2(a,b) values ('txgmqqjgcfsfadanxmqzfcmfwmhbwgawyfaqjz','ubbnotryfmjiubvkjphljtomthokmsrpvtacarkljbtbnbllclcjzgezryowlpyktuvgtidvdvmqkrxgmrcqmobnpon')
+;
+insert into t2(a,b) values ('triwrwfnukpqdyhweelqjwwdnkerlkrxawrvmxqfuhsrdqmvdpdlgbwvrglmxoexawjsmgpjkbtdrjgmxqzeydydgnascnkmyiodfowalhmtbvmfyooyyjeeayuhlhhkmltrqxnjnhbqsreaglzhyvnhwuneponaruflhdhyjufqitehnpwcasnikszulstyzblizqtuvffaskjfrjymjtdftfljgxdsoxzedspebpkyvevjsirnxi','kzcoosauzbckrhymyfqzhzezpxyesdjolbdkmdpadde')
+;
+insert into t2(a,b) values ('rglavszelmsulaivlworwvjrhjnfbojkfkalhjdpzirtolqugmkcnuovldvcaajchymonqgvgrlkfulvizezj','swvkcjembrjppm')
+;
+insert into t2(a,b) values ('fjsxserpaygpdzepdlabtjhvekncvqqpscuowjjrgbegxzqsgoyxhzzewlyhlnkuizouxhbyhwyjsqxfokeweokibulgagwnpdqkcscgbccsrnkbsxarxyaesdtuorzhavtawxvuiighrisdlijasoidpnagkglwskoyeuzxqnsgppqlrjebrlhrtegikfcgcrzxudkfkbeiyyogbnmdfteibzuiykavhmojyktibjpmzhxhml','knhzucscvwazvwbvsyrztmpkbrnaevaoojmrjnurexbxswsoagoyuphikbxhubnxlrigkljvekehnywgyrzbgrxnibkzadhuuelnnjvsabllcxwxrieobgsrqbiynfzgqzqqkxwfjcipymjafw')
+;
+insert into t2(a,b) values ('mijwcjcfitiyalnjscqzzwgucdzfxiklzscfiobmaxiwiqvkpxavcaggpoisbctpgqmmauxbtuowckuqizpbuwnxdwflmflrkybtnhreeumqzaveqreyfjsdneczjeprjtdunexasifcnsgiyytbnfwqxxpxgzpgctpjzprwczrlmeqmmhfcyrcveiuxvgr','uhkbkiqxvpipfjeemajurmpondnlvhffryumgurqenmmkpdy')
+;
+insert into t2(a,b) values ('osikgjejiyydxppyvdbyhrkjrrfycgkoknjlrcmgdmiircqzyywyayrgqaumsblyxppbblymfzvuezivgdhuzgjopibrbsiquttmseclnnwdmmdjyclqypdklorp','vygywdtdrpbfmpdpfebavlpctmdenefzyqbrqsqxoauaqnqqvsnsfyjoyzuolhmezeizanlkfklctpxtfjoibesbfbnaghttwinkfrrllkytczkv')
+;
+insert into t2(a,b) values ('wykleeobwrrblqtkuucsxkfjprfsscwvgqyrfjsgfkjaayanxdealzrmmfibepsfwolrhrzxnfbsbnoorgpkmvnkyepjsaevsyhcobsyeshrzjaxqsajujyvlyhfierkgzkjtjtkohqwznik','gzsznhpwuevvptahjtxviswnvhzfncjfoyzxjapaqlxhujsjrhtlftirlfsenwpkbbhssyapzgghbtxmmlelvvmlfslzrfsgjiihgprribyihlxrzolmyeadfvgmcrqsmxdxvufqyxtraajayhlfhzktwlwtyubevkdzypkwfwzvxvssuemjsdrarzylukynrgnfrqgpkcgljcshdtftsfxyitlamz')
+;
+insert into t2(a,b) values ('tejfnjtmsnigcbuuccjcbaejgcqdsgedwmlswzzvyaqoozjrjzuiifddasqvqdeqjwydgadqymlmilzmmqffwpijfeobjflvijlssifzbdncswhczekzysulfvkndtsnvbtbcvwfznkybzyaekdrefvifvlxwawvftiyzyrrrvlwseptqergmtthnipvhvyjanoxgwmcwiabsnygdidsnuyhrtsyuihkqzloplwqvajqytvyvjptfqgdliprux','tofytexrwgnegiyphmsfkzjxbosrxdyexegzsjcxywwrtsgydkskrmzfstsjdprlwb')
+;
+insert into t2(a,b) values ('wrcrxvbldpcymahbuccfkzhckveruvtovrmxmiovombihupezmajsluumajmgzbwrpsoillcjsafqlnxkptvpvlxpxvmtxplsgsjunkinzwgntjweteojjyhzesutcxbqzbgszgzlfdwzwbphrwfmw','wdnalxejnmmvqnxfilixtfzjr')
+;
+insert into t2(a,b) values ('qsdukzkxhooijrzqrhdclkqdnhdfnjjmtkbyyrgfnlbragmbhayrisjsjelomyrzriwcpixtjnwxzavncshztghfjdasgjtkogdlhgbetddiigipbxnnkhsksttzarziciwnvbntyfrkliwmpgdvlskymrxeiuzdc','ncvumtuyyslaiqkhpllicohpagbqvpmgrxrhgbeuxcmajdofjvcdohblssgkeuwtjsdfagcqysbbooubciykthtfsxoufbdnfruwknwqqxabytwlkhdslpjpfxpxellodp')
+;
+insert into t2(a,b) values ('wbamnpipzfaayyesaomlzhqgdshrqbxshywushldmypvepzfgzjouglhlzzakmcyjhvuyydnfxevrvinhdbhmeiiahjvfqmkifddkbdjpcoppflgfilgamtbaiqymsloqeidfdrajnxuiybou','prawgheagipegjfmxtnjenwuvsybthrcrbbnfuqgpaqghkzwqkdyntiwauaqxzj')
+;
+insert into t2(a,b) values ('clehwcmosclfqwnwbaahvkjaegesmhddlfafnaqwuuwrjqvbuwlebcnbziwafmlubmiiwhlkgntqhrzyoohlmoubyqetraybmlmqxnmgvirmuti','vhkhqzpxxwbdeevjlgnwchbjyrqzgyyiaqgqxnzajqeaetovkmfbywegwhvoonignxzggpofjwddxndsirxqtnzvhepincvdzgkatzezkhfuiulduqrjylrcpuwtjvfyfyubxbxtrttfrwhyxowypbzgbyqxhcthxftqqdztaqjgcnmxhkoawnquiswxebgpekefwcjmcdebowfomzfgluhy')
+;
+insert into t2(a,b) values ('axlombmbbnzqqpqwawjokfsvwnonvucszhfiqdquzrvgbihqtspouwbodgayaunghnmgtrhnieamoffcmvycglxocvwhgkcwerytkzbtyoflzhpeekenqwexguvglsjaflupxdgwvmgtuynnyzwpoussbrqqvmfblmhwkrwnibckxcrdsgbsmmnsubhcksblrblzfhjmxrgdwstorsifohhdaoponvacepploryjl','rkdrckhwencodzqwmxctrswaruhlgmbaugcjlnhfssvsnhkipckvonxvtzfggwsgfpqnyemwvscuahtvkmswofdgneyyrwkfqhljhgehdnnzmrbbrhqqeuqpecwrouxqhhqojtxuzeyjiystuibshchjaizeywiguntquvldtuoyyvvzufwoiqygskcpefqwb')
+;
+insert into t2(a,b) values ('cisldxwspmubswqwrvjghaqtkqukfgvvfllwttfggmlnvjxailnpfiqhusbdnbkkagfudrzkovaywqcuxyaqojygfewr','tneooxekabdnnjgcgzwsamdabvbpymuecvywapkdsmdtwlwciwhzxnxkvyvlxhpyxdxpxilatszcvivdbdyrbjpfyqqcbwffzitmutarefdjvwtlcprubbckwgdrnwfqpiwxwubofzrsbyffximdxwhcdcvkvdksphgaxpfyhczaibmougxvpoyjqxtmpiiwzlfboyxyix')
+;
+insert into t2(a,b) values ('wjqonbxxludamkjdvoqoflhtuhdzitgksvxqjzsbhkhsbfnmqxeplxxxkfksboqwoydjlsgtctphdwjsnnuxlipjrmetmlalfhwtlluylunshjmhazxmqaqerdhykqcqyqcybfhuosndfwnpvntareuhmynufijjnzuznsoahwfwltppqubwuaeqfzysfmhzdtenbvujhfddagf','uqpsfgomopxduoesmcvyeqfnubebyjdgsqazxswxplcbviepxqswozfwcnxujcwmchhtiueknkqscqcefvufcsjdorbtkvhzrzzowmuvy')
+;
+insert into t2(a,b) values ('fztaicwgjhhefmgitpsyroqzgknpnwnznqtwieessiepsjazxkycubnuppyaqqudfqdbvqmcfxljnegpjrnhtbivhechsmtwzfgfdasrrmboralmnxxaxchktejgnfaudmofljluakjwwnphhhkj','ddruuceetsjtlzbftlvvduqavhyehrurfmbymnzgqrcwibcaqrgdaxbgxottielracxbpxlhnwlubnrvueyfftuzszptjdomxvggpmadlqwoepwuykqctyfpokuxxjzkbfkbrei')
+;
+insert into t2(a,b) values ('czuhlcbuhifwktnhplaqpgitq','cgcsuicefofrprggtvktavfmpcxbruvtqgkeqocmwvpttolglrcbpjycblroeswlycecryzcwfbipdxexdesqigbnovejmueyxbrlogplfwrrdpwjylhotozbmvncrtfwzvdiarkfyprsomcjsutmuezofmhdfqntobvwfqfbrpezisvryyaufsluewzwdxmqynozyjjwfilojmc')
+;
+insert into t2(a,b) values ('vvtzwtkweqcdcviuugvczuayvezfaclbenpqtnekbjaaamxbayfrnwnpwaxewaucikzipcxaqixrhcqwnqbqgvshmjedixpdm','wpedfrtyoakbtpecpmqhorycrsvjjmjrmrhogsvtpsimqxzlnwplpvwwnlygpzxfskxbggiklqmnirqlqhgkyhzgppbnxbbosejmjawulfogwfhyltqquwnxedirrrqazyfbpajrqtxidzbwtetvntsusleuqkkidxcgybsenwippztpnmtlheutvauaefuutvuigoyipivzpcxasttdes')
+;
+insert into t2(a,b) values ('iqjblvehlyhjawyriwvorvbgecvkeyehagnhfefxfqraifmmwsgktmsgrdxcnhwceeizfdxmircsndtcnmw','rwjudlqkqvkicpjcuhirvmukixgypcoqvmdwmokaacmkpizmzjhwvpgxhkhwfxnfkdooeicrfmnsetbhrheesbjcwcuxervjbvhcjzyszxagksqpyddqoqbcnhfekwmctodjdnrthxnrpucmvzayjxslpuhuaxraotiiaxoksdivizrwpwptgefnashzlvzxhwjyzvftiaapxbcnetvzfrgcjdoylmsrbiywqzsimeqwferrgoyt')
+;
+insert into t2(a,b) values ('slcjnbnflhucchieafpgyfulgxvoxasuocftmmqgkqgzdpauxtnslycucjidieqohlogblhaejzuzgeiitwvkrconiryhdotvzeidbbqbfsrzaursfvzxmremwiuxobrhxrznnmjijmimasejpgytebsjgobuyqtqzrfmd','hnxqzrzwiqtutlizxhxmhgouocbrkxlyfpdymjakvuellohnkgdaelwlzcusolcvjhzgfxymzrqbdukrqtryexjazgynzcsbhfyvvufsejzvtednkgkpfefcvyrsitcojlmwkjvkhogaohzbwpfdwaaonuubfassucgzdqaipcavfiysqweouuoureknlqfpnlwzhyuuynlpwsdvmuwlpgaewgijzbpbjqmfpzc')
+;
+insert into t2(a,b) values ('dmokhttqwqzuqkksoditvxmdlsmxwuodqlubffodncvtfclzdprjtmciurgufnotfxvrvhqlbihyoiivggfqutcoawjiengu','obaszoiqhgfmwyaetllqlqmglukwypmiyutgvsdrtjfwctuvn')
+;
+insert into t2(a,b) values ('vzmwvilpfvbyhnnhupupolywusfxgkrszfjisuwcohxkfuwbtbbclardekpqdrsnupwshttzfyqfhcjglw','xcijonrvvmulvwqqjwlvxelvjniexfaklgmpnccgogsgqvrwfsamtusjjpdxthlxvoojhbxzwmhlnnnjjavnzdgstup')
+;
+insert into t2(a,b) values ('ntgujrywsgxqmqybgkqofpolcpvqswekwryljvcxmsgkitqihbufhthumfuqejrmsenpcekcirbnfvtukjoerfaikxnmodzujqhmylfsfjowludmapgzpvsahqcqnzb','iylxbbwsoanbgwkhjpkgfkxaqfuado')
+;
+insert into t2(a,b) values ('idvysthpvaeehlgjbtsmduzlejxbrxhhpqinzuqsuqdfccpymluwbhkfayoyhhovygosdvcvybzgppdpukrqnscskdizftbvmtjgzioshhtoawjwtkqbvduiedllycltpryvuqxlpezrdglftrmodaajyfoplixvddjawosqhmuqbmaqdyxehergvqlossqhplaiwkiwf','roqczcojcdltffsvqpfhwoiavamyepolfntdwvqfhdnnqyjdlfnmbwoxdwukueazfballroljbnsusislzhcxwzyinwjalmeyvrotnqwejwxigcffqjrgsatzysxjnljuoerhfxfzsqsbmtbvlkivygrslejt')
+;
+insert into t2(a,b) values ('xbywtqrwwddzetnoptlacxoukkauxxbgcgoelbfojqgdluaqsxfzemjrpkxgnteoakxqkoqcxcdcnwwbspcnjguectsbsqdpsjjkabyddpiujhxhajqwjcmaihrtsbopjomcdhublljlxliilytcypdfkimtxxbsplscdwoqamuuniebwmeqcpve','upvhuabsygjkxnewjizewokzxhybzsddftxoddgbstpxuqmldqoqflvwrxkltpfbvmqlnyywukrfwoahbxegdbxxdihlhkvosmpprgdlgjtthqvhzifsxgogtadfvgnmtsqaqqqtdvvaoaepuneifddiuzborkwtavagakxbthcsgvoyto')
+;
+insert into t2(a,b) values ('dsxjnpacodgfyxcgvmnfcmfjydylnksinyhhwicojeuxsviyzqlsejscpohlzhkmpelufnpemnrz','slfaseblembjuaezzpwkuvwcunndnbauwxyjdvdgjhsggejowrthgctipuooifkyfhsawafsezjvmqqdcjtlbkpzygxpzxfedssxmnhjnjbjedzyiklbgpjfygsnmqggajtqrfgvjioaojxlfnhpszhunpyccmerjxxilsbmtqxybdeyrydblcgfwufelglpnwwynoiqwyvjfnzvrkhaekhvsobvbfepwbrkdhkqga')
+;
+insert into t2(a,b) values ('uhsouecrsuoidhule','imtqpocnmhphxkohoqyshmvglubskfqlquvmrzyyninuqhbsfpizdyejmqgslefuuyykeivplxeysyswuefkhecqomrbsgzirjsvgtpjgnhliyjxnwmetywfwzbrmmunscobzkxonyrcyjdxtvsgc')
+;
+insert into t2(a,b) values ('askztplkxhhbgxspuqroaphrgijibfexsqfatbojmudoasrmqyhyervitqlyvwuugdjkugvciomkdqjaqppexktfmytvnvwmtnysymvzqxxqkkfhrydurevbqmlswrdthxctpdvyoheneahffnzgrlmnauztdpgzibjwepmsopliugwyyi','xvbydqicfpxjbzfrmhdwgbnesyeivyvlyrjiiscavodiragrscbisyedwkjchoglyudjpfgyuwfsjsbiqunvrglxnhrututbjocwsyteshbmgvwpisklimqnjbzyvwvjfgyqitlzpvmzlb')
+;
+insert into t2(a,b) values ('hwvfiavnmufgbulapzrolonwxufheqymvjncnczlzcjokzqlsvmomcjzgzwzquyxpunxdmotdczocwliaprpubwaeccsulvittgizcutxxb','ztphigaaorgrbasqqrpwtxfkukjbbeufcwsuxftrkfffyyroymiccfjsvpaaczpducmcjdnbyurblsnbtcnwqmrplktbbdoxiahfgjfovoodtbjoyckqgapwfeieremdsuimzxhlydzzpbkpjboulyyiwguxkielgqvipsfpsaezkmxwgrwfdbuhlvhainsotdw')
+;
+insert into t2(a,b) values ('pclghtomjeydtygwihwblpkizquiizsfthajpbpbcnoijdmfrazmqitpzqqebqjbidcrtgwksfnwlluglgsidlivknwjimjkbvsehejkpjcrgxmmxcmduaxowejclyucfijksilnvmxwwnbiuunqpmlqtigpbfpswveusqplyofjjgbriisqetprysmjfyqjaimyhavlk','yvvekqhjhmrpwviauwaoblbfzftkxfzgtoyzkagpucfhpxjdlnarzcqlcwojmriiaawemayainalnobixptpeoipblnkczvtycwhcmpxzxljfniusnmmdalqgoxbqncrwmtfgzbsxxeajmdlxfhxxyznctilpxulrdqsmvyiawigffwgfdlivkaaiqcszqvelkschsxu')
+;
+insert into t2(a,b) values ('xzxsiowpghlsuoxjdzrppxexnzeclipvndvqbbnfqfazlgvcvvigzgtffiuxlsmntlnbfpvlgjlcmfxgedvitmuhuwmuthpejkldvxybgupwbvdydbffnlqzqgbbubbjmrcphkalxlqko','echplsptvvldzqrtucovjkbaujiddsehbhbzrskdxrikhkqndrpnizezluptkhbprwtsgqwadwyagfimgfvdzkfpyyiryifhiargzdlqzferbsslleiowvilngedivuskvzfggcmbeerkqzmcidgsqdhkalfbrtmpzasjpeurhzaytmagtmlemjfdwdvsdvdkxmvzokpnpudpepxrbvb')
+;
+insert into t2(a,b) values ('pddfrowvlezpixqgshttygobmrhnpzmdolvtcosiffndolholstznztdodmpharpxvbzcsxsbruibgsqjxfhnswsozjebipzenpviwleouqklkoprepnfjlbitmmpfeseslsmxjjmijvidurlkgvbnrmshtcwozzticukffylcfjuvxefmysxbjnacderixxbyqelzevcgvqgzdlxq','gmcoiysiwiihjwidekitwiwiyosrrbdlwncrqdxywlhzpurtxlsxtthlqgtqnswvvokxpwvvkiaecohtdpjofyymyvojtliffvdbgnwnctkzyxkgajzgtdxdowxrpsdmllcitpnmudkf')
+;
+insert into t2(a,b) values ('vaxvoapsntuhsgwldgnwvtbckcetewpuqpzsyilzmbmmfyskvqkruvliltmymmakdvqgrhrlskphyqyqtwpsnlctihtn','acgysnnewvqrqvhckdalscvgbjmcujfegiypgrnwmqtijuykimconbvwtljlbujugrwlocktaugkfcuyqwmpvtdtmcybplqyefkwynavgtmhhgpnuzgacfnoairiyptamasqoxwnezexnswosctfroikwjogpninorjblctduckmovoiesfajotebseqzrnfuthrxsrbcekpokjcoyorvvfjtztcaleefwna')
+;
+insert into t2(a,b) values ('shigeurszaxnywksfjxxpssmebdbyukyindzunwrgnttbvawqtpbtfluxeyipnqerxqqrmqivkgenjnppftkebdzvasimmxyynoezxdertsldfxqhszurdkbnxqaouzbbgeblldezmmhbtgveimvpiqdmnvronlbazjjsobzctviomdkoiyzwfhlmyghgpyofgspaspouyomdmqlkqlkakuhhlhabfcksuzuuqiqxoue','ulonlgvvkhdlrsxwdqeocshaliqebjxjkyeqedqstuodkncrchmxqrsixwohyyjoaullkysonvpqhyxfwjvqxbusysadyphxiuslrpxbjkhfuufpqtgivbxmthetncdiwdtlvubndcbfbyebejcjmiymphjnpczdzhdkecfmojxaiyovfdba')
+;
+insert into t2(a,b) values ('kim','nfowpxhrrgidfeyyfvpaomeiebaxnojnapqyzvfquzjyhnznmrujslseyalhpqgawlilznavxrzkndgozhbxplqtjmdlrxvbwofhogcazamrkukianuliemxmfbcjbmadyyvebmaesyqyybthaoarpmbatzlzacll')
+;
+insert into t2(a,b) values ('nvoutdehlfkhgvziyrazhxrfudzmlrpchyjesmgjxawpalqsu','unifkwfynwapjgzjpucyuohprlhoankkurgtlpxnjbeyhmumofifyxahdhdgadzrfreicwfqvjbrvvticffsoksgokxpitvmesixqfthxwfcczuxddwraayfsktggdvjvgdjkcdqyrtqhrfrtmhbvxpfocgz')
+;
+insert into t2(a,b) values ('nunqunryuobibhavdzqxretqdsgprmdjpzzrquhjicggbbzrskazkdplhj','dpnzhcljupiixa')
+;
+insert into t2(a,b) values ('rzlhductaskvmhqepnvdaufssppwsbxxdxbgcggdmarjrzljdwmq','qzrhwwmzklk')
+;
+insert into t2(a,b) values ('pcjqwfxkiejpytftdtzqqccksaybicgqlcpivzmqzzokejbszsmotqcudrtezysuuzujjgftmhovbn','oxseqjdeskhoyntcmiuiteaddtljzgwvfeuijjmsaspdtzjgxwllqoaoscftlvreznkuuydapbzwzzjqpsinahmibiazdjxmkccwagtexinhmstrmsvqpeevknszqugnaklardezvsmpkjlyqxhipzdjmpqjlqcazciqcyehdsmrqawafqnwujedjwgwexitjycqeujbtqljmcyqbwodxcppletcafezjepooqboddwmculwvgsl')
+;
+insert into t2(a,b) values ('xmkssvirlcfqpzzdlqmdpgvppiiy','ijlxrmptwvqnwccgqnfmgykdtprhhqlvkdfvtnqkmdoxpyawgafebxclfewutferxmbfnfqlqosywbvfacakazwzelrgookdovczqbqyenhbepzfrkieqnipcdfjhknfjcfjppobslxtyjjaycrtitekhkqxzzhvzgmsragocfsfczsbtkpyhmyyprtmcbqaajfjovjceyxmmnnqltvpwpprphdupiuiffxfgapehhfcptnv')
+;
+insert into t2(a,b) values ('pygclsmetfjsyojstkaca','tnikkouitgbygxneroqrgdhrtnqeenzsilctlxacdnpwxgemurjkeipmqobjcxodssfxhnonvrskcwpkkazrbqjgxezskwqpigzkhywbxpegupogyxd')
+;
+insert into t2(a,b) values ('kpuaeuopjlkavpynpscwgoawkznqpjakbukchsbfkyvwhrqiedquyaepnujggxzvdalpydgdzmdxvgukojzgpmbwqnkdqivolbfbmulxbrtddgtmvaukrfcleoqebossaossgwnpwntdmepmizlhrajfbxxvzaizevynmedoqskixyaasotnsyqkdaiwubxvzrnmzsmmrdrowujmvgnmqynwxyllvmolfgaiefzcyihlabmdv','cgzlvrydsgtnwmynmrzyknajcjnbxclozdqglcrerkcnwggbarfmavnxvctkyriyedibvpsalitzvnjeigvfeqcapjliujavohgldicqpllvsnvkngpzsvcpsopcnuybdukgxov')
+;
+insert into t2(a,b) values ('iuyywxfbiauvhmddodvtwpkpyjabkxboclnkkidvokmqcpsyvmeelnwghaosjjqewtexfdycxdgtmpkdgyavjwgoacembtcdbnpcuiifudvynyxkdjqdpeaopedvedromnjbpqhxmolrhzoygetvnxmlvmmgoincdixyahpmojhoyctzypycdlrevosrsqwkqnamamidooosmbtfqymcsqtgtdwidxhocmgdxvzvwbrhiksvfju','iwuqlolodwwrltakcztvwarupguwedbfiqkwnomycvqfspnsvvyacvzifsezevrutygxsjncrxhsjbbkfzgipajqjstzzvsstxvmdtnjtipmttocdizsydlcggqfnosjjxzcipeslljqmszydmxmattupfqmywmzuqqszhqfstxqqamqbwqbmxvwocmlixsclnoxxlwgnpvjrfhmscuvqtcxihp')
+;
+insert into t2(a,b) values ('bqvfacaoijwzbayjevdbuovuvfrhtvasgntzfjythigenbrvdzbdfkpivzssvanfmbdgjkyisrwtqhbevzxynuwklyxydhlrpnxwlaysrerejeewexrryeomdmkmojmirbbpdwvwjsezzwkzseeqhrhipzwgetevetretazpqxkj','gbbsfgczuhcnmswvofbuyxmdgdadkaiuorfgphlwvrgqugrhgwnddlmrutgqghpsbnuaxlyauewascdhlsc')
+;
+insert into t2(a,b) values ('zbaiiovrgrwunrddyyicgvwlkhlgxoypvrsqgejxjwnbxawcqqulhnxoespfieemgackyyzmsympcdaobqylxwihgvhawg','hvhfiqmqprhwbbzeygsvhdtdwdtqsvuezouszaxxgiewiqscnixzhucjmjfjzrz')
+;
+insert into t2(a,b) values ('ilsfakzbowggogzlzyornyymmsvlgkxyhgrkdparclmzbruwrzmwghvtnnmgfglcsdmhmbljjpdyeluctufhkrzjovpdqoruybklychxtseqmgzzcdstprieztpwftvnuasqiuskxjmuklrstlkqsdeobtymnvzncscedcazxddydmffmjvjlumxshyewtqcvamuuqeyhzsakdnbvyidxnywxv','wwifjckzlzqzpmgogkyfuwguqeidkprtgzvlbapwlbcbatmpxuoeoafvfngamoieazenmricvijjxgkiakhpgodlcigbfombjsagdmgpfgskoczmydclwaswijpknqxhv')
+;
+insert into t2(a,b) values ('ayoivvtxfnrjhqlsobliezrybxnkeozsiuwoyhhhafjuczsbzoppwsgfmbxvaavtlxqupfggluxwphepijutjbctnssnamozhlimkwaufowqodfmxlxrqbsmpavhznbxwjnfeuaxglingkidveirvzdovhyovkdrxnqqxoiwzpylepxry','swqkrkqrbynhxdvtnzgkrbojhvgwmvbdzrxpaheiosvtdtivukqblrjfwrssmoiqkwuhomrbqhwdehxkvjeqyeguriydmafcwgufggyactwqutcqgudehkrcnsddgqtfmyzucfqtojzfhtdgogjpihnzyeujkogycoqzfwweacydloouvmbwlcynxnebmcknxpevgjqtayvlllgnbuwxxyqoobvtxbafvrvdqmso')
+;
+insert into t2(a,b) values ('gtdhkcyjhtobxtufsjcheqxmghuhtvcexzfsvzksbftjxdijitizqwpbjnlaqofrptqbzeojaxaqekjgqbjbhjkfrvpuvkfybezbbmsswnikkgjcwlppmpjyllznqqiiwqkilluhrevmdovoxqgjjcqbnukgjefqjybambzjctpirxsbnutrfjpnqkxfkbjujwhmedaytorizwidkrsokrhkorsuaxkzaakokvromkbsyyztnytupiqtixt','mscauuqzhgjlqcrgmlsiymqhjijkaehqibsdxknjwbayrpbinwrlxornaivuyqblhgcpperbtxubwiusmrkgsdzz')
+;
+insert into t2(a,b) values ('qugoadeyjhvroxskidmgshgllmdihjkbbmwwqfzdjxprghgryghhqaprmnqfvkzgzszffcnjulqsvagvtivqmdbsctqsyqpgviwzvzkzttvbneepxsphrfupmjfmxwshpxjirwkldzlvqscfssvrnngvjaufyaojg','hqifbykhntorulqlhlnlmnmrwlzakgmfzyrfrafxakyckjihvoavhwccgogjviecjtfckjbrsxsdouadcthvwvlzikpilttgrygqxopahhpqaclnzzwtsgureiwcboflejhtypynlnaswwveonxqllxyzhhnkksbfqdbbihehtcrrshdtiffjetsrbrpqjzcwuaeqxkaeoxijmikfs')
+;
+insert into t2(a,b) values ('xkskdnxwlitmgbmdoyjdfattnpifypetqwgevbhntbzzzsfhuzdbyjmgmxpgggxstcshdkmesgczjglfzcdspiiryynniiztuvpeynmxkycxjnyycpgtjrhitdjlcnctspiiosmqwwafhpkghizambnuguetdukeefwsyzffzmdgmhmmrrogehfslkqlowwbqsijjizzzwhcpiobezivyrfgjsvshnlgsgwvtaq','bxmdnzyssdrelguvmspzxiwdqbikejlwbisadpabzidqrfqnosubjpssgcgadajvajupetpeckjainvlpbdxkuyhrscofftvoqspckmdicpuiaslnprgxwofugipzbewqcsegmkovenwwbvrkjhglhjaupcqekmwgqywgjfaklwhjpqiatpyddswzuyvciptdupgfhaxvehowoyopzfbgiopkm')
+;
+insert into t2(a,b) values ('pjaxopnoulzarpcviuowigtmgcyvimyfhszoficclfentebonln','ittxgryvdwsbdrliofbbpulfpotjbbvufmharhgtaybwgxcdnfbdohptyyxbnuuvhxhlxhxkwnplg')
+;
+insert into t2(a,b) values ('fdmkbxmwshhcsawzizlwcugxuktqaizdurwgkmxlhclwaurwnpoamwjxqmolwtlzdytxkogxcnmfvshhycvfzaghovnlsxfpbiwjdkrpoppaonjkyvfxrmejpdhlaokrftszhomwriqwk','eizhgqtevqmdmh')
+;
+insert into t2(a,b) values ('mqdsczqbikboslyuokvtszdwkinl','hujbndvsdjchqjcojjbfuigefurjabn')
+;
+insert into t2(a,b) values ('ruuhgahfkafkkstfkqlkvafvxjmrhwulnucgspyqqxoxgzgargltjmspjvaztodjylvilrnfzrrjp','htauvaabwbemrtvqjewxgvztdkmanwtsrpyufwubefimbicikgocpsncmvtwrmlwsxmhsxrmfnzogvscw')
+;
+insert into t2(a,b) values ('hgalenlvxzczmyiphnmvjbjjedezwsrbanyelviczkwwsetxqjgaqteh','xcqhyxnifrftmbdnrlfowjwdrenvasoxelnoflqcgnwyiqfjzydoyhwopbbgmyqovlemneuikllnwcucbgabyxfsndqscniwkqeiqabpxzcowtaskjdsydrpftgfginiopsghmnvlxsyqmeqiptltiejsemetrvifg')
+;
+insert into t2(a,b) values ('omzowgfytmlefabffkepknskcklnqzljbcrfwjyxfuyspev','idt')
+;
+insert into t2(a,b) values ('kwnwzousqwxizcbyiwbodkp','dxuz')
+;
+insert into t2(a,b) values ('fntbemabtewnptrlkjesjvijzwojqolrjqwefluijcffgtigrjkyovjjsqlbgtkfrfwujniutkuymdjwaidwmvuborkxpcijyhaaabqmxehplxdqrfqweksjmzncmhgsdsbwtjlotyixhqhcesdrmdiyywuhforlzelulrskyxxeejjldgacqelaqrrnwsyotxwvem','xtqcqpxocnmkocujcqglfbwtatntjzbzclamcu')
+;
+insert into t2(a,b) values ('ouheeepmbvutkfnokkvizmbbgturzuplcnnsldivztoqmcqesbygwwqfcqaufttrycgmbjxitgutcwnldrcxphliizsyvwkfqvswcvrykhvddyzvfpvyiikwpoulwmklyejzdzszjwfqiirkxtjtixslseoofkgffivuxbqlytnvhdyphrgfujodbavkahpiugycjhqwjimysiqgvhipbpvkygnhoawcxniehhjrvuulmsetynn','mdbdkpjtfytaskctxeustnprzvozmyqqlpzolrnsnprksnffiikgvutfaiqkjjrizxutqkeiskoxbynuquwgpcuxtprgynwpkdqrx')
+;
+insert into t2(a,b) values ('dzijljzsvvkmomvtkzfigqfqgglolxxicysezzuseeoawblcabzinznwyvizojsjcznwghjerufjiidvxkxvtcrxgzacpegngghicekkzcgpdjcqdzpinhzckjsbiyqvkkfiarqjerbbcjfukikfjpzfjzyrlrxp','pjdkmzdrcgnarkqiwxxlrhvwchnboesxbjpbgzcluwjzoolqtiqlivhdphzyevxmvavuevbksmbrpuflcwccctew')
+;
+insert into t2(a,b) values ('hsylezxvcgunphkcecrekelfgokirhlawsrmwfqiwvtdqmtkhppvxhebmkbxoiruopgxxiwxlkakyfirhi','arqrcvllaqiuytsnigchndmynbfpklgiouknfgsgsxltpwvwjknmqqpphrslwhjqodpcuhstqdicirbjdkrowdqjfqcfiykloopumkymuktgrwduactaltirwwpcrtkgiennxzpvzykpkukhyytenazjnbivzlkwyatiymwgixmavkdicmivjucfomuhmqdddcwapxmnbkvcscncszgb')
+;
+insert into t2(a,b) values ('mnvdxrnvursidiydmufqiraenaxjvmuyagfgxgygfnplgkukmdophrqeyobvxbdeebfstdytxeeuskemynunxkzpjcxrnvudhqkhzzzayvfoesxukp','elimybonwzpaxvhxxtgmyeeabwbeojijuftwwemzhcnoxakzakynjedjnvvlxexazozowjgentbkbbbfewejjwdcvbmdbdjvnrumqoqftartdqdznlshrhlfrmtiimlcmyxnmpohupiojhrchefhcciksfifoiboczlwdddqdzsowanmldpkfcsxeasgthxhwamfevwyxbywktyngov')
+;
+insert into t2(a,b) values ('yscxfqyhdrzpguevnnn','lcqhjjgjeduflzdtcyzbboxvovziivgzamysusbroxexqceocmbhwjwkiyijjkncfdahjuletu')
+;
+insert into t2(a,b) values ('xsekrxhfxytdoiopdjzublnzlcdvllubjxrpbebshjlmugrtwecolbgidjvchmswbgsfedlvdylzfhdrmdffulnmrbamjoczpfxqmtunkdoedauckfdhkvhperiatdoimsnsexqwkcjxathgeyomgtkiddetltfavzelrmkcqavzbsqbzvyaxubtbkjnypktuyqvvwspzguaisapfno','qquvvnznmkuulkumnxkpqlkbnvlaplczmairgdpokjjnqgsijievwjredgqbhujbagvjexxkdbkgpeszfvtjqjgenrzispkxla')
+;
+insert into t2(a,b) values ('tbmozqizvjaceclxjk','uxncuxyhuqkxljgqzazqxbabbpybjvftaecwngpjafoyyadjznuarlkpqmynhzbflqpewpcvkpudmayonbpvclicvdmasbwwvhnoobgdfsodlivfbomfeqfamzletggqupbhuyzyvzjqtueshawlkufvwegtypzxvuvfqyrnkmdazvbkcrwspfqbyfqgwpjxowoffiuiarywanxslbaifujnibt')
+;
+insert into t2(a,b) values ('thvtkseenqostrnmqiwjvfpipcyetkjfkykdbkyixxvpueptjreaidikuzmozwgqknzzpsdjisdeljrduuhewkqeuzayneixbhmcbcqdkpwavuxlzslnazwogrwmxgwsxxhtqzekxygidmaqtfyybdukxebvswtrdeexascyicthhvzxlvarbrfabyhsijhoohjdaqxgx','ikdpzgjeafvrbrldmkwzlmgrbvginunjcinlwptbqcamlddqfjhbkexvlexgysfm')
+;
+insert into t2(a,b) values ('uxcblpgwvicfvwdbmaxgyayxuykumisscyabpdpqqoqoximwrcqfalksytivbxvtowwvnxbilruzuhokacypdsgkmjpvnltgndwfbvjxmyolabrwksiefonx','zylxscuadrambe')
+;
+insert into t2(a,b) values ('qj','xdoelgvzdweaoiyqkckhoburdruoplauakcitsklitcxwccfnjoyxytksjrebzjnvnzehyfzbtqvjpwzqpbmmijyjdevzfgabskkfylsdtosfdcuopgwfikbwloyztmfaqnmaqjvncusgxpimtnrxztsovjdfyribkibifa')
+;
+insert into t2(a,b) values ('nevygsmbusenxqbpvzzuuejqqdxnhfycgqkddcghcatowgyovmevdvstfnxcizddjmbdzockhibyatzclvcpnyqtjiarloahposcanpfduwiubzgkauvlmtnwmeevvfueacuxhrkakorglwnngdwlkffiricplysokjer','ykmqordldsfoyvrushvfimsyccltakafzixjtlgyjwzdhglhutjrfrjrtektvuubmyaqnvpdbomlwpffttpuynwvuogaagmzf')
+;
+insert into t2(a,b) values ('ikbjcgfivluptagmhmqepbjuoxfiejqgslutphxwpzhpgdcunmk','remqtxcdxspmrssmurgerekijxuqtgyspsszrfzeczlsozdmpmikohqkdyqslgbktbqjplmusjtteugdbogui')
+;
+insert into t2(a,b) values ('texfizllpoavpzucbnygdfbspxwytsqstcidtvbodyzzeidjfonmwgafpatoremlftmyetrlfjrorymzloknqckcxpbuhyrqpbcjmrhekhlzdryspkgefrypagrviuqdabqprjkijvhcnyildqolwokbzsmwcsgpfljdaajlhfgklitwmowbdhquimozaqocrfkqiadjhhfrurpi','ptjwlwydsevzzjejxmzincsbkayyeldsrtwdwdzoejszxtocvsstcjnoyianrh')
+;
+insert into t2(a,b) values ('boobohagbnqlfhdamjtgprgqggdadluiphvdtkqbdwzczywmcgnsokaazbnduetuehisqousgnqxahwccxgdk','jlmshbnjtnkpoxktkmvlnblegmtrftgvzsedkfcouoxeojjtbnmxvdhufurcnifttiaouniawcdgcrtzydvufphbkmmeosaovzelralujifclqklzcadncgqtcnspcjqknnlwdhsfvkldeddfffviixhgdhcjktuadqarurwxygroxmsctxsalaumjizkmmuontucuxkksptzqxkpomfyhr')
+;
+insert into t2(a,b) values ('jbrgcpfqimcubqwclipdozuvkqwtezryaswayodixowiexqhjqdskarlyyvsnovlzvpoteaupyqodccdbozkhnketzsxjhpdehwjsnjsdqqrenthvuahorsvcefanrbkfgoskwoelkbewzmpknuakrcygblyewgmcinijwcdrxyyknmupcqkvzrraabecpgsrlgbcatdwgbyldvvubqusssennrvldtesipongyazwqsja','puwlphppbxdhsoffmnqvfjduydfshqygiciizgajjmyrayegjwxnphqtarvvjiibzdpsgazaezmyzllyzczfywiodatuesezug')
+;
+insert into t2(a,b) values ('surwuoeeyqcbaimcpvyvpbcyiniwvfqqnyjmjnaxlwzbqsdilqpushqpyqztnghzekojwvsdgrhybnaqnbmlkttkpwqjwmwpembsrjkgzwnjtauaireiujkacpcnuctabioohag','oxvsamibckxlfbarvpsljyychqwjjltxudrlqcmzhavyyqycftbaufrrwppstrehoyhfjdqspkfryroslcsytfzlwbxmibzgclecgfwm')
+;
+insert into t2(a,b) values ('clluicjjnpifdxrcnrzlxcsfobelalmtkzeaeinsdpofikmgkbjhrggqxigvixpzbnvubjnbwqjydbgqnusotweft','tnngrfqsbjnozfgczzojsfbvtqwjeeqrqcabobnuzsnattrilqwotbpvrttclwezzzzojnikomzulgrqviwajmiwllqygqoarnpxqsqsanghjlcashikqqsgexsofldyexmaotzzuveostuudhgunuvqumshtfaldddmtdhptfikfudozhhcgzwqfmqtvqpzlbnlthsaenjaaquheaghfpmbqmzg')
+;
+insert into t2(a,b) values ('vfgtgthjfzoihdyjtxeqgbfluixxizrqjkdotkjtqltcndwebhkaekmgqijncnzcpcjpsxeeivhnbljsjyjqmgmezsazfvworumofagxvlohjwvhjlafwsnbxwwfrjktdsayngrieuzgpuzujihxrsmnrqqkdvpvdbbgsbuxrnhpcxqryrujmfdqqfldmzamivexxnauoiwzqbcgdoiuqpockposbnrrhczhcmbaxdndostgekcrgyzyzinu','tkfepbgtcdzskancriiobwludailtavaybgwixuvmwimeqorcemjzgwuymnbseboifqonmphaistkvirgkkcynpzvnxuayleiuolpgbpkzvjiwifwgrqucxbtntcwdrlvxkesejqwbewtmqasznrtymutgfnfxlirmkiqelttceanesyylezzwozvqbatdeianrswhauapzixnisxuwnemfvegioggrdlimrwwdooubznr')
+;
+insert into t2(a,b) values ('qcecdynmblpkdhoalkxtgrywcjuthzvatisqergjqsugjwesyjusrucaqdtctjuszoalwjodxbdmncpztijkwezmvgegexplokhbmvdaatrrnjdrszzxckxzjbwqvwafczhesooa','vjmmohqelamrinfwkypdgnrmcuqkxkgvppbwaepyalbfnnwwwqfywsjofrzchthrjbplkheyqrpshmnbuqppamzaqdpfbhehyzxjqezmkcuhlmoessappaffbolgmhoiyqiwtcputjptrgnvkdisaj')
+;
+insert into t2(a,b) values ('wiegfuhhnwflyrxwtzmjscecjnpyjikyolzuiyetvmbtlaugpbctkrpbpypvepgxhxezblyyaissswptqpcpczbwovgqenunfglmbmisudyciddzgalctxubqjfzqswcllxgdeapelunrz','wwoblckattcpmmcxdoesinedprkehrigcwdwuymhothhekrcndjjfkhzjgsvadnjjuavvhnrqfrecjgivigqqrsdamrbcynfzfortycpvstfzyhtaqclgvevrhunyfocwcieykrkqioxyomvlgfexzenzyiixigjnflkfokqmmmqjmzgjkf')
+;
+insert into t2(a,b) values ('auyxsoahjytvvhekykrzsyzjnbnrfvifzospglqvwhuwkcoseecvfugtakpwogvdmxvnbocolhgrzmrumxuxieupggidgmquwkrjdoezwjzvuwhjhwfxprqsmogutcsdzfcvercmughoghjmwbsksuryrdhblwalyehimsffzcuizggyuuyyb','cmavodytizgdylqenfyeflaxscpcxluhrsoibmcycvnhxplhmatxgxiycfllftflgzkoljuhoxwdpkffoslvrxhuqtdlaakzubtlelgkvk')
+;
+insert into t2(a,b) values ('zbxcmacpzzy','yjovvybrzkgikwcyrketimxvluchodmslgqhwpsulckddnqvbjpblhhrvtshkoapacmylwbutcyvzhubgacptyuwtittbgqcqelqxnnvivbuqqxtdexmmoexrcvbyghmdifebiemplcwndotpjqqammnvxstsyayiwwojwvruodhvjoxmjbnxvjjwbzhzdrvphdfiuxnkwuweawwmdluhlbiuxafalkzivouxytdbg')
+;
+insert into t2(a,b) values ('cnisakzarnfnwqu','krqsvnnqgzcsdrmhicgrmmqkhozlyhqqzrymdqcbvqxetnjaiunwvcisuccresxtaofxuoaxnygpaqfzdcutudxrskbepqtlftajdfstachenmvqzwwiylgaxegudkrboywrpnx')
+;
+insert into t2(a,b) values ('kabvglzoshvvnxqnfddrwmgwhnicdlmjnukewfcbfftvcvjjkcnlwuccbkyouxiwvhearngmpvlssjxhwbujcuvjpwhryzbizebwlyzzsfueubqmlpgzgimgqjvbgbebjeonpixptccfrqzw','qqfhgrhxlznlxxiwpxetgnpuonumvhlarukdifvcocelvkzaesnwcsbxpkkipxowdswakiqubqqfbqgbdmglpiplwiwzvywjqovatemvzkgjfaybcthxgmnpwuecakl')
+;
+insert into t2(a,b) values ('xwy','hdgpbvapmtkvinevosyodqvcybejtcyrnhzivhixozgaghxcswcewbfbmdtxvtqclalazbzzsoj')
+;
+insert into t2(a,b) values ('axr','vxebqnztilowfcdtyhomvmtmghdxiocwwzmqboafnhzgaorvuikmtdwicflidvxdzhpjddpqczraetawimlrfudwgvcmzcbydqqriikjeikywlqqopkigleoqspfrtrtcednrolmhmzxuakpgfxolwyusrkgqliokdvzrxjvnoncaasypotqszemkcvlcvt')
+;
+insert into t2(a,b) values ('znhqygtknzqtueidwrnreobjaqetwzlyubavzjrweipdzhtsuqabwsvlvsngcpncbhtlreyizoyqtsapwwicuukgyuffohoynsauwhiggiccnutueaeygkrpxgeeicfoplfqfrappcvhozsqqavfvwnkwsabvmwgmhtmhbdakyfpepuhnrrcbbmlojfdixlfucmgiqk','chjgutaecbduazwdolwbvqowztacalqrjicizzvsfwedwqwwtzitrtdzpvecgqhhvjvkkeqbdxodldkhbtzrflemupygsoybcvmrsnptoeofmkynidyojfwjsvmbnkiiimuvqpuhabituyjz')
+;
+insert into t2(a,b) values ('qfombtblxogaoduqssjcapaojyafxjwwpmxrawjszxwvqmorlsbmpdhyemwluajualruikjdypqgvucyvauranbgxlakqauinnuoxbtlkgxxauiapklejfszsftvrdrdpotahldayauxfcpmvqhpgaqmvkwgdkmhwzgilurdxeomyeedbxvlddtfxmmrtmmlelixcqfzfvpqokzikvecverbqjimpuespkxvgpnode','mjnejccultmfqnpvioisjkydcuhdgqwvvcdosdkeergcn')
+;
+insert into t2(a,b) values ('gqpqkpubfyndxbiwvezwqugiiuzfthlfckhutrewynzbgpythmsacpdktnrfoxxflfhipxyuzlvedbvkloimjohmftiecwhzaehbiplrzklxqzztiqjszihcitlpuifhnppyofubrxaecqbbnddbssrmdzmabaounqcenjphbrjdronbfmjihmzgnnwyxijiljiqupuirwoxgjxhdbjuemqufnql','uwavhoqsxhlefotzuioryclzulpzatkyhetcbciuynboudmugjaehckklamogyqvmrkmekiustsosazivmdiyenqszaasvovkshhxhhmiennvizbhypvzfrpszwuobgonxmvxnzbimcabrxlyrjulbvqceeqcktjbiwhou')
+;
+insert into t2(a,b) values ('ivvxukvkoyxtmijehjnkvbgeqzghxfnfrlsibmsbxmphomuuneucbjbuligjldaomtykyvfhrnfidncnmjtddhwcjcnicizf','cekiceloqsnlqlojlxnobfmqrfhmdscdfxfligymfkmgiziqpiopkqd')
+;
+insert into t2(a,b) values ('jhfokxdtdddtchsptgepmrxlujdqqxmvltvymzyfwbidfenoqrdqdtgnstwaamhaquokvicetyqngcfytkvpcqtqslxrsmtskukvsajlznfeimpcmfuihvxxhssgpodlotnqrytidszdloesebmulrngdttmaicwkynlapragxyzctygwmlwhyasewoftivihvmlxtbal','zzfjtpjxbtcxfyoynvxwsltjtghygomwqzjbxcgyedlekghkswevnqzmzaeiirysvgbwfxdujzyqlrimeoibzhgqsahkeikglvrsisdseqxmyfzacyfqtmzlwmyqtpymvoxdwvbulyqhhljypvbfxnxlmhtlukuvnplxtolfmtwtcmtynevdfavbhxyzkvoourktsfekpaimrqhgmjfvvdkufhkyvcpdra')
+;
+insert into t2(a,b) values ('rcxjbgimhbsczxfrwhdksovlvpzcnjylyejmmqjo','tcaunxbosgwvzodzvtqjpolkmoakhsjxdjflhdwgtpbsauxqwtkklslstenokcrsgwfogqcocmyxzjzbqwbluafxdwinbcwtivfukvjqzbcpxiolxwwnrvhiennmmjmnnmurnktpyowyiqusgnavcyvtzqlulvxwfncaxgyhmtsukmlelnqjkahjeplfqrtmzsuminzwlzftwnmlscbgcyqynrp')
+;
+insert into t2(a,b) values ('yezyevnzlntaekggkzzvtmgnfeypldywglbzinlvlqxabcwqnwoimgxewuufwfmledysukiljbnzbciyfictnelwvevturslo','lgynwxceimzoorajfmfmixrgzynqpffbettwvjxtsrubprjwligpaxgknciaxkmgnuuagafjfavwgovhzmqfytafvnjrtotcvugkeijqiiryqgjstyxapcbtvycxzsyzrbeeltebmat')
+;
+insert into t2(a,b) values ('ymrodqllfjgzddqhjjlepajtpqvjomqzbklogximzfzzfbioaxkscul','evshtygwjxwxkztkvqeozwctxomuspxmzguqbuihitdehrqfsyzunbnqhnwqfmawktchxmqenhaofrghefbxxauczueanzjvtlubhyftwawcwdpxnybryvfpdwpthjfzfocruquzkmevmpivhugbqbmsgeypvhafdgtexusghqxu')
+;
+insert into t2(a,b) values ('xuqoqkhyekqhwynhjmdehehiputkzdulmwnqdtsrofzdxjisnhwpgppwabishnficbwtuojojwfxjzbaalrsucliidhfjf','htmhoilwqdyslsxqmlhkicbdnhscqaatqploneepkeopakcfvagfqtbgcngvkpbytubtfydtcaldgvdzppbgywoewankychhyfpvclypsyhpzlamwfdsftpcmweyolhemvnyjwwjbidlplnuguhkxnyovrrqfgydlektqtlkfuwvuzbryyjt')
+;
+insert into t2(a,b) values ('knczrhormhoqxfukvfpacpvcwvrvusubriyfmrobtwujmmlgncdczfjtyyawvoxwq','usqdlmsghadgynneqmvztlbomcasvvgwgpytxfmsoenndwixaoqnozzyiwtlkoahpfxkssitc')
+;
+insert into t2(a,b) values ('uyqtmqtpvopgqxtwdunfuthbnevbtikvxagysodmstqdhysyowgcxlpheyvnixamoyogyxmitckrhhcwdotpnzdsyailwhbikfcnotsnjmrvcqzrozmwolbywizwkzngzrbsjwsrjsibqmilrfxizuifzzeres','qkzumovnivkvzqgkuyddwezqmfhpdiycctfcbuwxrnsrmuiblmiqidfwzftmttjvrexoihgsfymyajysqyqusfwcgpxyfsymgsublqqetfwhrbjrlauxvgphiaewzhimhacovxbgsawifsfgjteljlkmvolprosqolkpozgwpcz')
+;
+insert into t2(a,b) values ('uvqhjzjppcjtumlboyyfchpeynffjbxepesfiqropmykhsdbswgqgmflfwjmtuwldsmwvjrldddbapakvqboizayjnibdizcaznwqfeonqyvlufrvfdizoeimohdemagmsiuitrzhflbuvqmxnhynsrycpmcitgawfivwqxmqarlhmjtfbosizdyeoyasokjtgljcmvqitmakoqrfkbmqszsedaldefhmjqmfdzsbmzjv','beoigptbyscrixnutcxueolsvpkcoywjoiintehjyiqounzkvmxdghlarpbcgkinypkdhbqzdwvsexdjhtmkfhfjuabatahxrwxuocdnmtvkjtawlfhisxvgbyyhjklktaxvdktmhfqgrjumtawlpmwtqruvcdymhfygecipqbiuvyhctxixlyrlzqyxakicoplkvqpdktohenzhqblvnbkcfnxcyhwemlynxpprkthlvreyacvvyqirkkg')
+;
+insert into t2(a,b) values ('upzxulvysicgiesvnpvnjzejlfkabtvbekogwwdadfhhqqmzieigitmwztaslmvoenxgcsznjshabzdrbkredwjfqrezzkmjlmegvlfhptdpippnygbvsvqdcffltqaqetcwbuzxwjujkqcvoqgevhiyzuppbsplfrqsdzsnupxitgsenzlsvbvuodwkvjmkhaapins','llwlqvblwomwvimulc')
+;
+insert into t2(a,b) values ('xecihqtkckksqckygtwsxhgyfeheguyoiodauofjxbgztm','cfomlqlmgebjmlqyqljfsjuotcvdtwfshxirfovvgyyemdmvhopjejrhaneycdqcznotjljaymwmoqnabfsmrxhmtucxdqysiblnrloxddibxhnxhn')
+;
+insert into t2(a,b) values ('ndyxyivzxsqrjjiotgsqtbufadcpawfyynoxhufinfqvifdlounkvqcrsmsnwnxfnmwlskizjzmnqpcwobscfzctlfsasljaxgrhxzfnsfzjfatyldxmtkhozvlcktjyrhensyaqkluhzswrvxxyabzdeaycupjelmhthslpjwetrbzucmfpniyxmlqmesiwyhldixkdobxqjgclhburpmkaelkwlqlfqosktlvdqwmutpdcbmtnpypphirm','homvndarknuvpmrgududjixytfjmefemlzihdirmmntqephpzuuhwhopoaterlccgmfvywqbkmxohvareztjzoqmnyfxgphdbpvmobrarcxyalyfqexburcbrzvmsabdznnvqgbyfddhvcvltkflepxcplmhlcmffyyphukamtxckjtzsxkzkxtlqoxqhxgesftktotqlauvjitgdzvjhczrjwhcpoeonuiabflusmgsvwdmwubn')
+;
+insert into t2(a,b) values ('mkxwikzsdsdajnvekvpvaixlqhorlrcshgdsdbyyzccihlqszqlggpuzeoyfqbhojkofgvxhvswukoirmavstfbtonmftywxmxzktrcguhtxnbrvvfqvtygwmcjlsovgkknpyqkuzmdwbemzknnpbbsydloyqtkuwnhkwwnsswbjmxsyjwtmzxxxt','nobyixsmravfwjulvtybtdgattzqskseyhdqsehzuxexnbybunictjqiigbzjiszucqxoflyihtupfgzbhlgxeswaglecewfkoysowbidktpefrbrtgqhmdxmkdmdospbctnmjevjdeeqmowyajclxqpgdoumvfxvtkqoqjbpnlmqmicwupucevknfamkhfbddjcmeftyzmxuuueuudfowrtqnpmzjwkiesxcnbmw')
+;
+insert into t2(a,b) values ('vdufflhmxueqawbczqauooajlraaaapamgwetwphmfsafpedupqjsakbwiktkptrvbmhoaekldptiqtfcpbnnwwbuhjvmbkitpielexuidpntdnlleecfwdvqxrcwomfbxviucvwrxajgooalztvgziyrwjbktmzrwzwxxgitkrschjtctolmecviwnndrqjctgcltfcbjikhux','lmxbtpahwvtraafjygiihjbipnzlhgtfqvcwhfajjrhktiqhhxaqxgudxuiooarntydbeypslhmpjxxxjayqwxafsdbzzwxzxjtfpsyrvneslugcwrrksgandkdgvwnirwmqyymtuckubj')
+;
+insert into t2(a,b) values ('hihpcmhmxzjj','klzdhfnfxgtjjkqbbpoabhraxfsyhvtnesbrqvxrduqpgzczinnkivtdpkekxhpyiivfqokkckbuxztwuandblltliwhpjgakehtrpjesthqefghlbmueqyugioewjnfwgjwkevkuprujuyobzoowjbjqwzddhun')
+;
+insert into t2(a,b) values ('wrcsqnkabrzehevhsoepasrgdbsiresdvrorzjbcsmfmyozqdvnxbcveaonftbupyapxitubejrtgjxocsbrqiptxocjdondnkkpaputvhe','lhyentooyiupyvbzqmdhvaybrmwlfluowwkhnbmyvmehvehjkevlakymdtcydaektbiiawsiplxtbvgoiaqxrgwokvmsymovffuvbtseveqveqsmffkeepmeoqvfeejhzirbeeblchydsscclb')
+;
+insert into t2(a,b) values ('mruthbzjblolqaidgifcyknzhtkyczuifuqobzzhurqgazopxevhcyxdkmicdxigkcmdkqioechcvhxiyzmvxtegoksqozuwaeczyewagzvpfganugnfguhnqdiefnvrkr','vmmjnanhobnewyaehasfpusntbveqcuihgmqbpzczzognroqrioolfqapkdgjgoopqiipmntifktoginwlyaqpzpszjpsfeobovyizyyfqgnwqwuvgjqigefeaqzijhcrnthzabtdvcutbk')
+;
+insert into t2(a,b) values ('rvdhwzvfvblaeqyqnaexhhnpyobglnurcalejgepcqwlgolttcrwszqkvulcdsxexdbvvymggziqchdkjxuxbsihdpwcoeraiqoevzljwyngcpwequwufpwokyogdeeoqcaeocejvymgyudzmxnebejqjnhhdkcduhtlqfkoxfblvwdiqefmpydreqzcwtxqeqrxpcgpomvanxpu','kncitufgvlulcyioxtwtwhbdpzmxbmvsqrlyvmipthyixqhfwuyxiphvgsdegezgkgbuijylnuvkbnzirroswgwqyygvbpythzdxrrhkejnnbgpludkrjsmwrqgbvvoluaxipmreuvw')
+;
+insert into t2(a,b) values ('cbgjzglfbkldgixwuaekedwbomicskwhkaxtocgrtcqlbglquvclgrzzzfdigtosubuywfbmsunihlcrawfoyutfjqbohmnhbojtmflqdcfvgforegpalssbtrvftmmeonzomazloiecwtsdenzoyofrwitphfuldefyzxkn','vwmqzfxtpcmnryjpngoyopzglvzqfmkfhcjnyzxghytyjkzgbafvsyfjmqhlvadkusgfedkiyodgzazgsuacdprnjfxdcbevqxmimihwdzehoseynypfcpszmklailtlvfppfmsjfswfurbqubz')
+;
+insert into t2(a,b) values ('egzodsdvioyepyrvrgprzjrmslxyituehvunkwcgjxduasxcaoayjwtdebzdyxnwdvlmmjnrbpxvyhqrbotglcuvqimdwyzqkpsklrmelvsuinataiockljgqppxlimscwvschozvasvoeuxhvcpjcmglexmqoxcdgwkrcpaclawzprzaiqwozzkzdwdschvssbvmwqriivrwajakayupkpof','zqcoqklqhmzuqqdnvqcnmhaajtdwarraypoypalhiwygtatfuucsacaqgkdohglxnagmjuxzsidkgqgmrjauuzhurfkrwqrrntontndncvgvopttytdkbrkpebnkvpagfqhujfkhsfxgaanmcnlvcfmngavgagzohnhpxrtwwocgsthhltlfxngrjmevvthjjtjlagzvwqnetjwmdtvqquiojfnrxyi')
+;
+insert into t2(a,b) values ('xbncrduobdoinjxgqdhmudxqzokndxvnzslsiitsxlltfjyalsxpbvfculefwiezirwkjzgdtptearmqouwndpgphnmaeujspfrfnpjcixlqzqpqmwzikgrvvekxyeoizxpyyhazvbeqinmyrzuyxyixcixjagtfcxlckpixrwwoaixjyyt','gtagbxrvlpurxcthmoiqdctixjjxxmibwplxmkbfxjlhnotdtbzlaradvsjsoknkmrfduiggoycoqqiudofkrlrjqpfpshiuedcwwvcteeejmhfpfyaxfrixyxjckqyipamjzybbvlrenbwjzb')
+;
+insert into t2(a,b) values ('bgkprfplydknqthvnwnttgplxtr','vrhkvclpnxqdyebtjamxodrgqujcvxvoddfhgdxstkjxnaphztqsmlrxjivzfocfzmyzfxkkutkphznvddjyxdpogbmosgmiyocuuxfzjaegycqaqigvonzqmznzcfxmdvwypuahpnhngsmldmldyczauzxmfslyrhraygerfvtzj')
+;
+insert into t2(a,b) values ('zofequnefdrqwnaecbxkvbgciboogholrfiqkeyjvfhltgluvmwfmaablpwsyhfwztxvdsauphqwimteefimolwiwuafpxsfeueiexlrpxfuffmhdewbitupycdklphenpsqhfhvurqhwwmfwvzqisiuzcvchcnvoruisuyuhiqmydlpirgrkwodpbgbnakpnnxmiegpplrgbgekqtmfbskrllhazxkspix','qctacvftwcbryntqdsnbcudximjtcpsswjhugzrrxtryafnylysdxxqgxrklaspbytqxdloovdtsrjiodwholuuajkxlkyelqpfnukqyqhqnfztgvrtcmprrbvdanbgwfnwxianbzuumitgktaxgbzrptghafhfygylhgascgricfhz')
+;
+insert into t2(a,b) values ('mzivzcbrqeamzcoatsybzonjrmismgasscxapwusuuygjkrymbieutrnmaywkixujosgublomlkhnvsivelefvwwcloihlyllyqrpzdmeqzdmephnxwrwwafngvcyblmqdv','bhsdkwargvypizizkjiubvmvzfzukfepinfqdgsnlipduugibyalcvytappckvdyarmsbxuwosgrkkvzevlccsqaebhvgdnemiozudylfevbhjvmtdpjjmvfoeyssfqpmaujtqovulhupfiztmjcwydgfrpoqjmigjrmltwgqdumktqvjrqwymcbxxtllwlorwojacahjbuaedvcrjljxcsmddikoibmorykyzwqycirjfgvmmwamfzpjrzm')
+;
+insert into t2(a,b) values ('nwduguhhdoiruhosqgkcvkzrmbtrjjhofuhnkkzaircmveekcyfigxeimslavyqiuzizgcrvfiguehua','gmwwbtxvpafyhrtjrebtbzrkpgfqbefyhrvnoxndjbgsoarutnbqdmwbwzoxxtfifvgpfopviamwtvnknubwyvagzctxrmzglrvyctzwhqrmlclryqnnuqbrzolgjaexegweftjggrizjodsamtjzzqcvusxfvylpximvozniqnjiftlmnwjoj')
+;
+insert into t2(a,b) values ('ixugwltuqgliaqhryywypstncakcvmqaspxahdyzdbqpkdbzmgbtncccymbldnseggjrvdegbxaobgxfjjigwpnjhoswkjwgvijgeuyrgryuzjlfrigitjofbedcuvdktqarlewwsvpdynwpfavgrkulqwouexhpzlgdrtqsmubklmkwuyfudyofavkhcavjhaajxvzfuvgwtmyuqjfrglqjzbcpibvudqzufhczytirzxreehqata','xditcyhyduhabiskmzhvrmheerzkwclosxdjuwlqtpmuhjal')
+;
+insert into t2(a,b) values ('lpvbhrqcjnnaooguhxqywrhksqitjtcjipnhujilcrowjsabodrjetcemtudjondtbofxlpuwuceiztrujrggwlbcgfeigrrhjuxiofhqsrtjhgizyjrwngapo','gyhukitkantrvzvvuvsmwhwjnusihllofydrmmuezihxhwxbsmrudydkmowjsligmsupwxquroxuqwpcmtmluiasollermeicgzyjiolcdycnnohivficncepbupcxgfdeiufjdl')
+;
+insert into t2(a,b) values ('ljncp','xlcptarvgiygihkdtaeobajdbfowkcxqlwgnlrwwgoijknmglhmixbteqpzigxedojlyojeypzzykhujrevahwssxficncsfdyihbbczlqklmiftfjwgcnbwxsasujqpemldhezlmtzyilwhxntjovummztsxpaubdksdyyffqanmugztesngj')
+;
+insert into t2(a,b) values ('ggyfndfzpkxemgmhbpqhhtnd','vhghmshkhsaegcdakgvykmjbryfroykxkplpmojujvfrjcsaorbrytbfhakyhtfjasvsgmqbwyzfbzgjoywowgrnphzsihyhsdityssdujzccbdnnrfextpzlcnirlhfsptitghyjtvbembkizdodylsfdhzlbxmhkywufpcwjyrauaqbjjopaxcpdasi')
+;
+insert into t2(a,b) values ('aucjwkxbnpqhqvzkhlldemwdykdwapaczfhsezuvlmztptgvhpexegaeedrdqnenikuaqoxplvscimuqlkasbxbisox','soipxfwnmrdigqypqgkqmaelfavhacbgdsjmcxdlcoxiipndngzptzvbuhymddptycctdwjvylebndaymsdpnvhuonlsomzkwkkwvdaeacshfbmkvrsbtdrmowwsauawvxwwzvykkvmnovvtlqvlledzqqrdaimlcuxukmvgsoyuwucputymcvkuqtyxirsrsrmcctoxijctparksbjqmouizmwtdtzrvdfkgqxrpuecjcs')
+;
+insert into t2(a,b) values ('arxxvewskjgrnvqsgzhtkmrheonvjmplsidfkhiceeznbjmjhodiqkmptnjwbeugvczhtixsmbaiwcitsoeutcigbnyxyebaxrdyqmnkwhpybhkobraibekhtneripfxknqttkjgzyjwlbbmsxgtvxphfrryuznfvoeraquggscxesvbjwrtawbqgrhxohstpgmrivrpjsqfapsbrtdhuxhluicrtrtzquqwncllscsarb','recyhkndwgeqxybakdmgrzivhslwgrfpzmfqmvdzrcveaxlclzswhwcnqebkkwvraominvdumffiaznutcmjxsdumhlsobjiyhnayfzjdahbwrwmzazkkizahfgyavfhyrl')
+;
+insert into t2(a,b) values ('bqbymbsjgdvlfqxx','ikcfwlcnbvxczbflywqltglibelsdjs')
+;
+insert into t2(a,b) values ('aqmosoeptuwyzymuiatncpxpixvdpelyjfszxhqbfhmjjcrloyihdbflkemaebllwkktbdmjahperhwtpurhrulbewdhnsirkhywdpacgmgdgkdxbassyqpfvcfkflerrnmguxiwcbusccotybycidlmkfpxpsanskvkckgxrzkcwhzgrmwogcvdjymnjmzfgwieximsexerslsnvxjtvzsh','zijimioovfeocsmpxjtktdylhqatqlkcqhrtemezizhumrezegu')
+;
+insert into t2(a,b) values ('ctpwoizxokzjno','rrhaatmozjtjtqzpdfgrpiuwhchanwpcnwjoglmplohymvoleuggkfnmuzovqkzjizfygaxfyhulrcfgbsqyqgdjwmlvfkjpsgeuostkyiyyyuhqtxxethxxsrupnclsxeldccksspxthywugmcizuvehyizkdrtmakekfvmevbykmlvcyjdyosdoilrumew')
+;
+insert into t2(a,b) values ('armomakwfvcyicszlusjqbgkxyjhlvhadysvvsmcoerdurgjzowcpfuopzemgycfhqzrjekyzhyoszidqahpisckinvxmeexgtatac','hslpbziwezcienanjcafjnnafnarvjlawdswxnfrdlohnkepouqsjmyfokvlvxlwwgjzycenzanuwctkuzwfohbxiaxlgwlntvxpqiwbwitsfpntwcekeecrdjkavoswqkebxiusuzeddhxzitosmulbwbsogmvwqwwtcjvmsclupu')
+;
+insert into t2(a,b) values ('atgkoepnhmhutrkxkqinwflpgxjldiftttvzndbgssulyuheoqnoduqoaxfguiksjmkgnlkeidgfymgtkcwnfdehvkxndakmqtsxslfkxlcew','eqzroecqckjqfrazpprjagjvjpucrnsuykorqtwoupasdzduzgcqmsresmqcxjjnxaiistozonubmomlnbiwlkgcwccvmgibggzofxcauvnrsqibyvbrtghlecwlogxkulvgvyhrhu')
+;
+insert into t2(a,b) values ('fomfepocsbzfyqfwncpyuevuwclcopazazbiqtsxqfhdbcdnljfhdtquvvxjgddmeezdocideuzkhqycrafrmvtkqivlonrswhhvjpfquwhmibgymmokdohdopljgkaxgoqocoqesczrtjqbvsytfmejivtrbmmjhuisnkmxcbxmmzhoofcjijxcpapreeqdafaacrydqzamxna','nshbucjhwxvrektegnatpnjouyehvowdoflgnglfzyzlrwoysubjpjunnavqgwylsaubxlictflbwwfofewrkwytivagiurejnkutawvnhemchoinmdjpmdlftuajqckkpxnyp')
+;
+insert into t2(a,b) values ('idhkcjfcgeivmhlcubejahpzdnsztuvcqjthmzsiuntlplrxhwnrqwfrgmuekpapnmntoamqwxufefyezsgdowmkbuebubmgvwippjdccsyperklogwdtvervxnjqpedlleueaofygprkezmzkiozwwkbhvzehkxrbssuqndfzdabzjxiwzzz','fhwwlqmzakntnhiuqgkoungcbwczxbljiweirgrqnmjgxoyphadayidhslzqhkfysqftvmtfzhhcyaccgerchfbcezhuwasrwdmulywrxjhavzmqpqilazyivqljbykorcdnieclhoozlygprtxfbfagzbzarmhpxllgqvvyydhperqesuzcodtwgvefwgxdlxgtvnflzkdlciahbqpsjltnsquascujznvqkuj')
+;
+insert into t2(a,b) values ('npwcsjyvgwznpcqdncfhcirtccobmwvudcaeeezghjfoaxyffuxtebwzkkmqegzdgqeyunpeabctosdyrrrbhghgovtysowonpuzcptewarjisvzgkkawnlazrlioqjfcgylkdwgdjsmyikdvzaqmhipsxgwbzfcyjgatnwrgfmyrcxzvdfzfaiwytr','rfqmtevjqujqhpikzndjxljndrzgivnbyhnrgypqqblinritgwuqcwjicqpsiyfpkmbysphiyexsxjsuofmioyjiovzbxydttsjeuvvpumsvsfbcfjriqxmoicggtnxovgzeppvwq')
+;
+insert into t2(a,b) values ('giczpbkrjcntnjfopktcndmblyoqkxzoddyhmvgfatlhbvkoweaukqcgynfvoilhbbuhfmorurpzwttgonhjmyqchjhieodbqdoxdyfttizstiverbydxzeqenvtddpsolvriyywbytnovdqfguchmnnnkbjindktxsbhnrmpkgucoltwygenyijekhvmibwhpwjdhbmrgiuaymxgavbbfvzkbvhgvemzjpdvultbzfcbufswxfxskfvdsccev','yinjhdrskjfzjrvdexffvgurwpuvqrqzrymqzvzwwdydhcsnjeajhroseenvovgxriwcgzofcynjpjztvmfnuxogsoicrwkcsrwgzvuzuckodapjttculkamilitsflcxzpkskqptifosviqljlbjalvwgotioibrsdtarhncvss')
+;
+insert into t2(a,b) values ('zblemlatakskcofmnrovndrpvupwjrqgdqqdsgrcumsqtquxoccifibmwcupghqcrhjikoufmuskexznbfwplobflvepnxdtpzxurvqfbwjvkijuqomzpfegvykbwpepqw','lnjaefdmifebmkzzmfcnhlqppgdmqdmhsggyjaucsqzrrrhuazcgstllsgmgxyndblamxfxfhmvvihkjfh')
+;
+insert into t2(a,b) values ('rkcdaxjwnxyehmyuurwxmevglqhnzwfqcfmpqlfqaovsmhgnxwjulfhobxdgobgxdlbdw','svxljcxlsihpgibapblwmbckjjizkrawmvxnqiqpnogcgjmkwdzsddsoruhxillaaarsavloautztsgjejkujivndeemjuedlvxkvzzuwsoridwymqxkwsrtgsieowerrwntpgxsbtymyovpoxtoy')
+;
+insert into t2(a,b) values ('okuxxtmwhumrdzzgznyyhtslszxggtwiczccingbeyjiljysdpbfyfjagdzlteupioiwjzzxyoudhaljvhsyosenktgrrjwhmohfycymvmcfbpuqvfivmjssunzjirlmvddwixxkknqrziupljeewrnrghjqfntfynloqhiqeiqfjitybnkzfijpupamtauhfcyaohnuirrrgzvqobcichdpgvsnpxuouczuzaokodqs','wvtxgkmrktttbzfzjebbxqivuvwgdoqehvsdznohrsevaosbrifwbwpcqskehabmoqtjhqipnhjzgeuldoiwlvxmmxrlazuvujfbpjstwvopqkoyfutaitwhdghpdfkqxqtatsybhcettcizpjyipfniuweldlyzfneauqywqiqzucxltwjbvyfknwoiferat')
+;
+insert into t2(a,b) values ('tqemtghukmvkacdbxifnqrvjqewmnotstlipneqocwbgtvohfmhwgdobqrztkhzkxarxwfenxgrnbqogxrshaexwdbsyltkoekmihiztbsatetfxbjyfdvwxokwtkjxrfmrhddwdxplqeteoexgphhjthuscabylgezekceiwynmlghaemxlahlaymxnyjgclpwjozfbeqsthixwbegjkyuvkcwiqjphpclgutmp','psh')
+;
+insert into t2(a,b) values ('goxtbvkwsdwonybzkzkhgbedycnrebshbatfqdefuabzvusryfzwqypvobgulqhuzdcavmkdyclzjhemwghnjagsfvgncopidtczeorqqoqhdzyweprlynqucgvcoxlzlwdsdduhfferlbhqqdpusshabyhogoojljvphfkyfzpyylwmpvxvazzlikwvbgnddcuvjpnheqxblgktjkjeesxrvceadwadhtkdmbiqjqbcchwwffrzmmwcd','hrzjdkmjbaffavrxmlcfecqhfxtprwhheivhireadzcvddoqdjzbmseojpmpyatjflvzsddkzvjsubylectaetempcooxioluyzigaecpsoqwcmtfjvkhzpmashdwmdgclao')
+;
+insert into t2(a,b) values ('qxufrsadxpcxdggmnvkbooxjqmhsiqbpufdepzuofydjtheowddwpeaqnwtzngbrabvgyhpzmvkwcsdkyxhwmlbkfaeybfspjycjqlifndaomxfhyqfvhrklxzworuqfjyryeloqdfdkhjgojpxiqqppyhehluzyacvfdutlewqaveyehpddajczzvbwthzuwjvblzpbacbooenmrckjhlxuqleinhqglftzdhuueiziajztrljraqyfxy','eqogsbkhapyyropncfqyaahjgdyrilpizmqopuprxthffklaprozafmhjpiprdqqjjdbjhhapqplaigzhdmhbehhzseoshzuzvyvvkyzknhukzvqzeewcdarrntjhmysmqcsrbhshgppdmrlrqxclsqrelclsgnybazfjjuafzqryxcgsbmgakyvcgxexbhqsrqovwvhhqrrycitbfitntlgkacjjolaq')
+;
+insert into t2(a,b) values ('wanvwpnigpbuggkzfeqpaqkzpmkgqgmhjnbjpssmia','nfgkuansmgoszzizfiyhadifbqdqfsqzfqyenizxtkpfrzlyfvkdhxufwxiqbbxwmlfbiynsmddpfmofdkpbrsenjaltonjyerufhgjcquvhqpilfpykjrbvhoknkpwvkxjetrmqu')
+;
+insert into t2(a,b) values ('gcxwvkypysngdnjuozkublbdoisbfgmzqsuaceskegzloliozkpkqounfryasvwhuyu','dxfbvlzxwzkvmgzxrcqarlhzmlipfsdncsxyiaousfllredbqljpore')
+;
+insert into t2(a,b) values ('wolajsviyrxckwwtgqqohcjmwpjqlikegihuktwllwxtodhzchzvmziacyvnxvbndlkuhjzsszuryoyunhdnehuojuetunzd','uvbjjrzxnaeouipdcivpmsgt')
+;
+insert into t2(a,b) values ('zhfmhbgxtutvekwbncvomzquusboushanvfjduemvcpybdhntriakindtxvxezjnqwoxfhwhvlafskhedngofqavrplecgswokborlffoslqhwrfuvvivrwiolxqdztqnyslxyxhcmkgqdqthaxdwfqeadyzlrgrezfdzchjowokuexrsamcnagrwmyvwqfqbmycgfhrlbjgxgxfeqshwqdexlrlkvbdmvmilprotgucwhghysgxxjqfsrcqx','rrndpaxndpihjtkcbkbmzunbxkdigeuqsvsprflkkweyrigfwtrspkrmiwxywgqjdjqtukkiuhecimbk')
+;
+insert into t2(a,b) values ('odrcgvhbsxneinwnvhhcglowsmzgoyzbczddrffmieixyiiazwconllutahdyouonubznotbrcldktjztcruxpivjaibpjucuombxfjccodkyyjeiimlxvjjlhinjfiyvvwbtdtlotlryorvssnjpwgfydvzhzewyvclpwryztncdzocczotpyxmlcrjwkgkbmk','jfcalfpbfkiidaefzlwpwzmcfgyebdnhkukorrrutcrirbaruvfktgrjfiaiygftaekzugivlhpzwpuvmhdslzkydunfbklowiglpliuglnhjhilywzzpsbskfyqgwktbzcjijbtowoatuzsswodlqowlyetjmbn')
+;
+insert into t2(a,b) values ('rceaguxwljijgpuvt','oqeewbxdcrmzrovciiupihqjqhdpqdzhxgabqnahzhntnohanpcojfmekzfaoituuupmnepvqabonddlqvsorehlsejkctfwodlqvvkpwwhtishvzmoryeyjwspuiltppxwzqnszeizgijluubqvgigllrjessziolhhizauywlw')
+;
+insert into t2(a,b) values ('kjxpqndnfrhnijnasirfqbhtoymhyzxjatlayhxclunrlpcswdaowijcimekejlkbexiaujtgvxmnbqunkmmseeaylhlqgrddpajpfkwcpmdhyxqrxraftytyminnkrxzycijrzrtfbahrqfhvufcswjqqfb','qsevdpubsinwfsrvvsvosvcmkmcpkvlymdrvmnhmfstqfidtvosjqnrpntnzfuhoqdzllumlgvpmjvszvxzzzjgtlofcyxvacfioglosnldvuaostnhshgkcpeezszgs')
+;
+insert into t2(a,b) values ('yycqgmwhzptakkurgkbvxazezvfpgjmhshegwwitweqvlypaficzzvgkmwuwciodcyvzmlaxczscadjnczodwmeyoeumlzuvucfhbfkituwbznbkmzjpeqefpgwmurfkqvaksuvujovgtftvwgjeqhsfizpomfnjhfpqsdjtrppyjvlfkdthpdbfxtyxndugtfpjntuefghlmpdboqtckxtvepwgodzvmbyhoxcalb','auyiejhrnbeuoyxtncnldgtcbyanntfythvnylcgydxnwammomiyxbzauxxnozduasayyigkxriqjotmcgyztyqhuzjlxlrtclvuypjcfrnfarsaislcticegvnyawupzh')
+;
+insert into t2(a,b) values ('ibudukwklwsgdmpqiufpbvbgniefoenikpdavzheuqszvefiigngljpezwgybqzsxrfhufcdshxmuzsguatq','fdgnaiclnhjxzikmbuawrhyviffargwfyndtmfaflqnsoyyhuigfsdbrfdlijykxixapzbj')
+;
+insert into t2(a,b) values ('qjjdjxhsfdhbcedlzprhwrpregnrmxhlpektjvzpsicklrkwrwwdgpjwylkucyxaqwlxtyexfmiljvqfmdzgwhhnhfxiqlvrzxurnuntmwjlswzul','dvkfmeqiijypvczphqsiyryvelrbrwtntddzcnitwuozrjgydsexziyoesytbygnwlpqcgteyjxogefcxvmsuthgznuqbmmapzdgifbhxdyzkefowkpvsznytmqdtfijaarksomushwakaqqtkubocmpjbclcotgepjppaivjexjuvezmvpzcgtpkcotmrfgernahooipiszu')
+;
+insert into t2(a,b) values ('oxqkiabdjoacsroiyoacyblubisxtuhhhozbxzdloiawluwgjnvixarsrmosocuxzqlztaqltgeoesxxkaveybmnntmp','pcbbgzemledeiypqcadigcmcqvrxskdovfpkofdhufdnvmcewuifigfvzclmruuaubqwrxmozeayanwxbzrroylemleqonvnkgozyggcggyvghoydsvcpqinxvuzjtvwumwpxvfemyxuckpdnnsagkwjssptujbwzxfezqqvvjjdprherieijhqzcyegu')
+;
+insert into t2(a,b) values ('jqmndyikrrtnflsxwihstdhiwixjqywdphealfpbrnwezwgcybgizumlmimobapxhtmpbammivcjakrowgcfbdcbsfwihfeugnhueatzjlyukeotjupfvlrrgjrkkooptzjlohflxp','cvwumchrveuduirzpuips')
+;
+insert into t2(a,b) values ('sttmnfbmnfrzwnobfod','tfnwvwtkfrohdvidufiypvdzuynaybytvjgbtsdxckhwqnfmjwybqcmjggmdfbsjufyjflltqpirhyraaehttvyaeewpelvohxtswyscxtebpjiutjusildmcudydmwwmqogmkmsqccgbmkmdiuyukbgcpoogqqfduxnpknacfhm')
+;
+insert into t2(a,b) values ('qtusqkrhnrfixoqvheisxzprjalmszthsxfuunksqrnkebsgpstfieglvxwzhdexsk','zvrwxfsarpmjajtlihbmfrrcafbcvjayrtxqxkzedjnpncwxrbghxyhlcmdctmaekqcvnytkziasucafxedccqyivnadcvnwptixaroknhzimuwcbmwpqlxgphqibybeqhhvoc')
+;
+insert into t2(a,b) values ('bhgqkbkkkpjkdwtgrnlcnzzsdwdvefuifpsqwccztghlrfcnmshzlbogkzsxtbcfraxonhppbrnnyfdprbeeyxhtkowgbyjlcazlnlbae','pkuuxixrjaivctjkeyuviwbdpamebzceicrfuoyyfiwautvmuoelzfpjkkphrxswcyzvdjptpirprpqvyvprwd')
+;
+insert into t2(a,b) values ('nqrsvjmqnhlbmyjpinzcojoqgtabwndzeumxdmbeprphcjlb','liofesmqqebotqvledxvdtodrguzmgbbxhppsdvevlgsagd')
+;
+insert into t2(a,b) values ('mqennehjohoysydxbfeyrvqdaijexsaatowuplfxjcusgbqotaltxbedzzimutzecyanlcjsvlgzvlgpghzplazaitjqbtwughjrghnkbeaqrkiyolpwnlfngyetcvvtudiukmygiwsxihmzgmwdzpnazqrigsmxqwzvdtcopeengfuzvjfyvrewxfzi','phbgxgeajuuugholkzcvlmclubdxyefuoxodwmwfydtff')
+;
+insert into t2(a,b) values ('wtqsqakyhxsenwmqcnjauisipbhbdmfhttpwcfcthnwzhgeiqiqjoxbvihdrgwkztzsttupwkvnuahshpaa','ycgfoyjyqistdsfqpoqxzaajsallhdqnvdqvaqzafyexklmjahtbkiqfwrkjuuknfkklvxbdcqfgwsaojscdwjhumvftpuqkaabllyttsdjylvkenujtnzhhdyowddnnpvmvgcefzcxqiomjagnrmjzypgcc')
+;
+insert into t2(a,b) values ('ihssvgdqpgspvrjywndvlnbstobsdmdngtziphgnethvjecppitsfufzqbdyjcyvzytgudsoxkyercferwnqhykoszbeutwzriyudfjovzuwndpyimrkhhbyzmpqqccaomqmjuybhmbulmhhwylmyqiablivsqmclgfcwyubxaezgjxvqkgmaczrawmuaeypawmrvyslwwttdkeofhufarjy','qtofkqxylmffujopuslpaauiribqumnrmsdadc')
+;
+insert into t2(a,b) values ('wigfwzshawojigkwolyenffukgbzwgdropaylsnvvlhpdkwlhauhzdnnrxnxuxwehviejjbbqgl','xfhtwtmxenwenbakhwgpjpzubhmvndbzolrtdbritkvjeftrfmsdrstnrkhqcjeuryfvvhwxjhshgoqxtsqfslkhrswjxpdhvhzhonbddleeixpmlkwmbavqjcxgtilyqzdwfvzdsqdarsbzmpcyjlajbqwcyzmevcfqbwpfoeznmopqinlkqswifikvtejnskwswcnxhuftqmiybwvithcrhfhvsndtnbctxsysysjwtoiwtrcwngnpc')
+;
+insert into t2(a,b) values ('mbubvxegdppswbmmcyxrnxjvpnigonwphwykhhznklmxoimuiklgdbrjsbantrdoodcjjwczudzgvbamylgfttmatbwilkqewourudzosxxlsvdpbavezcbnqkmnbnsoirxadyhzvfgkqrrzdgttt','xzgdmgnckuinuktzieocdetpkoxkwjdbuukdozcezzjhojrvrlzziofsqntg')
+;
+insert into t2(a,b) values ('macpdyjqjvkvnalmzauqqjmctcumzehgyayysljzevnpotzfyovabptuahnhwlohpgksucgcubfxcwvrqjeqkyozraecoszavyxamhkxuhpzhscibvnjatzjtzyuysrbsmgbcnlsgtsfoosfrcrlatclobvcspiiyquzfojyuur','cxvjdipopffyygkesmqezjdnliwfyehzfmrbwdirr')
+;
+insert into t2(a,b) values ('iqgzhzwrsmljwekhizrcwtjmdsstqdzkpuaodtqsqgvsxpzesablvbkqaeskvuchiqrrdadorgclsbkesaaudhqmftwtbhqnrvztwranqmcgqklbupcyeexlknypchbiojymxnrsivlaczmcosatdylsxttsrvtxuhdxhrhpxdxzqstanbempnqifyd','ckppxcimaxkmocnpuhdgkqwcdgylx')
+;
+insert into t2(a,b) values ('pcwmuehaqiwltueozmcsfbgvtepafqohtvxkspoocercvcevpglicfnjvlnrhofhhqylrtvggoyizgqtuhlwhnwgvmfwaunlefrontedzkpnjh','edaunbwijxwdqqyviprmuvzsqtisdvdxywxxkwbvwwdwqkxctrguhkxwaqnz')
+;
+insert into t2(a,b) values ('rfwgdwiuutdlwfmxvjpvryoubdcxrjuvlpyfeqig','uswzvrfnntlgngsfwtsgvigfzwplwvqkbvomlquxcsdzizvvlhudsuocmtdguwggiuawhnhdhltabe')
+;
+insert into t2(a,b) values ('djecwdyxynfujhwzikkvodgeejfkubehujazoibjyuzhoyaparczdsvldzsqutxercktkdjjaowaxlghfmuqpiewbnaxsgldisxqisvsdgxeuajwakkojignhviccprmmzhgpugvgjhhvhtjkadfssrdpbfvjfxeticxzqopzpjmsbmcppetwqllegrofaehrcyhwuqztwhqlaqhhmzafzpckfaurclgsrxihslgogjxzbqdp','lnjqcutjxbkroblohlqcfouyqowrhpjgnxotxrihsnkwuuvdgenpufofdosrrqtukgoikpluzanrcqcrxxqelawddplzhbqxtbcjatbhtstxpqgqkrutyfocakvpsxcfdmzgkfqrzoesjuvnhtlcirccdpgjhdmjevsfrxdpjmyexibfgxdkojiyqyqzfonzeniiicbqsivvuakzbrxclsxopogppzaoboqm')
+;
+insert into t2(a,b) values ('aitpvlkvckcecazxtvhictanorizqgynqtjqibvxllzenbfnbexwdjpzilxyfadorbxtqknwanxsnsfwfbnhtjfilycyarruizubmqygnptcvshidbogkluycnowzpcsemymtr','fhmdweqaxmpzxjvolgsfpiafxxdmdnelqlznhrstnaorjszkaeqmmqdryowsitxrgwqxdmmxsndhcdardxlihexqrlajzampgktmzkfsumscpwvffetbtigcginzcusnjpwgsnibmkphoggwjpyyiuzigudaaukyvmhytecfudluddgvikuyetgmotpykwbpcyuagaqeddqievbq')
+;
+insert into t2(a,b) values ('fgggjwgijuqghbpybwwambmhotnriepiljlpjgntsbmdtkdcalcszuzplmhyxherapbwqpvitxpiqtschsjmqluhlaqiuckyqowixsdbgagyslmgwpnrsienivpvtpknwsrnlnbtosenefkqbgvjmunfhhovkzafpzvjkknxhvqfgeumajwbxmrneqsgxewbo','mbhxmebdlitmgqntztijkvmtqgewqzclxivxpgnttzmpmoywwrammdflfbzjgfoeblhtjzyhfovvbxrxhqlzawiugfnwfnrykhq')
+;
+insert into t2(a,b) values ('pxmayytvhahzefpnioeolmxhbmhkanugzzuadfxpcqlldnbatfrdtxghgcylnifyycbtddtxpkhhbzzmbzfrpyegifvqndygvtealczvimkwxcgivxfbzrkedvgluzy','aphylpwtpxrlqrpavbfxcncdfptepifjgmynbzlodbprreymgopoknuesitkia')
+;
+insert into t2(a,b) values ('cyfgpaveejwhzsexcphkyymhovubyhjkddzswtwiiyqfwnvxmkiavqn','avviefzbdyhpondddccz')
+;
+insert into t2(a,b) values ('jhmbatnhnrzucr','aqbishmvreqiq')
+;
+insert into t2(a,b) values ('xhyfotvqsayolqrauoyqeoitghsyzffwylqeiaxsqewncsupsbofsygakszojgrlxpvtlalfpbrmzjzylhidvybcaeargsyycmgqdirhizotfxilpftlflytcnmgcwyhvcar','vnsnjlqlmzbccsukbosljrnceyehftsmjiyhddtgstjkddlafesinyefpzihgrngaohcufqnncqdyabrjqttpvcsqdeognmbdrfrqvwmijhlh')
+;
+insert into t2(a,b) values ('fzah','atifmoidzgzmvvzweuouexyriujakbq')
+;
+insert into t2(a,b) values ('xecxhlkkponjylbszkybjkzjbynlkcqeshd','hlxvcchhhrxgybvkrnnfsehdutlkvlaytoffaqyblyuidtkijjixrhunkdbqszqjxpvzcdjelfzevajuoaehvuwxetgwyeneatplsnojqhtsbisseramcjlciaooiihdkbgthvuodwpeehwyrhfirhxnktmhrvzhgzyqb')
+;
+insert into t2(a,b) values ('uojlvzglgvobbxkhqzpfssheswbqekzgxrolmyebndcrrlblidkbinmwtkibjcaktstpbhhsxghzvdgwiljhhohlxsndvjpotzfnbarvsqgyptbqkorsviakdjdthfmvirzuhjyznpioslanhwxhvjdsfeqstqm','rrmuoqxgqihnpnxjjkgeoolyvzdbiyayniwkoaxjnbsckkugjzsqaxlbzzzsnrksmejqjktivxppnnpnihukxtcqkglmyzsezhtdzybrpbuhyolifjdsdlvrlpcozuhdpuhnxwjexeixklyhbnyerpekqsibfnxrawolddgrezslpqsqbrfbcjxxxbsaykoivnnabexeuozwfqzrajkzhuavtxvcsxjcrrouhfzmvfjsavcmazwjzcxhur')
+;
+insert into t2(a,b) values ('oquzstmipcudcqtchmdpdospcjhvfieclveztemppicdxokfrezlpmxykgrexvakwdwcxmoqgtvlaoexg','svhbwgvetfyspritjrceisxmzcfvb')
+;
+insert into t2(a,b) values ('emlolndttkqgvhqkcybrfiidsbqxaddumozhfpsvtcdkhrcdspwojwlekxjcasbefueogcdervjjimafkrvexibkjekhyhyacqdgywhqjzbjfdddlocpwwpngksfmomzorgkghoadvmlrbvgxgaqobpex','lhpjdglrhygfcfqtksny')
+;
+insert into t2(a,b) values ('dtigpizbllraaktwansllpprcdqywkbbbuuffffditdnp','vvqmzsoetxvrzlxjlicgjjsvygfcqhatbllaomfzoelqsojyofdtiqseoblbtzqocxzpmmkovgkyvcqkmmthlnlicakhtlzqcmbcwsyphguiilshubvngsnrlbrhqjtthgagazioqhhhgjtmqqmh')
+;
+insert into t2(a,b) values ('nnuarunccbvasixgieligyoqaeuungxcdsljrcdlygtgzotghnrhmpgtntufpdurwcwscmptijjxqb','mzhpkifikhxztmgtpgzffgqpzsrpsjnoqdwhlyzgiczdadgzzjucbrhftcaxsjuxadbalvwaycybpgjjamewiqvmipsrmgecejmoqunzqbemfxjlvoaztufospmvtyexmvxlhzaoffnyhukndyqvhpbpxgzhcrkwtktvoiimbsjxofvuwcwoqxgqrbiqksqghfpcfsxatnqlqikddhsafgbxsdmqsmlbp')
+;
+insert into t2(a,b) values ('zwsdrjgnafxcerrtpaiqpr','ekpdfjmjvizxmlvfwatuyuigvqrteswtjmxdnrgddghzwuwqvpsfdmfbrfoanzmszlzcavhtuxalxqauoexlxwaifszqxtragcgknmdsnxystqjfwthcwobgwyjctndzwswnexinrsjqfvdzxitutoexyvldumiynlmmilsuxaqzbtolftggojdrfvorcjacvqvasyogkvrvbiuaznhpyxnvcsnmmmw')
+;
+insert into t2(a,b) values ('jjrgbntqjmrdhzzvhewjbuekaqsujkfpltaxbyldqqcevugnalpsrktmioedahzibqvkmnedtgxkrxejgozgacdxtksrxkflaldncocknmllbfkoaxcpam','gboaosqehcqy')
+;
+insert into t2(a,b) values ('oiyilfhsasunatqjwvvfflqjxkxdrnbfdlbtpijbmxphfvzrxqxvqmzgumckrplbshqhjjlotuarpikjvhwojcfvgbkwvyxnlnlfqbpnjnxkrtupqbbbachdltuncbvfqrqanohckhvrnogtcwmyoqnjzaaincxmhhbepcsdbdiayfaanjjhdzrmhtwasvbcotvchifzkelybymareujgtvkjurfdtklpphpkmoagxnennvikkxbvrkx','kwyzzjvaurfqrusyjdazditpshspyqespiaacnrqyxawbknrdkfjswaqmgcqbtzljbqbplkjiveyimsatgseqirnvtdtlmnudzifuqbkjhyrrhqbivwiuomkljqhvjuexuveuhpvzkqriufjxedbjdymiqyuzzqdgyfybbaylyagutefbntrntlxabqnltlgae')
+;
+insert into t2(a,b) values ('fvilrzrchyibazthjckuupanwhnqomgbheckdvmzhstktchqsptrerripwnintiuijzalckjnpvrdpxynxraefqgcuhfkwaaidheecwdzloxhiobkdbexlnzmnkmujntdjbegglys','kexhhanabbfqqhgivbvqundkigygptvkmkaeexhzubmgcgxzandunovaioeilrcxnhvticstifylpuqgthevgxhctocuzwgdveykwjbadceclkmvwrpmdlarcsdqfpxgjbkwtoyk')
+;
+insert into t2(a,b) values ('lwlnhsgvfocemjeoxxkeeyyqnidtpwxwqbtzakylmhsreryyojtzhunenracoaehgyeoousfrkwpmzezvlalfsmefcufqoykafamznbkkcljeyaevsnpkkygkvbypplqsgltfoayeuckcioif','fgnfwgboelkzwemxplbbscmyqnpqodyfvhawtkttkuemhsm')
+;
+insert into t2(a,b) values ('kqaimsmrlzfgbkurnikccpjtungequgdmzjwfqigmxohhmfairgliptoqsojotekpyefzstpavahwigtxwunnxdxkmgarrwxeidrsqvwlftvevydgqeumlvvykraegvjuamjeubcjhfmzbniqzki','mppiddgmpfgypbsmnnenzjahsohpazuavkbrsfjxaonxcbibfrahvewrejxalvywiwbiyfwwkvmuahnjsvhbjjbvojovl')
+;
+insert into t2(a,b) values ('ysuylzzlkcnucfufhkzjjif','xvbcxkidwrznbitlpatgigdfkweuwdnxnhlyywjhxwymrurzbtmlmquuqetvveolcpqyeicuzaakktsfzdtyaejqypjvqhgkjrweatwgthvbqimolasaiuyzxcdggjmandzmiesyxukj')
+;
+insert into t2(a,b) values ('zcayrqveuqbdakwnrqfdhnausceuauljxmhwuzdzkguifqzcndrtptazgwkyvatwwasxlkzwupvyfkqxayttvefaoslbuqplavptdvrclqsvbyqszykaijotwfgabhncooblrwcxohiqoopltouggdogi','rxwfseqoyrqlhncfnveidjavrolqxluadbxxnqamkoswjbhlkzrmzbzpanyzfz')
+;
+insert into t2(a,b) values ('gummstvvldysscdpbhgcizomsql','fheugvqssevkbdh')
+;
+insert into t2(a,b) values ('mxbgdqegbsclbrazjhhbflrbnlqnqymblvrakeqrmlcktcxxitksjexuawvanjptvtnvycgxlhaitmosritbfqvvafayrnewytvfcezxlirofqnueptawflcwtkabibxskysxumwxpsvkebklgykspwlwdffqym','tkhqkyaxlutrqrefyogiehjaxtpblokczufcdvsswzdcjerb')
+;
+insert into t2(a,b) values ('xfeyjmxgfjcx','mbtolzimptzszvwmivgvgjieclvltvoxuoqadpwpybmhxddjaeozirswvuhjvdejyfgrkoilimiwttsvupuowecqngtkyrdssxpdmebzlsnlxgvwdqmpxkzgwowhodtunioptsnfugljmcdgobajxyoptsqkdlqhzrsxfszfwwswqvmrgritdkxrccflihcbtrkkiihxdklbkeefcfb')
+;
+insert into t2(a,b) values ('qzwgccmthlfyntfsiriilicbvwogjjzrctpvzzyasexbibtyhnxpfvucvxldnlullz','qjjhvruwzogngkjykjxeexfvvwwdzknbsooagbveymelzobbgyxblabzoitsbzwtevsvsofrszrghyizludzipvafaimeptub')
+;
+insert into t2(a,b) values ('wemqsztqxxzjnzevvylvzejlghmfpifkeclksxflxnzbdmoavmnhcpxppcpyauzypwfpbxjkldswrdehimidycjfadqbkxmhnrechfekimmrpqhsaawrynzfbwvlgcgespyzfsbqqnuyainkugpalblmbpxvkhbsnanxkqsroioshbrzqspqtlyyuxzzhaaqihdutiiugjzadlsuryuutjcmcjlhakonrprtlmorrwzibsypuhvnctxr','mzvnxnylhhsflsrarldgzwcqysjzbmeictyursrqpjdzhsiptdfqqauqapwmpewykazphixoehhnblcjcavaaplhaanmsdmkkapkbxlznqqyrtvvfipyrauttfvebovanojjhkmedgsmqntbjehqruuiubesuhuegitufsaglgedfdasjofbgznqsosyapvhipblbwzyzmvkyvgjypttoukllidrfecuhukvzjqzriq')
+;
+insert into t2(a,b) values ('fzjpxnajjjzqurskugtkrfivqiqmsqzeowndlafmtexxpcathiswgdqkxfelsaiwzvexfzaqbedgyknxunvntrcqveanowfnuvccogfdmofzlwjnzwplnlgsqagblilrzvhqfxqcmzjt','svwogxzuvvhcgmwdammwgkhmjyduwhbxmbzkliftnzmiymukqxotzuzjqfwrgkdgcyaxthhlpodfpiinnzjvhzqgjxxjerflwmczcwcsfqtcydzmwwpchwwfwscnrrlwoooifcpe')
+;
+insert into t2(a,b) values ('nhuhwbyoadhniqdwzdufhiaekfhdylqaaltlzgfq','akrzzeyjuvlzytezmznieohfwydzddihjcrovjpiqqnjghytatlxcxdpqhzspuxucnxcdixmkqgnyewoyyuwvziesevmqfjxkavjboxdoraxfxavymvwsnxbeijuqzfqu')
+;
+insert into t2(a,b) values ('gyjngvupzkndcuenusznthmvgoykykarudyhapcyoxaxcgmahpmziuufaknsqeqvjsbdwanooilxbpovzyocrsbovoraklsfpsyjzxstllwkdrtplzcbigfcbybkasdhpvjtezmwarrrktlhicldokjkdvcoqqdirdtphopgggpm','cvuhfahvtqnbfnzmumgpqnbwrgiskvdfvsaxturgaibpbxlbybiyvcxexghyicg')
+;
+insert into t2(a,b) values ('zatzxjwyaceiossycelresxxv','gozirufqwagiuwpscxqmpoagmorewemutnjujdlsohivjwfgmtibahoengqdcovngcojqtzsybfacaugnfzaehcwypivauidcalpesinljosfpdoqolnwkcqqaaicxsofdoctsfwrebmapmmgvegosjvqlianzgjzihhlnprejmhgfvochimzhgoyzwopqmlyuyawktmpphwfedqafjwrfsxdwqxcbfkbsqyzbfyiouufezwufumifyuedc')
+;
+insert into t2(a,b) values ('mrndzanagmuabmmjdsxgjakctmkvtjbpkfjsxjxyfubyzkbadmoptkyeifrbqihkqoovbxbzdwiglmcxsvzrkgzjhuzfkqzt','vzmqzzokejbszsmotqcudrtezysuuzujjgftmhovbnpttxkcajintk')
+;
+insert into t2(a,b) values ('vvnmybqmzauefbneoefcqemyiqtynsadqxopuylvnkrpttecesxtnlgcqrgogfhzbqqmcqzuwxbodrwxddmvuerbnlvxdvwhwowrxsrskygmugwfsntbdgucarmjzbilmcyrezaxitgccldefbsjzvfvucjxayszbmtvne','szxfyoqrhgsyygblxegppziaszresabahmj')
+;
+insert into t2(a,b) values ('dmtyixhxjpemwzfsmzfoduuzeoejcytcpwcnrjmqkggtctcckazfwnuakhnuookbwgpbtzqjevcgawgxhjozjfstouoissiiflmbusbdqzpocameeeupcfmgbzowjbkuihgplejhcxizpxkdxpajewcrziuurukuxbjndnyjwxspeakwajkuxvdpkzcbjisqywvhhmgtexmlbgqkaaxjzddbwkvqugxovkvpnokckhtkrwusdhroewl','cqnzuwjovucsvhuuhedckattlqxirekuslumzkovppkdfivhstcmlxnqxmwbejfkmreuqyipomywqxfhpwulogzkndgvftsfnl')
+;
+insert into t2(a,b) values ('pgunjrshjuvvdxljxepwbvqpfdugzivzumrwauvfr','jghxsszbngtdakmjponeqdbskpcuenjmthwbfowbqdlvpmamzhaxeasfqdftwbxqjbywnddsvqqiibkmlpqcrfuvmeahnottoapqpgpvvuswjtxkmjnplitxfcylqqxzqnyalaqhhzgpxochtjciupfgxundoviikzjxmxjucymrqwwvdvtgzsbprfadtdicbjldpxdamlc')
+;
+insert into t2(a,b) values ('vunskcqjxfyzromehfqznddivlfluxiwopzexqhbllcumtqgrzomgrhgsobhfxjlsjmrbvzsldupfzftrxxakrzvntibxsbkpbfhwmpghupwlte','vgtqwytxzrwiioslidtbswubaoxpbpumaqg')
+;
+insert into t2(a,b) values ('kqmmwcamysjkyypufnofkhebopnysnyrqcsakuvxyaaekpgdrilhvymsugxionvckjcwkphtqg','xsskvioqyozrwsztqixheognxoevepgphashcpysazuhlpchtguykacrdlwyfofgfhmjxzndlaomrlfnetcopednqywqnuqnqhqkajiqdcsjmnibdjavwdtjthhzlbtescflwhwpxdwjfbdgbhjeymwqkbsagqoifadzcwqqmmprxgimtttwpkyplavmuxzetcvmgxpuxjcjgn')
+;
+insert into t2(a,b) values ('dxeckshivisboiyqkwshufyrscsvfkxhsmizxmtiizborixjtokqdtmnwxeyjwambooaygbrtvahyivqzdhtggcmxjaipijvzwssmwclgxponsbsvsbfxzywamdydfmobfvaxtwimjhoryafdsulkuadxebjujjsmbsrhxvkmoxnmlyyqdephhqvnkjzaclndarqcicxmkhleslbglqyyvnuxjkizuvmn','za')
+;
+insert into t2(a,b) values ('gvaxcsawzwykswjyiinyylsynexwtpmmvcspvjaahmgagzyirdldbieqnsqxcqxtzljeisnexdqtrwxypermhvdcoeabsyhxxwnproasaciwxzydrccrkfibicagdklcagauunnqjgpvwbzlponjufnguckovmlijgohfgsrnmjhhrjdakynrwiwdiekwfzqxcgxwmuujfmikyjmkuzgxyxuutpgtosszuvvvbuoobzeapobjzahsku','czaxhqxuuqqreybgifzpphaoiqfeerarnodnsoudwdzrsrxuapsrunfewnkrmzofgawvmviphniikulqebtrsoshkongjfpzhabipxbayygzeweqnyzztnrmdyzvjlfqijdtlfotcczfmsmcocbvnuljtevvfh')
+;
+insert into t2(a,b) values ('afscerzogtdzwkadqurofoojuwnhyzhjjzmxohgxzasbbnrenjiefkacyovrqsktcafctxdpckbocoavaqmiiqntarnqpotnmyavlsgorrambkdtakrnqwwyfixgvhxrmqewepdyzorgjoeqgtnifnnuxzgwwswfvwrnmltwnvpkiabmxqidsncthfuwnehehaxzqfzuivmarfarsemepjolrrzcpfuv','pxmavkmlnpcrxplynycseujcdfpbyftxeuqzvuqirwzghdghwehtprqjtjnklujgmhdgomnflywuvrnvrgzrdixpyomysgbqnqwfqkmwfbilgjnbpz')
+;
+insert into t2(a,b) values ('mtoaifiomskxlxsnweshxxuchwlavplhrhijuvsakuqfmyynosmtghkdcngjblycnxgqzxloexxklimnrnnbazwmgdachycoxivizpadnrrsnfccuhbjowknefdzdpatoizspllqwduclajjnccdtxevypyrgmqawlcajatghknuoqxrrsbjwgmdujacwlbpbabgqtteeg','xxiybvurkgjhckejrmrpflfzocuaimquraaicbibkdnsgfzmcubtkjiuwncsypjrkdocsurkxdqrtsfizhvtptleuqlgftktonhgqgsoihslsyackdlvfdy')
+;
+insert into t2(a,b) values ('prszaawcfocpupjvdtqrqrpqlvpfybdmhqygwqorookonhyhxzyfpkwsfxbjfqmljgsihecvpzwidntwgkvyonafzlzr','gmhtsnqrqetalsgfnezimlafmqeaeibescypbarhictmrerqgbfjnrjcvvblagmkqrrouqvtlliqlhoptpsfuwnaalomqqtkttiwanmrjukiwsohiglycaxbpcvrkcqqklaghhwnbvztogthvzxligbzbeyvgchhfscvetksxzcxkjxkqicgzmnzgahpngvxuqmxrfpxemyuphpoyierksyhjgrjaoiadzfvxrdfscjwcnpjuyrmd')
+;
+insert into t2(a,b) values ('axjkcbrhjwzuarvrmjuekyoswqduljduxvekeovcvmozyiaunrlchjythknlaqippkpccpuyyalocwvwdrnxpsiepulclfxhjlgkukbdjfvdehzdcukhrpqzrjobssfgfhcurgqpvlzcccouoirqbbbjewxwzmlpgh','qodinxpszsoinuuxocuotffpqheppiciqofflahuvqwkrtgjrxwipcvxafyswgsjruydefkprwktcoslkpqjyqjaouvpheflfnjmpqapeaqbuyylymzeddmylwsmzygzfrakkupeulckowmcleoyxpoozsvnincrpguysodnzpelueqvvjmvjjiutlvidct')
+;
+insert into t2(a,b) values ('wmvfndyubcjenylnkttemnngpubzutuelcgslukubunaobmorjludjfwvbzpvybhzhernrainmapshsdaprgeielhvwktnxvjmjylpnyemkrpldhweqpamqoyziqbfazgrrpwvcncvyfodjrtciacubuphqufhfiucwijkrzcwufwijdcfdjegbtyrvkhwwrdtaukpkikpwbxwmwimuucbo','jvbbimpubyppuzdcmwwfokhgwfzdbpuikdymnnrzclxywosfhhfqiuskgazhpszpkpfahxitijpkqtlatln')
+;
+insert into t2(a,b) values ('ihmndcdsgvekgkbrwlfobhkljpyfcsebnirbcwylvwyrjxktvkkvirtrgjtizjzvbdhtovsiodbzxdmroeldlrfdbtwxvmckjxdfswzddzspvdgocetowkykmtyysiddeakquuzkiwbvcadckomh','xgqwispfwfezmgdjredckyiujcjqxipirymmyakdvguwqppvfqtocsfyylqglaxwlhithcorjinhljdrqwjiofjmisrtqwbpwvsunngqvpdhejafymxqbjbsshgxnpdfteirbhlojtgapwabxjntoxfpcwlbjpwuzpssobotzcafbxldmflzbiclsdikyueezzmeoeidawzjbwnhfmvgequkljjotqipgkzjopawkclrfmwxyruasay')
+;
+insert into t2(a,b) values ('lzmtufwoyqdgoxfjjgjathgzjpxordrmsfnjgfcpfdxcbuiwowreqhfgqdlixzseppzbcryprecsvwknowazcsyxvldbavwnmekrodpcuxubdzrmxrpkvwkqsodpjyeytdqkkvhvsibo','qetkkuxmwieymcqbafqeenasadmfcbatehoymlsvcbqvtetsgptaqayczswrnfrfnvvmwarlfkcgrguygwzcwikrfajuylorhyhpfocgiwipgzfhiqwzvbnlhnumrzwoywxgzgfottlyoovilqhrkkejhesjfszeemuhljmgomnfzkkmzwwbmdxlvhnareyjwg')
+;
+insert into t2(a,b) values ('xkahjtkqpcexycmbuyeozergqlgljpuzemluealgyfndnhiqqaqpymcdismqqhjuayunvrkktecumyykzxkwnkthnefyirimfgrnvnwdthujdxddlnicxrgkukqhdbpngnsspcoroupeommshq','sfmmxpokatnoetfedacxpmmljdlezkxysdcrnxokzczvlxhhwsbxtlklbgkpqsvnhjrkxnjqsthlbykhdqcaxwtniqzhztlklrzvoclyfmeysymzdauscurm')
+;
+insert into t2(a,b) values ('nvxrivbwnxtuhmbasfoocrntoycblvouzpzbufkanrqlcfnevzfugjaaqytwbzwqputvcuydlgiqmugcxhatdatevpdrorxtpfnrtpsklyuxlgcwjmgejvek','piuznmzsnfogfzyzrrleznqdscqdnjirzvrhklgpitrmfwoiazeehvodpzq')
+;
+insert into t2(a,b) values ('bxkdscvacyhaobtdhveqayideiwtoeemmvzccamnvbwwhcocskiedveobklxnqzcqdaejubbvlizvnejddxhxdekhxqsqooppzjvinuihiudgyrmyocwnoopnlwuunrqxxlzoykarmfloqogzxxqjfvizvrmivpvnxztrwdsyjpsnghszifcjanbehxhopqcxxyikcuysbjofxweafiapiuqvzjdv','qiltqhfowedstosgbqzaqvihszqbwmgpvgfewsiqqkyptaccaxnellrltjbetdoauryspbwbtqc')
+;
+insert into t2(a,b) values ('slcslkgmtrheridhtbosskfpjayibkvhmtetqcufatvmymkwh','gsaouuouqvhqqtlyuvluyazfoqnwqwsobxoznfpanmiyubcsejhruauotvwrspgnvdjsucsasewdiwfezbcygwkqxijrnwtqgjkphknpyexrvlcxftymacevlbnkfdkmqcdggxzepegccacxamaneqrkxbmamflsrgizqrdsiipg')
+;
+insert into t2(a,b) values ('nydjwlepiiuamzmviyyvbmstoocpxelrvxqmpquahovzetsaxuipkvdvojogojqzkhtljsa','wjfttgqpwphjnocldmecvbexjoecuytymgmzymnvtwrsdaxktorwjlyramtcnxgritbpzfkgztmjotpysxsgxxhaazojcmvyfijrpn')
+;
+insert into t2(a,b) values ('jmtwmiviawaipgybxvmgenzoatryrmghqtpzhvptswhdsalhbhxppxhcpikrnwmjvvfewtmkpfgvomlhimjmvcyplympsqyntepmfkytvylmrppywrkwfkvewljkzunckuvzzpwddrcmcukldgifqktefpxstvnztetumditnlzhpgnhitw','vbsovhcqusbhviuthzghybwpbircglsttglqzlhksneyznwzhojcoffmmrldniyxatebaalcvvgikixdauojekhstpgbqfzfxcouhavfsnxjhrlygzjutktekhwvomvfchevddduokvbnjlneonsddnhtcfpjuxvcndybxsjpukxpyenhksqsnhsqtrpmxqdgnfxeu')
+;
+insert into t2(a,b) values ('ozqxtphtiahmkdhssbefvbtgcfeqmymjzabyznuzbmgmufhdejzwviyhydodkrexfyyrqvaitcyvmnkbdsqirnwliwnnjwmvwhnwbalaadfkddilxmakstrhlyechbzggballwlconupbgfvbdgyufxnkqwfkxbpdajtwemcrmnouzaqyjawuavdyydnhmbgfmljdpooqqgcgbbacyvzcrrqysonyumbfpaghewktbosicspbaustvm','rtjcvdtdjvnwjzitsnkdnlolxuvtbxjcpfeliaviajlzkvjkudlmmgobngytjvdqannkbycphmilsoqgydupnxjoudkinslxlyhacwgdhgbvg')
+;
+insert into t2(a,b) values ('ylnnwzokmprrzrwvsthjhnzhtfzzgvsqquvrljqreoevwtitskpbuobzmtkqeuuhrnwxqyacxazuymkcwkpjrrgsqwqlmgfjykpnkgotjcgkkveooticrjihsdqqghkcnpqvzfuppkuxdozuaxfseonidorsgnjhqmfpxqmipvgjmzpkqjpg','uxreztdarsrcgrpb')
+;
+insert into t2(a,b) values ('ntjjfmjpunupsiasbxezo','iptocwdnrtatbupwzaooigzqnaqilfreublxbdorxqqwrxbakpocozslrijcj')
+;
+insert into t2(a,b) values ('mcazorshinoxortcpylmxkufakipdaoryibl','xgnxidhbjyksv')
+;
+insert into t2(a,b) values ('hsnlmrqvvpzrqjbsjhjvgxvjrscukdqdvspjvvisuaotqzxzdfkaklwfzgxnmtlllgotdbuvzuegdtgnwydmacruqbwnutceevfnoxzkfvkxuxewesdyveseodqzhpbvwjzqsvwnuxvfsbvoysuebkijueetgrsvitevcztgitdxrqkanduljdxeeoyeglztgnheroyunzuuqrk','jsplfbyirxiveqczohprkplepojvbuwvoupulawarcqjsgiondonsxgulniobsihrzjqbznydyqjubkkdobytivldcsydurohqguvnaevfxvnywjsmswmpcyvmrbmsbjnzigoqqlzfexdmlbcvpkibcvzjblrlqwirbxzjjqhyucfncjosauviqfzofjidaqqbkpfpiadfqyeayu')
+;
+insert into t2(a,b) values ('aovpniqasiufubtbeiwxiymjfnudcjyqgmxhsshikecwvigaicyjebzvgzypowavrvqmzoznnxrcoclwhinljrxfcetgyqasixbnntsailhdothonqfjdnpajatordeffzsqnjljlzpshjlcsteqvuzjimuaagngsfvqsexxrzjqmllywmtbhqoavdbmziegjaputoaxnffvcewtzbwoqbnrahhkglfaheeksptiqenkucndogf','lhyecwdarzrwymjbajjykuiejxmkpybbmieuxenvkgcpgoqhnyqycsxwdagipekgruskmqusejczscpmsmqvmlmgqosvktbtndgaruvgeuqosavlpdcdrsmevhnznxghpduwjwnqzzwydlvkzrbyititdsiomnllpauihovvqndyaetqfnjgyvbxqbgg')
+;
+insert into t2(a,b) values ('tkjzilpxtdwwjmruymmechyvitmvnrejrvyqnlepyccvrqhoccsahdzystpasuhvqywevmhjlnpoafwaihljgwiwqszodnzapcarnlgifgvlwnyzlkgnutorouwelaqswakzcwhqeknxkehiorizpenapdqosiebowkxituiqqek','lbyyvvndimwkcoxshphjiscrigoeihasxryapytmubdcaudhpktathjntifklulzevatrambnmesrxzjtxbnylvbwkrvwjotmjdrtyqouvwex')
+;
+insert into t2(a,b) values ('pskodmzmlovfumutjzixyarlfwnprfommqlrjkfikwddnyeynookdtfgnspwfbpbassxptterkwschgetmujsgsqqhasuyyismwjonzwkdckirqflmuttxzyiftvayqcpnajzdcfhhsnewusohngbxyaigjqtzxvtqthwjbs','elaxlfydzkthktghgkshonmasgkiqemezntcqbyxiuyxeqyetuqcbtlvbfuzdzdxxghwgddhrjtgkevlxqeefenjaujirbcgbolqfjokhaqdmlqqsisukbrpxrtmskyflqrnhacoaweekgivheaqoiijwbfwdjjphwqfrzzecdlugcqylmtkekjw')
+;
+insert into t2(a,b) values ('jufdneeexhkiagsonpusisbsdlidbfwcuirislseabsgynkwj','magxqpsgbiegbgmchahoxyxuaffszimxkgnzijeldtcydyirmjypuylklfhugvauolbbaejquavvkfszejuyyiobncabduhjtjfzohjopjvaslqrgqiyftiudkgpoiqeuiymqxnipsqswablvsdtarkwwgopqptfxceezdoswomtgseccbpvdnfvfsxbcb')
+;
+insert into t2(a,b) values ('hnttygqrsexedgdilhvyavznbopbfgkqtlvcdexjevsrwawdeuxhibogsmjmoavystsvsfqlmoypjwrtvlhihwxvptyyhptqrdprlxghppbbqwiwdca','wviobjaifjumccvvujknooisbacyqjolwxjsoecabtfaskpjjkcfbzlwizxapbyaefpgjbbxyvpnqbwygoo')
+;
+insert into t2(a,b) values ('dkjrjtxqtqraqirxaoecilxpzgzrr','ounkushmiovnqijduirtfnoxusaaapxqeojgkgvxshypzszwvqiunzfgoxmrplnveeyoilfcqyucfusyhltewseqknppgzfagmrentyylytaedyiomrysqbzusfpxthmrjibuapthdvnpeigwtriejunnbnpxjkndatbkgixfylseeuutjrfkbmkvtaryzyjisniun')
+;
+insert into t2(a,b) values ('pfapsgqifiqkzalbscbsjlbqqnznhqanfsojsfxezacgdzxvtkfmgxrcqhnuxrdrc','feaqvexejnmqgbxogzfqvckeovtnuimgxddcyyromhwxrlndpaxqinsmttikovdxdaesbsupsxxlhxyzuueqhaapsfepzpenmgnnbltfmhwmqmakgverusfbgdkenoikafefzowuaezlmjtnoetmjvfauvnaqgdvcksiojdorb')
+;
+insert into t2(a,b) values ('mgkmbnuwnsdhhvbbuu','lwrrbpsymgjghksqvemrekxtrdvgrpxkcaqtczgttduitaddzeikxwxdtweuagawyecnfleqwtedkaminmfvtobasihwhsnywttdxardkmguvaufngqacchoxzvzhygoohyrqbpdryrhmxvmhbjtuojaqrgeadstafumebwglbcpvmcgizvakv')
+;
+insert into t2(a,b) values ('nebwhyrjttgybtubkbmiaieygyzguozdesrubtvejthswqhvezghdpnqyaogqfpzyenuthwdkwbfsbouxsmbiytcrqodorcaosjyxrckoitlufpmxjgnjwgtwqmzhikvhwmtxupwwnesodovtyfytjqxpicpsjvhfocmjtbhozlhrubnfouazwvemcbrfbfbwxmhoxilewnjellczsspdhzffafindhpsouzejeznchythawlyhsxnbceizbb','zzxhydhfwkfftekoqeijmmwrskbjhhevkesrhcsfwtorbwaoxzylprhqeeyyhpynlvhutcasptszrfbgiacmwylvkwjlyx')
+;
+insert into t2(a,b) values ('yzsnyvkmmbllzhlanaqgrbfknhvikttokdeptesyabglrjbfaxqakdukayjpnw','fawzishhxvwzvaznnkpxdyaofackwsaknkpemmobivvuvmycdgzryjswhsslgndczozhjesyfycgyyyzzbbeudvjnfodmsuzbpxsmqpmzwsdkftegiuwvaqlykwqzqylxpnruulzqsgxpdknpzrhgxhsbadsejntnjmutdwkkfgwzwsvobxzbmptededbzeidusifxmohehenmnyvrqlnvky')
+;
+insert into t2(a,b) values ('yvcmzipkmlzqhyqlymfdcxuujmxxugrifegqqgtkozmzuxcdlvohjycodgqhwaaqvjysavliditdjyxpxskuainewwnkyjwbqjodevdokzbahnqhqlkhmvbhfbbvdvzhsfmmydcexkwdmkqqmfgwqleftwikwicgfqbilefsudlajbfwfffdvmycwdzomqxhbcwjatuusigtxgdrb','adzgcfbdfeodlcswyftktzmiqlltmvsbydzsobomhhptfstrnvmgfipgip')
+;
+insert into t2(a,b) values ('ejgaxvjtgmyfqjpegvkoifxeydnpncygeutcd','urblayuurubdmbszxgsutkagzwhilmdcncdlgtflngvocadfiixyt')
+;
+insert into t2(a,b) values ('fmzzacqlqxpfrfycqsolnfljdbvlfhkzpjfgekjad','sytmwabfrutsjinchupfxwldorxyzwzrzhhuhnzidriaqrgjstwwkecyfgnyadwwlncylyjawletp')
+;
+insert into t2(a,b) values ('wtffodsuvneclwoghdiynuhbmxibucpwyymcxgjisvklepdyzzxemtqowzrvwcisaltelejwtjllgktsggwjmtfapiuyzc','dgigchoaikruyeddfepgpjzsuikmkxwzmnwtmphmcfagzepbegkqeohkvywqmrzvilkhuwtkfmuzxkzwhc')
+;
+insert into t2(a,b) values ('xxzgewpivkxwbwamrjhtwvovnqggesloowooqghfiilkvgnrxoxvkuerqkdqkowonkmvttuymxpkasybklzaieqezvqtdnsgahbtqigccsugeiunwlnejeumnxtjrwaxxqfzknwgazsmcklwruojcpnevfbwzejrsscnwxtqimpqrqmlugcxeediqs','ynmbfsplhmtlfpjpuzoyhbvyqzzkkunivekqgkwcfswygsrglozjwciljcmoevkedhsnkdwkhlcohzcrdpjuqbtooybpulglbvcjrssqudrqqfjvrmbozivtbyspcaamxtqyrazjpdtyikviugtbrigwtvpzklascduwwzifwnqtqpzjcgnzsdfqdewpwmxaxegq')
+;
+insert into t2(a,b) values ('uqerytzfdvxeeoxzdaqscfggkxedrt','jeztgpctfabuajcesfpbn')
+;
+insert into t2(a,b) values ('anryutfedtzgboxsditapqagefcraclmnzsotdfpilnyvkdkowhtcmsciidzzydtpttsadwtijrjxcyfoohvexfhqjdsgcotlkgphatvvelnjbhdxybzhfvchynka','yriqivwmcqpmaecyukauprxfmtdqtlhwxmpvhrecvvfxhoxvbyudnfexilzrmpjfeouhceleqszbdxibereuvcuhphjnidagryszilncfcbuiyxuqheraevedagxueqvfvocpatvmlwaffsuxttpdtotueibjgvscsyotouwdctztmlsgosvqykelmmiultqpfjelwcqiokjvxnstcbr')
+;
+insert into t2(a,b) values ('qlnijwnopqcyxwcgnsfjlxndduruumsgdynniwhvfavbpdtulcbcgmhbageaourkpioibtzvyijjxqkqkmipezstbpw','tiyiuftlgssinwsuxiwyyitssawapkytldfyewvpvqpafzloysiuydizyqnqepimstjxwtucxuewaqhsjxjmjnlisnxmcrjkupfzrerqyudomvbguqrewvjgougygboztyvmbbgvrxbshkwukhglknfmfmmhsgepsjsnotojcrwpmpmkczo')
+;
+insert into t2(a,b) values ('cjympbcltxdyotfjbsdaqjaafromkdgropfxbasogonrgqjtbipamldbgrmoepzumeenijjaqjkzdhwnvapvwtowqfkvvircjkcyoqznatrikoufugrcswfybzjokaysdcsfvlskbrraziloumejoxwbbbzvmdppjnyy','rssusoychpmeeprgazgegbgsipnlcjvbrmpiqurvsmstfifnwrjatjtshzpmmvdpdruornqlxzsvmcpqosooyiisxykjzceepizdovemqszmtrghmukvoenoggsuoubrpkgzlszvbxqyfwbxzdgokvgnmuicairosmajncnmvbifymdimdqbtypkjnrycquljnerwjnxs')
+;
+insert into t2(a,b) values ('nkfyhguwwilgscnlcojhmqgpnzvspqveqhyyrvdxkhkrfjmggwbuowihuqyybrxgvlbtbswzngmcopisqdbzeqewahytqnebbcbxesrsebsjecfkabnexuuuguuxmdtbpapkqqagnwwngnkiejwaanopugsypzkepoomkplskcbvyllstlvgkhlykfurvehtdqrfjgjvrbacnuznfafkvpzczwvbagowzrclzuerqyuggewlg','pvyfzsagpjpkwwszbynemqcdmpjnrwxibxwoxvcittrwteekjuszwqbjogkmrttcgbkcfxvmuausmjjlswludhhnoyyqzhikubqvlbdpduhxsdnmwvixynsdmbqogbwuftqctenpnrdfnlifeleeftbnhrspzwnikyauejaktrhdiwgbazqwqtamdqnjudsbxcda')
+;
+insert into t2(a,b) values ('','prgdizuhipippuusvctdyospaurlehhjomjzmvwelngyvglfieganydpicoudebvwlvrgxhvfyilozlmaztpvhzaimzmrwytrfxeiwscthzsgptozep')
+;
+insert into t2(a,b) values ('egklmqhecprbjvuznplehmuzwllnaljhnnvqmdcrdxotdlulmdyitsvqlzncebdqgcaehrlnbeaizdhezmtkftccenpzbwdhhzjiomgeirzbyvcpackbufgxpclaphygplbzicbvufpuchlhmrhtmqhkychudvgvvsvagtxslxxsrmxoklxjisltnovfbohxnvhgprlzlogussiduixiyznwafqbvbzpciklirxncuiufmijzznotjbgdq','obetwcoefkjltzfozrwaxxgoahdmqmearydsyjgudnaaftdhzwxqgpfcncomtmvwgkfdlfzytltvusvhgzoimagycmzyrnbysbecxecnwmgzdeshtolqrxbwchekvhstngsxugkwdsyqsuoamwyynnfneomusviosjoalehiegjejjbtxoagjxhnsrzifubieumahfakqgxdxrbpafdsnzvxvmeohihvsgsckzkvdwflg')
+;
+insert into t2(a,b) values ('luynzurioomdelxccturcsbjac','yoqyfvnlonsvxjwayhwgrmxkwluqyoffuzejyajkklcrujxpenpeicqihfjygmmokzsxkytlcrcizgrxhpzkwelxikhkllpcijnjanoeyixhuqipgyijhmdcbayxbftunvjcsqihmsenfdunulgnyswovgutshiobdlmuebkoqnvefucyqgx')
+;
+insert into t2(a,b) values ('kqkujvctwzxylwdgqbwr','v')
+;
+insert into t2(a,b) values ('yjeuvuokxqvxdyboydrudbgjcxaamnwptsgxhfnyxqftipoiwgtuulfigxfrgqaqvfkfyshcwwvjwgqakwiglncczbkhabcfbsbysxbmss','jnlqcokjcstpumjhhhlqerqggbylzpxvhngfyorpssrvslgbgpheejztvslxsvlucwywvhrmkoxjrjqlecjreoiilryuabqwibefcyzogjkujdrnvmgxrdolimoldspnxaluletpokpilzuxvwamvzdzkbtzwoqseeitbrnzqpgckatrbnoxvpzjkgsmbrdtzzcaxznckaieknkqhrrbopabqzwcouwccufebvcmxbbjexrwrnayegqnusww')
+;
+insert into t2(a,b) values ('svmwxcmcyiobghdtjlwtwqdhkxdobacqygcqjqsgdzecsbrzpbtetdvqhzysquletjjgaxrqlwpkozhjkwvqeoutxxpncshygcglajrpokbgwiejvfpdfvsezvcqfqrhsztsjpmxjlynencziaoanxjhcjixlhgekbaczuvamjsqkkbfitojamh','gcuhuffruaxknqgfrmyvnuvrkgeaqpspcqcn')
+;
+insert into t2(a,b) values ('pooiaiiyoclxdqbhdffnlfyqttdhwhfytcjrsmytqqbvlcjgaperihcuvwsapzmxlruemsdcaoiecpqdwliqrnnizbwfebpxrqeqowmarattwbdqlyriydagoctblfphazljekpbnxrpvgmjjjrmvxbecobqgeapmlmallkiudstkizoekvxxjsuusylcfghmdwtejcgnnaubhepgmbcfxihruquhoymaj','kgzklzbyfqscteevassgthfingbgkjoytjycetznxgreertdcyqwqyssnccklpwzucgswtwgegvozcmpybaevhwhcystngmnveekiuskaohokhbyajnkmxodhynvddgewvkxyyiafcphcvksqhemuoegjotfuwticolubucvpkkaxpbfjaqyzubafgmcuuzrbzbzcwtamwnxvufifsfqxexxfybbwlz')
+;
+insert into t2(a,b) values ('kqiyfrjxadhlxjumwgtnfrtdcuzhnookugofampfrfcnkvozuskwesqyzifhqgfznvqzhapxcyeiutiiqwpclvufquspacmkegdvqlyeoxawwnyhixjmlwfcsmdpikddjjliqwuavrtoamlirqzugnpvqqsibmeyaotprlfxemmnuzwxnlifazgyfmdqsxn','kytskmpnrutxrdhewupzfyuktuhoemwmspnqtlhqrgjjxhtpxlrzanvnjwknhtgrbipyrecrmmelfimszntkntyqeoibtnooagcedojroijzxsocnpzidjbmocovfgnhwjpwhgmgjzmauwzwndbdnynennjpqpyhlxsrsqxzsanmepwqrxewnnzhakxzoy')
+;
+insert into t2(a,b) values ('hontrojdixfhzdrhcxudczfdehoubqhjifgmrxddqkayssglvsdppmxfevgdwyikzqqcvbjhoznphldgrfiluhtrlkibrolptepbuesbrrkaryufivfzoxdklyadmzisowavgbnxdgalludhrbuggauwkhkcypclvjoyaouhobmisxlcuwipx','zxpydjgblmfoaqwekrapprorshovuouwzkofyvjxrkdohhpbcronqriylrilizswavvtrnudhzwqnsegadmuyoovauowadpkcvgkqesyelgfqifhgmvmqluotykqonixkufwujapyahdkbsujhvtmsrqwqftwlhnlzpdfekafqdepaejutrmufghamfzoiykqsuxjntx')
+;
+insert into t2(a,b) values ('lxozvkemltmfaulxglwequbklcyzimtvqxgbvatjmvssojfagxfmnkmsjvsbxsszwglucjaclbwvhfzleqpsutqvoadyjybguxkvhzgrqijjtuvm','desynqiwchucdhwoaoppuczfdslneruicnbuhibansp')
+;
+insert into t2(a,b) values ('wtyqytzcsvyemosesrsdjhaclknbsdsltvjwchvcpgrrzumzbutchtlkcqzkfunvdpcprendougzgitgqlwvxeiszkvjqzcadnyvnbvrgpthvxoyuofvonzobwylyqedoiubmherpvcbbgthzvhdnchwouda','akqpdmpcdpueisoqfylfjstewqemlwijxohrrbiwfoosvdwsa')
+;
+insert into t2(a,b) values ('dbisragtlriuzllxgdmcrntqnvcj','cawplhnebdbrphkspfelxrctoqrdzhooaxgebvayuwqmnzcawnpkzdghrzpdiilezgqeeywjehydwnblkpfbckxpkbmuazhsnyuykmlrfuofjqekhxqooonmxjzjzkmvaqcvprqwiseubmxjvknogrjrsopmtlozetfquzmh')
+;
+insert into t2(a,b) values ('qenqmsvbcxqxzdweliesoknripdkzbakdilxphygtpakkvsaalwqikfrlffaydkuqeilyebzpqeogmiwzzmbfsguuwoqcvrztcabadnhfligvgdcyfyybredzzplsmdvuhtwrypscjgkbinmxmodxkgikjimuohwvcadngtakiegpyezejvonxmxfxovzjobocuedfjhvzhdiybjbwqhyzisiezhrdkloexgsbghhjanfceysiatc','ghcgpdyfchkoxfojcfsjuhzlcdeliwqdnzruljwcwntdcjpaxggyysjkjgeqtrrfmvzpjydiowoqfmjeycuqdtiumaanotjyyvvjrxhcgybowsjeekqzjfxnewovyvglzwvklerlxeutmgbbxcvajnpcibgkjtbowxpeaewojrxuuegwqvftmzuscozbgbpybahksgeurhalptxpweovelcrnkmuzzurgbzsjuisrgqbrykwcljojo')
+;
+insert into t2(a,b) values ('nfnyodpieyfwiprlkvsduwdyxwdpkohcmgfgnqaugrqlqkovvduxbjppsnsgpfdvydwbgiuytayrrbqnkfcuxbcppolxcarqeoousvxwrhjtbrogkmjjhiditmdtpqkvzlieatmcrixhcmlidgpleaxgpeyfwqlljignbbayorsyvrinljfgfvzzaaceqjzmvsqmqhqscrcnblpb','jyeozrtkhqbqhrdzdbjbxldmhrxmapzfpnnqxsgtjumqlclbbluctqkofiblifksrtqoizrsubbkdhgfebs')
+;
+insert into t2(a,b) values ('azdy','yxxllwgswkgwujrkvjebynersvispvauphwoajmjelojmuhffofhcbxutjmxthbttwsphkfrujgpogjygvklgxwmfcjcgcjxemboyqfydieysqrjkserusytfpkbonminm')
+;
+insert into t2(a,b) values ('blkovasawlwofqopvvlkchyatyumsvfsmnnesatzyisrgbmgtdhzvyqgtlhmjgtggopxtvxgboveidpozqct','itwmowbdhquimozaqocrfkqiadjhhfrurpiohlkiweioaszugirjbwvuzuugofrasqpiootbanjsyhascudfdlnfirwkxqzmduedextftihnvshakmmkhqzrsxvalsfkoalxdnvarduqyffnfjudxwghrwbxgudbkqazjjeicbuxtpnnbsdtjzmf')
+;
+insert into t2(a,b) values ('aqnejccdbrsdcnphdhroiytugvprgferagwfhdibmkohaxtxkocdsdtjlwoqctoujyqcwwlsgvpdhcomtifquqnyvqvipndeidlsqewkjybgpzxuvaufetdthxhaqudejmzsfqfysvmvqsobxyjxkufjybqrbhsjnxjmdahldjsdskgsiswaciilmqenpttjpsgmoxmbfadxhnxfndeywujcrxesenriqccaqmflkddsczqypbhveivpi','fmtlngbanseibgdmpcltlqcpzvmisscjfpidmonygogegzhcuwvwlzwhtywa')
+;
+insert into t2(a,b) values ('ljdzbrlacbzwqyycawhvyvpscoyjghjlzkngohojjfglmwunqcbsodrrhcvvugduodlozfnnhmhzxdtbkkcxhzpcrtaetggkivasjirycvtbhxriuyexphhpyfptuhsfykfylbrkocdsjoxqkizvzdmnizinghmlrdctcrlxjkjubsbv','bgzvgooffluavvculsjmhldppwmo')
+;
+insert into t2(a,b) values ('cfzjyddfmpjrzlpoyardapoyyptywwvuscujrvbddaznscojobyzpbrmrbgahtwfrdnuzyegacxpqpjuxbnwaupjvsdlplnbxadyprufqpgrzacinaseethjtoyaqvjpqnfzcymixxjrverrgcpqqneskxkxzaskgoo','wyntcedregzsrcaxzriayaaexclgjpsswpyaidboefabjusccfucbkkibkdqmswsukecnapmzjzafxwdzsbkzfdninqiicadtmneolhdlpewinxiakclunzrnb')
+;
+insert into t2(a,b) values ('qcxznkufdajydlskswcbcedbxmggceinrutuanvabxatlatbikhasfbkxxsdcychbnqranetcbnkyobvvynvabdjvloeauocoxqlszyaglhqdsstdbxrniehi','hmrcthbunbiiqgwu')
+;
+insert into t2(a,b) values ('kfpyaawecdscqrrunodrvdkhliaxnnedokxnhpxwimqpk','yijlkwtazvwpncgktxcqyphmyxqfojfklsvqvxxksvwlericagrbuqlrmzjrjeypfwyyvnvfpznrjmmhhiozpsuhlbcgrbsfnjttikxmoaapclxtviblvyisbtzpsgzetulcysybnbbpflvmhxcpwonhzfffmvcsateblenwkrochfiiuwvaqmnjzbpkgqwpcszprzqbl')
+;
+insert into t2(a,b) values ('kfeohjzlwfwzdmgbomjrhweelqjystkauspuepatmtremdryjfohvbxsdyzlhihirurqmdysjcdgpunfbyljrxgxqoovgarldyboeykkjeichpqsqhpklcslnmtkxrovdfnfuvkncvlahdmlxkbqjkyrfdbjxfnecmdvnifusnyvhhcmqirvnvyhmuqqiuaybhmcwpdvnkqjarybcjps','kvshiyputewbpckhhugkmsmshafykwedvlgegjkhaeauybfiazbgzfugdphdybhlvndedwobthgaimbwgxiovdjitz')
+;
+insert into t2(a,b) values ('yvyfkgleqkipustrodssbvmkxyqtnlseymxrncvlzipevkbnikwelvjkgashrwqfkvsgsxhnuqayanfrzlredruqojjdrygggoghwypafcrgbvgdojhqqmzyapsilqbixwowfptpbkdsfvfmpsmeartrbgzsacozznetmaphlwxkjpgsgonyebxkqbxxt','gevetebrtd')
+;
+insert into t2(a,b) values ('jmnjswalagxkzwucpouzuhcmjyntahosppltelcdmrxvatjnleluwpnubribcbhhbyqwbsnrbbisjckfdokzggjbeahpfmprkicshnkxaafetwpciqtmecbcflejtezousbithyfgjkyegzcxwwsqxhbojqsqkweukstuzdspqqsojknwentbdjipqinspxcoakn','jetzngeqwclzwrbwirngzjvxxakffyyouivnjkoajrypcdagsjjjxxmtmnxbiaarxmu')
+;
+insert into t2(a,b) values ('htxhvwiugkytbtsbjslytizciefhgyculcuo','ijiyhfgyjfktymifnkhhimnspufnhkqgnzxiafpzrcxltaahgajpcnaytgojfbmvjiodfxksurpqtkhzqvooetdxatxquiwjckcbjfvmnkrblhihrjcozxnpvbpyuvmm')
+;
+insert into t2(a,b) values ('amczdaacndklnazfneptspqhtobunsloqnprftsuvogrqqpvgokjomrhnyhevunbxwwuuuhyfvdfqipanghokcmwxxfmdyvtaxoeasbyrqxqbphyjlrtiufadwlllfrfalwvfyijzgimbpcaczsaunuzqlnqshgdxdfezaknsjrwctcqvheqffkffifkabvworprgifioslwwtwmrtjlfy','bxhbrqlykimesdtornemgzetcluxohmotneokdaaefzruzznxcotphtjpgerpwdklesxkswkmosjlfbpmymgsqlpbfahmugdjaiiptygyldwgprgtysrzyjubrazpmptcywswfvcm')
+;
+insert into t2(a,b) values ('gktxbjdinuzlrzwlounrzeqfqxbguqrurtlkbvjvwpvmryhrtijtbpsqqpttbazdnmafrkmjrnmomrujhdnfnnxubbductcmaagwqqysilnznkymgcmimqyfqxzgwxhtonvsfpomjiexrhppwkujtuzdswbysnvihatoxrfuyearnbtftzdcoxadnfeobhugjeqwiyngngkdquostjddcchzzfvvt','ytgytizmomkghlgjfbrrje')
+;
+insert into t2(a,b) values ('yqlyojxkuyxzhpgqfdmzqsamqfhdwmnhmxdasdlkceabzgxahvrnxbuzakffjdttdiqmhlixvphnnexriahkfrmthnqcshwqciauqsghgekjlghsrkfdktokbrgdqefjobhprcwgmtpdaajninrbxezjdfaosjkecygdztsenbqrdtzvzyehhmhwetnaetxopsmndkwmzftuczuww','uvpboklpzmeqmwktddfjifxywhnxxvnecmnoyrwmgedgnhkodhuypjzphrlwivlopd')
+;
+insert into t2(a,b) values ('imnagqugyiobbetbbaedigleqgxdrtgfngp','rguxgcvkckdafmenjtjputbrfnhjrvskhdcmagsqsfdehsbnnustwyjbzsmvfdhqbmhnyufwbfcbgheauzzgrjnlxcqvgjidhihfiqv')
+;
+insert into t2(a,b) values ('tvbznubrffeuzubuwnxgitolhenlbbsilstrptqffejkeamakkzkgwrfklrphstygffxwnxjtsecycvfsrhfhfpomqcmyjevxvufczenbw','eghajtpapptggaqdjokmfakypdmymveqvrgovisimsfvziuhutnvrsizopybhvjsupbkhpersapnmovothassnlpawvtffirggxztupppuewhdr')
+;
+insert into t2(a,b) values ('eiwbvnyvznmrjdbpfulqouhqqjvsvnrhjckkcddbpkpzixrvsmgaiaubxneebekfhxlbfjxgailtkmhkhkrqknddsmtxtseyczvcjtdtzwzfwlonwspgmmpfyftisuihmsiomosaeilitxjjpeswhglxerheufpwjhb','edaumvbtlfofoglcfvqhaychsitanjspgotwcrtfhfvpagqugxlshqoxzrcxejyepdpgkxmfxjqnonlptxuhitmbzwvypmilaiemensyidffrpboyqvtzyuwtpzdssxpcieawksolyjwgxkrfuapvpluqalifcsuccmshrdjlqfgzmpnwxdocbjpynxkrlagjitxiw')
+;
+insert into t2(a,b) values ('pkrrcaykpmfsppruofdlylnvmou','kwrzscutezfsoxrsmwqqencebilrajkkltlroxskhgszztrztetzoghlbhjvqwcvkxgrgypavvfmuixzepyivwftvdoaqfjbszxtkqampioanojeauznvzxfibxkfuhmdpnubnlpqbgvmncssoxbtfufghphltoaykmysvmbkommvoxzlatrvuhdmbcxybmvdtxybzgsiitp')
+;
+insert into t2(a,b) values ('zzwgyudixlraexqyfefksivwgzgqcjdhiixghdolbmwavnudsppjayrwdfvsqvowtszwytqvrbuaijxvhtruleizsfaneartvyztuakeccgznxiuxfzkuyazpbqvbvybfgblnpmooqnidvcrjpeakbthvhhxrndejqjzkicfcylagwbtedzpbjrtvztfssdpotmkytvbcihootzyhfihtcgmzgvqubauzcxdrnrgk','llepkzirnvovwzuoqisuhtakjngukkitjtljgofhaadzjgscnllwpkmfugnclblwfwhtwupaykjawjmbkwpppcuphvisbqaeptcrvzdjhjxbkofuhbwlndtfrijbagrhehmxfimtmkcmahyxnd')
+;
+insert into t2(a,b) values ('tvtktbsvromiecoghgopnmivyqsqknlelqvecggsyzkmsswovqvvxrxcdrxuhjgy','gbyvodqasnywwrevomzgjjuwbndnxsuzemqijmrhaeqexhtmncimzggnoruogsauuaboweaevrzqmczxhxwfswframguqjpmoxnbqppmobpjtrhcedfxbbeswmogebabeupflzfvgjnbssvjlkpuejvy')
+;
+insert into t2(a,b) values ('nbazxfcqjronwpkhxjjsmaalawtqvjwnmloaqxykuylzqwpchfhsdhjrmwhjezqlfgxqyatphmzxzaibiibpysdwwpcburzhmwzvjzlnlmxawqvyvzzoxntvksugfyvkglxcgsdxjaubruxixktiqkxvwtojpncjgjfgxbvvswxbmjwcubjdfqfanqfdiazgrwloahdnqfkgihowiqzyajsbijexlzqzeartuwmfioqpzkjmpudbbxl','jghhusiipzrhtbnqrgkyajryhytiuvcsdqsxxfysbosahgtngmjiqlvhtzqzosxgqlibjlsrgeidovqwakpwqnnplvhqylhphizpmnrpiprchcxhhncscwwkrwdiipvjqbhynewoqzieyjantqgszcfdxrahyzznkksbklqx')
+;
+insert into t2(a,b) values ('blxzkkwgwfvkcvuttlsyryjvuicajog','zjcteqxuvaayrjeautwrkypvscsmtrzeghxgobainskitprrgnqiazvwhbddohwtrznrogwjimoyrnjljfdewbu')
+;
+insert into t2(a,b) values ('cnodnotgkcxikskcwcagywswxkjkuozbvzckodvhdbapucrragsgnmoaeajnfhdjmbwdutqzwwdhwxmluxrmevgwbvutdezapvhbtypjhcgsmhxqtpzypyawquaqnlthpzeoevifhznfzroukeoshkfabshgvrukyxdskprwqp','lpuxoqrdxawnuhxkayhgddljaunojwxxowxvjkdqafsluiihmivdzzoycandborygqnjoszmmbiudeporpxsjflxvejpsbfcaceuqxeadgmimcrlgvednknumrxukmidzsdmmbtticgxnhophmkkpgqtizytzyrrajkpuubxvrlcalkbnmhfarymuucmnyaeqjvwdcgltxurptqlmpynxixcduvjapvk')
+;
+insert into t2(a,b) values ('ccmcvfarsffcdcrkixmzgvjaijtphmdexfbwsprsdivpbrrmcdxzpcugf','uoxvtikgnultlrcspccbtspedgpkfzryybtyyneaobzzjbyuqpcjzbflfvdupyctdkcamjaduyoaocghioqcowquqcwzrmwtxxttlbxdsohsucnlqrgbknczchfcvouiledaubfadsuuhiembayvebkjjmeqsdvkofwjfuuejzqkixhqjstphtmigaiqtbmisbdxewsaolwlifvucdt')
+;
+insert into t2(a,b) values ('zotgwidtwbpqjknhcfuzrbbyvugrxelmipogrhafcjcjkslvdwljhvyuakugchwgejfxllptpyfbhyqauujcuwyrknzuhhvoxbliecgstyjvcqjxieovahodzixrfgottkddrrsvezdlziwbmtwssavv','lnmapdchqvlgmfnurzrgghufinfmmjcfikmjroxjupktziypojoznpogsajeoubtpflmszhkhxwnmwozyqugojujtufqgqcwuveqbwhrrsjblkrwvtydzstfqhdnpbaqg')
+;
+insert into t2(a,b) values ('dpzqaxbyveyzekciuleauzwgcuykuitgekmtdrefifx','kqvwvjazjtmxdpbrfdjfaounalmtjmaamdwdlrefsnhgtwudrscolynbznajiimnycyqvgpqlshrbpwcimkxpovtzewjgkdazhfwvivvqqdobmltmoeevxpierhbxcsokvedoqrzvyoffsayyohquhhwiulyyybcblzstuditjtppilblryfsksnfghuuedprvzlumskxlziddvsfcvxnmulpqlzfcylewg')
+;
+insert into t2(a,b) values ('uouhztbngqptsujrxsonxfvreaamlsoomhplkrlhegegummqjpphgjcpjcldpyztxaftmhpwhviageapqpkliccspipavinnvzexwcdctefcgzry','disycwicqznsfcypbkrlsuqsyamexqpmwtbcsvrukkjwpzeblozcdrbwtnfczumwrzccexoyobrvvlzstohehiusacteijrjtyfubnmswawhvnykpanujdkkyocjzdnj')
+;
+insert into t2(a,b) values ('kqcfsxftsamzcgnxtewjrvejosstjfnlozabkaxiceaxblfvnhkqbqkpgmhkodpsejldhcraalvzpcifcdhidoxjvjdqpvtulvjigmbkqlbratamyvxcpeqgaofnlpcaufcqqmzbpmiwczholbxtutloueeduxvzrvzkogkyllsfajytyrbnspgepdmakquw','wneimwvgykukqrsajyuozteklqqzerrwlcnjmiccypeoepubgaouggoxzzbiuppdpoawwcezjzepxrxsjembvsreabhbkmm')
+;
+insert into t2(a,b) values ('nmvpryblxqljggbmwywfqyzpibpfrhigalsbrhigqwikjro','ikyctsuxfvjqvqlqsumsdeocviyuchemhilyuyiozqkjafrdqkbdbwfidefvfpehbgedopkvqpsomrambmgzrikexwaqtrxuixshqduyasmvxsk')
+;
+insert into t2(a,b) values ('gtqmeoffrxmbjqdkcygbhvbapkmwpajlbofaovqwmompgmskjogyznktqibgftzmqgzmqrvyjnminvwspicdvjsfobvtwdozhohmbexcjxbuojwnvpfptjpyubplhosfcakiekyxswxhnmxzs','wqejpgsoinlvybpblfubjgjamtbwqqudfksvrsmazfzyphmzkpiskolmpvwgdgbhbwxsfmtzubfiyrbmqurhiykobldsftzpaasjszdihikalhoqcaqre')
+;
+insert into t2(a,b) values ('uqoogthhjximrvmedhsfzlnksdzfrgtmtig','idxxnnstzhjgnbbjkitcilxzjlnhvuiwrghfyogexxbeqtknjxefipsuuemmztwtltbfrkxgiozvsjqa')
+;
+insert into t2(a,b) values ('wtlkbzzuieoagdjvkrtyoljwmnrdityftbwptzoilydabk','megkbnwudhslafcubwzsvosgdoaltgnzhqigfzjpxnajjjzqurskugtkrfivqiqmsqzeowndlafmtexxpcathiswgdqkxfelsaiwzvexfzaqbedgyknxunvntrcqveanowfnuvccogfdmofzlwjnzwplnlgsqagblilrzvhqfxqcmzjttbzlqqnmepndjzlfdcgmozvcpgsocmfnqvcphevviepsuokobjigbesjsrybrgdbmtepchro')
+;
+insert into t2(a,b) values ('wsvzozirqpyudkdbsutsghnrxwikbhpsagnhgooogorztgifdgzyqieoeygcpahzezqjfwajavitutppwzveuuajrklntynlktbyjtgenuzqwuuxsjjotiahvylshyhvkkbbdkddjmwpxsamiubjolitdvecnyazbcf','gyfxjwipukjpprewkslsdqiwkdsvjxsxamizgggnbnlduszubgaeppzetinkbygcwhapalqzfndejmaywnbxnliapkctbqsdhbsodvwqsxgajhlrhhlhwhhoijhcfszfultqcnpnxjhyvxwjxfukuupoxwkaphqlgpqpkavutlwixyytflryqorjfswczbsgqmksnbpcwxdkduwuegeaimnkpxapmjxqexutm')
+;
+insert into t2(a,b) values ('kdotsubzbjiatmckldhithjnzcrnvaprxufwyfbuhvpnvlgtahkcnildbfngriurusuphjjknyjomsadyguqgovmridpx','reipibqciyfrczatjubsfgwzlxwebeqqayzkqixifxmcravkgkwcvudwinheysbibobvvhjqqrxrsvgowxvpuxlhougwchzrassxqcdgfykn')
+;
+insert into t2(a,b) values ('udkaotflrrbjnjijggtiujmawlvhpjlbsfvumfnatulnnbezbccwuqvnysfeeazjeswxjmqwbcweqzrynnbolobpxagvoupotbsakyulhfcukzjhixiwszhutxrnhntgxxanshjpkutayphletvwbriwzgkguulysaqfltmyummohyuahungfalrwjvhxdjnsdqxxgmoojmhamjmzarmgejukmtufnqnznzytxbmygdgqkmyexrnvyslph','buvfoxtgmogyxcwtlqqdzzbgscgohksqlzpwjtwojpeavasqthewfapybqocfyugjorzmbihgiohiduoeftlujrzqzewhqjaefcwrcqrqasifozscwqzggyhantghdvnburtdtoefraklbckisocmmbxvwgdcntl')
+;
+insert into t2(a,b) values ('nbgtzigkavlrtwbskzddotgsgvsyepiedkhodyxcwklrcsckyszbhsdurqzoihhjvkybbkwsixwmboaykvtsisxjkzyxtjstsyhddaziairdsahsybomfknzwhkgckakzvklgy','pzoggggccrjgbpiadnzowvrwcjlkpgs')
+;
+insert into t2(a,b) values ('ffjmbdecxlrdnmvbgnwxtfwkxcmgdscrssbqqpyucryrhvcgosogtorhkvncxljzucildhuaxpfqbgmcjqoybwbuvefghwafhokvpmchoubvsanjncdopfagsoebvzundqcljcghqenlrksaggnowlndpwfcu','zmwiadqsjomkyraoeqowuvnefjpmpfdmpyhmkfrarebzrjxgawfccpwxkvvpkfsdamalfqcypqzhyjgsmozgbdhcljpzrckvazizasjzuwazhutsfmvrhovgwbxmtgmnsetwyibzfkuwvoxklejlfnwupcvdhzfsixvwnwntovhyjijrjjzmikjkuanwqyhbpywmbpbdorhzmvqxkkxzhjfpupcrgirryicwxcmkhldxfxxkozmuvpihdc')
+;
+insert into t2(a,b) values ('ujmzavxueuclpqed','jukdoowtxaonvjqpzadqjaitvep')
+;
+insert into t2(a,b) values ('pnggzrnjoodxlespiuaawcmykcextiarlsjdfhwaapkdnmlvyxyjinzuzdbgrthxjojvvqddzknbzfcoeocivfsgofmnarqsjnhkresribtnryrnzivbxcmkwiakodartptzcveddijzjrwyvaohbkprzmzpdnhhzpszgdlcwbifbkemtkyagafoxyqkcrmmoxgsphvzicthjrnkytimahumotagckfphfspyukavtzmqocbsqtflwiewyxj','vozdxbgeasqdieaqgosnixwkquteyymfudrekszqtqkqqiukjdafasfrdsbargomrfkipcwndcxuozesenzwxuuykgofaaleerqvgfbbemlbibczhwuoqoqpbutcgvgzbbwxsajaessnyxaadztopbnagezahgnlvpdlsjuxactzixtrytgffyssghnymfvlotquyrajsifuplvysstnferqxwxsctugvbccr')
+;
+insert into t2(a,b) values ('wrudjywgzluhoufajokdnapsxklvltadbhjfpyhnkldzuwnbohnmbgmzyxwwthdbpyzbrsbifhjftlvkksgzrcawqrxpphjeyajykuibgzlk','jczlevrobwpaacxssrbtbngimlbhvbronsffqmzibvahaoakexpveivferuqglbscibqbvvvumfrlslhdqebolexzwoomnmywtjjfmrzzwuanmzatarxtpohnqzwltuwwpfhqvvfkwncnjtrjwagxkhdaqnazifdjqfueujymtipprdkmhrxsvsoemif')
+;
+insert into t2(a,b) values ('bsgyuovxkmrjaiwifsabbmjzpxxqgjqqllaziyfxpguwrbmab','kgigxyypzftpqbaabxozrxmgdvtfhykhvqvpmujuybkhzmxmorkbujplfofkdpihxeltfufztuojsbivixhtwookjlsbvvicithsdaqlpvsrwegskgvhpwfjwllhlcoebvzsihexyrynyptxlxiypljjcgirxmicgbhkufzlklwfpmuwqtkzgzxvipnl')
+;
+insert into t2(a,b) values ('pfnuknhvpivzeamnxkaghwormvmuovcjtajhoyqdvuzfkmztvffzeksloutsugwiuzodtypdvmukzwsmmmgugwivvbtwrtqkdhygjerbdfymxpkyavqybonfeglloklsvgvxsxgvxggsdipwastwvknmujhktgynmeudwncygeguqlwoeprwsywsrxk','xjalasudsaegdyfswdhmfipabjmwpcepdafzqzlgffjbnunwcghwlpfmvpgfbzxyisevslogbbxhtsqefupsttn')
+;
+insert into t2(a,b) values ('niaypwctlzjae','oaemwgaejuwvabbjydgxngkfqvlwfajyczvkmbbdieqcl')
+;
+insert into t2(a,b) values ('zxwzmtqbkxdlcyaslwhsenztbzyvxbtbpdquhjivgpuuodoazfhurxunvxdbgtdqcgxhdoilfftelcmjrzbdkwhukqjprqiwtptfhnzhflrapeidgtllggusofzoyraobcnfhinrbnifcjhuhqytkemv','jgiqjomroodmlskvgorhgxmxymnuxcmphrybxsawhutszjehzfotyawaakqhxvrrtiywqqoycgtccfxmyusokcgovlmqrxsfuinzeuivdlhrksaeobzwfomisbucbrsawkglwmbklsyepjibvzcndkfzcvtozxtmncgkxljfrfkrcavoqhmkkkfrdeeq')
+;
+insert into t2(a,b) values ('fcns','dkpxkpxoaddobughcieipyrzfxttuxtycooskfgeunkjhyqskynskciedqjqbtmsyxhmompfnzsybazaipeknaknfvpxcfojkthoteujtuakemfxqzqhdyvqukdtoxlytrcywa')
+;
+insert into t2(a,b) values ('nmpabbsewmennbgictwkmtqaumaghohfpqldawxuekgebxpfgyosrcmtaqinjbrbjtwmaxlcrtasocciqwtvjuktlchotqjdkewljiymbtzdwwjeskoivuqpwnspzupxxcalq','owkzanzhjzkxyymoprwmxmosmfjlfjxlokmggaomknplzciinzxmncmgwdzoueawqlfgmwusnkbsusxrpwpzjqwzxhfezqudwtoruptrthqaluzbywlsgzwzvksihdpmwospbadfktecudigqytasjkwilnxwtkfvledpappkqegyjpu')
+;
+insert into t2(a,b) values ('wfghvsazibsbkgzbivnw','rqkosowinjigceakqpqrqrtwxmumwxrrvmrelpkznvlwgokknyjhjcwalshcrmtxgkeecphwryvzhrgimjvfhcnpfftusxztzdpcxtenzumcftfqpxuhcvccspcoteuyciuvknszzwsvxfbhkjxxtywhjxwbnjhwttuqlewgsnezlyxvamwetisuksrfvkxjxsvurbnqrcqp')
+;
+insert into t2(a,b) values ('aodwvnrvucnjdyaxyonamkhwctesaryfeouwimwocwgpkryhbzdeggtukyjngjncxiwsvbsafhmlwfgbyotgezngqgpiakirefoqfulsuntdphrmtdlgqyomvbyzwhbwxvszpcxxiuafnfhjutmuzsvamlvpwbjcjfetfeexiodurnaskilyjgygsbreojjkojyaonqqrauy','czwtqcsufmcrelgttqwtosppghaqtoqaclwdwmqenxmlolthwpovnaypwkzzowmudwtdfcyrcskixyxbjulrbvjefiarjujdupwekxxhyqubcffczwpbukssppabvykt')
+;
+insert into t2(a,b) values ('kevpozneohdnbzrzckqkfmttgkteuhniybs','pghfzdrwciucncmmdggmpyhkduvuponukqgthpcwsacmfiyhvscnrgmqvevpekphstxvkvyajnmfuxfvttivdyphjufinpccchdmuufllwzvvchjhawifczvbbwxktiuwpnyjmaemyzqud')
+;
+insert into t2(a,b) values ('qdmgsychetnryztbcjtsbwvnyfbijtwdufyhwtvdfoaalangoccxodnvnuaochzitrkvxbglgactadnmbxjndwlkynhasqimdrygmhvepbkfimpyysfcamvanwhqnapgphzwajufvhveb','mnuqsrvbtaazggkjpjqyryjjuqabehvtzjbauonaovcuwwjdracshdgpsrgvadgqooizhsekefrvqwthxdaydluyerwjsafnjvcjybiqmxw')
+;
+insert into t2(a,b) values ('lh','ylhkkzwzt')
+;
+insert into t2(a,b) values ('epjqmtzrczkgpajuscvgarbfpomsanbvahwuypvkcnycrmonupchvlarxxvnipdk','cwbfzvjhiabrzktwngbsyvctdbhiiwdiqrztuckgmyvyswbrfmxgrjndlt')
+;
+insert into t2(a,b) values ('faaqlcliro','sodsfazojqvtechedmjogtdmfliwxyehofiooawbaogpvtdmspqqazmjxvdfrlgkwguunzpmnqssoeoshfnlbjsnshixihgytzlqibtkqjj')
+;
+insert into t2(a,b) values ('tyworzpetimsycpqvriccycepftaritpixomrlesgqxejmbukcogndcumopwlnrrbqfmijuctzxhitlydupwefywigcrhirhwbmfhaqtmjhv','zohfpvzglfegtamfymuyvbtyiduehcmmcvjbkzckdmiqqfijbndbuhjrieqvlhpjswbvzfsoxgkbhnregwylqlfpqcruyouyolukqyfwknucfjfqutsugzjaqhcihozpmtejzehiawocsvcoaouygnzvxmrhpwwxldkdhvmwqxvlnnbcgiegltejrnbsymjmsajjazdgoeqskocvtwfqbpdqoxmaoabvzyrtuxbvhtuxzlzbsmu')
+;
+insert into t2(a,b) values ('mmechyvitmvnrejrvyqnlepyccvrqhoccsahdzys','rpotvkerymclqapxuakwgyobyqtowkolnoravpcadhvwhdauoylbvzzpfcfhbtterpuamidcayxtxohsohdjpdhqnmotphruruksbpqdxatqzlrsvvollhausxjazumxcmpprymrefsacnhy')
+;
+insert into t2(a,b) values ('syjifzzekkyaibpokqrnmgifygyjgpjsqzlolewzbxifokaxcopgluxruftloctfchvhwphdotckqbvxglnshaodhnrqpiirstciuganxwqfegsvhbcuoxvwcnicrgrgfsfmwrcwxmwnlyujbzzdvrloctsaxcpuatwtthwayqmezqrstvjzrqtvkgitjelfzsbfko','ykssoiossmvyhvtfjccybwbfyvjaazvsrlrykrxexodihuozxvgsxvbgriszpvaocbylfwvnjnqyvckieiskxhzlusoailnnzcucbiukdmqugkkslrzgdnpxnqzwrmnasyfzvyrbrwdcpxyajylqxkwrtxhpxgfozyxwfobnyqxudflgsscegqeoejyzaxdzssffsmeoecpwebwdivmyarrxwavanoctxujplndfjwpafxzretpreni')
+;
+insert into t2(a,b) values ('tmlbfjtaxdjohepnobbezbmlmsmfxomutrmkqhikodsoqdcxefdrjiogkjxjqowldtbjzcgztailzvaxpwofinpfzyahamkgpkmqvfwttfzlpiewinkoeivaiyndfojgddeaaslyhzhgpvpkjjitffnynijdmvfskxxjkawwizlhdyucdgqkpukmgbn','onkmcnbjwwlknnepnaeccrhtwloeyfftnezitavkcngzibnjvyiptbrhupvzgqbhbquegsnwmzthvavsuvxehyaztwcznirckzqjhfrtv')
+;
+insert into t2(a,b) values ('vxxhrnwwnikjgnqpadifxsstpakrlpsrujelupbsggtuobcgbayrkkcwaiptuejeabilkxpkzjgzkxmnfezotjtogfxwfblmjsxjdpbuedbdmv','nntgxwaujzpdqkvwqwminfahmgetooxufaqsqdgdbvojpplhwhiislapbgdfsvwzjtzftgyhwrtmkokyomvgczefveapynxwgedckhervtdkzjcgqmvqmwdcproxalyapupdxlepvdauvjjjnv')
+;
+insert into t2(a,b) values ('adeobzkilhtildkhyeeqqofcyvejzlhgvdpbicaqeoqgnkejbmrizrkcjngxpvehsrqvezmdaukingbouhgtxsqjhjzaxvahanyui','fnbukuzydlbtmvnikmkxfalwlgmefdjmcpwuysyxgkcaiqbxlnrgtfyiusgtxmlqmzsbncdozfkdjdkpdciedszlclzezgtklwjmccaijrhjofxbigpkslqgjvyqkvlbdctpjflwgouhrkj')
+;
+insert into t2(a,b) values ('vhhawacxltbwvwdxcbmqdgrzqfahvjmzmiumaegaxrzgmilxmdvrkri','szuktlknxkxmrzedwkufoilzmyyyiuysyywbdkuielqdsfkaactazuqaomnemdapxznafrxebkkaymzvtwjbdbcbsiqohxbmlhrecoqpgwomsdjpptroqenxwztgszkmvkfosqdvdsehiabykasmldboejrgrrfrhrsusrezbzyecwvcqpacxgjsmdrobsqqzfgeuvmwrgjcwpvwrvfkhxrrtcirboobhoibfpiybrebyducx')
+;
+insert into t2(a,b) values ('drbiamqvqrrxbutqyxnmciyfschvulamcbwaimpmogmqbtzfhthfdkjiudjkmnvepddseyxycqewkpdtilrsozufvchdqsotehhtmiprnfsyhboytahmprmbwhixbfsrfmilwuetjfywkqkspsaccbrwnlrbcjssxmpbhjlrgztruaabobklkmwbpoejtnjevlcmrgbnlfaohygerxgxeldtoahyweycrxcpvkzdekzmtttnoitziwcvoiul','wy')
+;
+insert into t2(a,b) values ('rtciacubuphqufhfiucwijkrzcwufwijdcfdjegbtyrvkhwwrdtaukpkikpwbxwmwimuucboforxazymgssrllocxbohfmzebufdbucijrtmfamsibmmpeazxiwghaqqytjpocvfbaaqdafaecthjvmsgwqnkznngeixienhffggemczsylyfnlynmeirjndwgdbraovztrtq','lmdoejdvxwfkzksyyzyqnnzoruvywdpqpxqrrgwnqkiweuttenrrhrzgsqalrxqfajunrbkgjlzsosfiynevxagzwxcddqgzibwebgmhpbksvbjawovksfjgrxxlgfpjd')
+;
+insert into t2(a,b) values ('cswjsjbfgkvilnbjbotprwafcphtjiqrtlxholxsexkonowgwzolwenrmorjvvwdloaflqzbzmfreocjilodjbetejwqkuceyebcgcexssevnetgvnwlhiwkpyaxpxfmrasiemoexazcdefyosdmngwkudbyvoocfqaz','glbkliiiebnjpguqdaghwzcuecialhobupsckhzxrukvmxpxuujuxkszzsvrpttarlwriwxgkrfsxzhwkptcsqhqsshmybbl')
+;
+insert into t2(a,b) values ('xmfkormwewhxxnetywftllowwmkesgkaiixoarhpemifrkscctqrzjjdzymsmvrxzogjtnyxnhxompgjezlnjipfexylcsozsklluwhxfhzmioplpxibnzlbymcztfkxjdwbbgebnpgxypesrrrfeapnolmsneytolngemcj','ezefyqppsbrfvxcahjrkyenjktaplfxtdmvthlmswngknxlsnemxgbzuhpabxtclcoljqqbnrgnelydnykgmliytafwlfrtqfbqcujmjemgfqdhtpwzshhvsmymreplgfotjkyqpkkibetyrkxsrsxnghpfxcjcgynzkwbqjyvstzylekqfjltymwkjvvhdzzrojminqaukglkqcgaqnnntelgcbhpvvrgqxazewompckvyjgutpxh')
+;
+insert into t2(a,b) values ('rirgasblbblrugykpptwbnzuhmtbnuqtxsbztqchqiiocxmrvrlunrehwyqbmltaeywdoebrevtdrlpppuatpsvvruuurttxdznqjygqobjnfgfmqqtztpbob','nynqvzjwjciibspdxsyeftdycskeqpzwfcgxdfnclucgcikxykywrbrgfoxkefmxqmkivmbiglifmaktzhlbywdtrtuyleucelvozvpdklpudcrqiccnjnjpkpuwotgbvhatfblnvnwkxbnrllzuzszyvtgfoqbgtexdvrdhbnkvgcviojzxtilzgxffzmvikwoonqzfzhxqysbdyghaapvklsypkfxgduiodxotma')
+;
+insert into t2(a,b) values ('ewylrhqvjxnnhsfsykczprugdibvbweqreyuwedjusfoqrcofvcpudhbkepxvofriwaorhyofuozewrxonffcqnez','eskvtbmhtaminmxyllypguoyylfeuccxcghtoieccmvgvzyiudricqbcmslazgxbonwdrurgaqovurscdznfrbwcjqmvoracukumorjkukpjmwcwutwarmrnclstqhlgljxohajblskshgqovfxyapylwmgbdzdwsgxvivkuvdywoehidhptbmxhzwgcbbaqljvdjugqocyryhmtezhzzkloaplwdxrdhlgmbuqnlmzydoxzfp')
+;
+insert into t2(a,b) values ('bdngdkgohgfhxaarmzwgcjidghumksowfvpeeytkzxomrvmfiinjgscfbjbtiouqirzwhjxbekiiwofhyfwggcipyjfqkvnomnuyxjeqbdpnicqeegrubskfxouzfjxvuyjpilecgkoxwztheznpmgdlkxrmbyplkablpjpqmykycmzltzczhkfpjrihmbnt','fbvyxebvttwtmhbfeouvwscwglypxqwssdkhqbjljujbaconovyfjigdikxqylxytnnhpliyfgewqumvrd')
+;
+insert into t2(a,b) values ('hzzkhrswurhybidfdfqwioucmbbvvikmxpcnxrdssmzvwhjfwwtjuzcwenhcutffpzceelklomguvmjowumdoklwxonfgojcqjvufcapuouafolmaqmrdodshhvshkldqmbygzrccumdudrhcoricsqrsrhbyplzzvitumlpwxnwhuwmfpziqergjxuhmllwysuxtuvluqjewevvirexcbichsdzyijwzivpgzivoovaovkizgcivkhwgut','glmnczcqxixzasgjbyzwvybsircjhmymwhowokcqlunmcupbhadxoveifjdsojpafgrmegxlnjvvfdlxddaomgdmdxauncrprddcgiryvisgcvbxgiatoqepvzjafypijnwlgzgktuhnjcmsocbsbtcbcqekjmwcisvfrenopyhjrkefhdqfkcslpnranutqlkwewareljctljytrvhqnkqwmczkoexrvbx')
+;
+insert into t2(a,b) values ('oiapkeccdkymieoizsodirknodvstwczggjmottneqymtoddpwbncpfllulasoundptbdtegvqybofnjuhqvtck','pyuwrpgwmcmaefexnxmxyqqfamiuzvjvipotncextvseivtmgpspsfwnhtkaxmrccsbopeipgewwrpqy')
+;
+insert into t2(a,b) values ('oewwwjzycsfulkvncmqglrfqlpjxzhexwkvtoooqfeubfikcoarklogipjnpazbxovdsfxbfgyeekmdjpdagohyswviujgikeqybcyywumpfmbjjjrtucjzjwodgdoprotunqlexnxsmgmrzgaaeddfcvskdfyyjcszvkvgzxovximxfrpwoetnahrbks','drbjcvoegntqxpbrugzzuzymqquslkzwazrwmrzslbkqxphipjcpsdffihggoohpoeucopbaateygmdzqsbyuxakhpefqm')
+;
+insert into t2(a,b) values ('mkjjoabbrbxdvxrhrkpazhktxgqzeqfskwjbhlqxofhxlyelx','exiltllhitukmovhfskzrjfzshldhnosyycwkuzkkjuwpqsewczpakeaizmeezlbjyxdjmnhajopabt')
+;
+insert into t2(a,b) values ('lrougfpuqqzfdnpticxaqhfvwmvzsooprepevfthogpvnxdiuhomtyaokeotakldjhmmmmkwpfanlvbhvbqjowtkdhxlvdmfpalyykqnhlhoipbsbugifdwwoxyeelwmtprbjhpqdrtmzpmyullrxbrbnxvoybtemjbtfrfblmfpricqirandtpxxtxyjlngvswognpaoxadpeguzaxktpwreqtvfpjscehw','nkwqchgnsgicz')
+;
+insert into t2(a,b) values ('xdjaozywqlrjorjpcrsqrdpulyvpqqwqixnngmrboodclvottzelhwjknbmiazhzprujkjhtrqulmdvruollphmjhgqqqjkzejfjvnkcijkiujovbztpvvtiujidvienwslptvblhzcxofxswfzomzxfadaojwsxuxmicbeigruntxsmxthsnjxuioysgfgxudmrxfjjqxxyiiezuzmkdvthrkskjvurujyuvpl','djkkyiayoaazzbguepzqmezeuwjstziyuqllwelmhtniedgultmeylczneqgpmkunyceaabskukpywuewqhixmdxgougphheoipbdirfltppkqsavshrkfycapqptzruycgeulcxplkmro')
+;
+insert into t2(a,b) values ('zouppxjggmcmgjjsbhdtbvjgbqqdetjnrfzexfcfeuuinhvxgmrlivcycdloqgveealewxztxntzadt','jizveqbemgxxloktqlckmsqixgkgepcxiscbobilskaztegngwncnzdzxmzucrpegialdyeajxxlvuezslsioxewerjcgqqzxrceevdotwzltpdpruciryhgtoirwtjiwufqwftzzizfuvkmplnlyyuwphbnkuolgxkccnuoonclhapksgwrqpzlspeqbthtoxucdnkopllbwfylwinczcexpzizvjgceroczxvcei')
+;
+insert into t2(a,b) values ('mpxyirgoppefxavgaxdhudimrzojjbamitcjvpjsdabuacskzdowyenwercvyfmrxqinkmahkxovsojseirnividlskwasffqep','hfvyshyohqwulsuoixiheuhevpzsfyixqyepakbxpffockskbcewloyukspnqeemrvfuevwe')
+;
+insert into t2(a,b) values ('gjvyrnurgojnx','jgtosrsbzyzdgsxxffsnpfwesuyxvfbohfgcwwvkijvulyeykcczkiktwcrijbccmxtahumxmthooaduvdjjlublvggljrafuvlzkpvifncweckuhwphitwyigztllxznvdcnmqzkesjupnkzglqzirqj')
+;
+insert into t2(a,b) values ('uiakstbirtsodsqpazrzgxidwkzjurzuhnjwiypjdvdkjzwewzltvzehumjvlgigbvtylkgaqqjvazqyzrfjwtifvxqgtihqffwfrtgsofeqwsqhwpairxdzedrpyhichwejjbdwhifnddevwpvtmwikbsjqkifysexlzovuygnutgl','dmrrssqsjdlzslymdimgyqquwaekucfvkintwqwtngylbvokurrzywimluckurvtliacaplhcbpcunvlttnavbewvtxtihyszgdzjhkyg')
+;
+insert into t2(a,b) values ('djjdcwfjxmvamxtzwnxpfdlkavdn','njtzlrhjcrwpkakjzmmltxblvchrqhsbkfvjykmlhkdsjzeojqsaeeyev')
+;
+insert into t2(a,b) values ('pvfhatigcfhihslcavfshdjdhskxllypybswxjrfyoqjsqawiqbgvzyyhjpluhjecdzhbbynopnhuusyriyetiuhkskinhdhfbasgqfbtspjnotbevtlpjrqjhrffrowjaiqccgxxqsslxgpgdsszunutoraqyzn','bdvuspqpedgylbmdjemmnbamjxezpfnhmmteryampgioqrwcwyaqwgesebbipeqxvmwfbif')
+;
+insert into t2(a,b) values ('uoipsncuwwgpsavkekfkueiahbrjiqwukblcmumpnmdwsxkuebqhkpgxkrquyominhfafrwawqdudszmztjdtdohpfgeqdtqlqpudqofrmndgbtgmupmcnpckqmonzasyoqaexjorrkwzyfbramzdbozpqoxvsyvlkitjgwbfxfsuvydfzqtbnlpfipmuutrylowqayodztqnjettme','dnnghcmbuypbrylslxvnhosjzldtpivnupfsqqyxmjjfvxzaetffnowhyccrrlgjrlldkwxnraojdziwgoymmzpgrsqoebmgjvrynjwkqjgsccetekwomtphnfdewvkdnyyypaqcfujycxwanpoghzlegdsvycnpjitruklllhcqrtfxdchjbdbvuiuqmxjmhu')
+;
+insert into t2(a,b) values ('lzmovbqdatcammjbtquwqlguiqpzwnoykojfiobjnybyppkuhfn','gbqxskzvbqijvzqwesnbotiztefpedlsukwcrajkdegtyrjuibbvxzgynclqspkjvniedscbwqdlvpxphihcqxqagcmbmfbtfrnwjyucmpbythtctoxnufmqcchkzygogvyobqkpytdpixorzaqdkgwdaskqckwwqwfrwjrikbw')
+;
+insert into t2(a,b) values ('nwbrivurvzzaifpivsfkbtydjwtyaztinsqpgapuswronmzarodqegchhayvsltgokrztuhvowjlfyyidothzaduxwgkmkoggsjqytncvopw','nmfrouelchoyghelyiqiifawfyxrwxihbodbxtsqttfpmkvjismvstpbcaighhblkqfvlqrqjtgwrwujznithubnubvxkohmskmpdgizpsuvhewzeasfuotogefuqxsqplltiixrrqlshbsueznjsptkwqpgumoejjegieprraepabraoflbuaoqcpouerclirifabkiuaikovcrhbmnzyjjncqqklhdybzitxdcgeuxcnbjytkkvumnv')
+;
+insert into t2(a,b) values ('myawhugluelkhkfgzaohscjhamxydsadyiwqteoytwbicodkgwqaigpzlniaboslmotmwdtjxzdnlghxqkdxbylskhjudxwjyrpuaizgijmnrlpxbytrtzzhjuucwfmjatrfvtbeghjjmcbiekjo','ergwciiyryhqasqikojuwjry')
+;
+insert into t2(a,b) values ('vfrxhgllfvfkccbphfeucxbqkwdtyvlckgmeibz','mrgmygycyqqxgfqnexfbkppwkdgbwbip')
+;
+insert into t2(a,b) values ('oxjiruykykhtzqlyiqkhydgwkgoeglnrrwmmmczqodvqglrkaqfnicwyrcuqjmirvalglwemlmsdjuvpzsjdgknxwbqarpsqmjknebyovtjuivtrwskvhupizpscrpcblzllugyqxksgxjhapkknatouzymohqkzhmrsepygfjplxxvvkjhorcsbdhljavippxdzcjkuadkvudubvjjojuwbveunuhurkcfunhncwwp','cyquxkcahlsylaoechrmewmtztioqkhexojovgqfrhwjlqtmvdtqvfmrevrsjqibovpuewmdunynewubaqampalxywlomvedwmiqndncvaksuxtmjdautxwjbgcpdusyhgizjtraalcprctslqhtjobnlqzaqhwihstvpoxwuxmdid')
+;
+insert into t2(a,b) values ('uhbhwcrvvihhcprmprspbtjhfvfdesgethusqkwgtsorfefvjmwzxhkxmsbpgmtfcxgmxvgtlnrgvyytjydyxxllenoalkjptjqxamzhyuwbyvpevgsdywqwsltmwtwiyposbczjahisljczplidxlgqqvlfajkjfnfazqbxplqqdbiukbbeyxptqbflhmbtsuyqjsrgkdzsturbkgilwm','weauoqbjehkcqijfgjmra')
+;
+insert into t2(a,b) values ('wxppnzlzkjwdsvmpreioifrbwykerdhqsfjslnlyapeixvwalsgxizdiepllzdmgfpyxlsnhbsbwhucehd','ecplwrrntoodizkkssojmqtasgzavihrttty')
+;
+insert into t2(a,b) values ('yofgvcsbhzwkudwyjusmhpjhakhsgtgyplwxuejtoszcbndnuxickyaoztlvpfzywwnqdiyoveksfsfcpxcnybipvstypguiqvpqmdkfspxbwdfbzbwtfwjyqiphad','hfycxcimzkabcwwhsdbccdyeeopeihszwikarteozokemgilxxaupmzgwambiajpjbixfuyxftxuaxpcivagnjkckitujbafekawiscmjcmkcmpfdjtlswngczkyepokulxnfoeilgynhysuuvfmibsmkztptkxgzgjjqnunolqzqsxfrbwbqbvqjxsxttwfhvxvyakbbrpnfhetkjwgqmyojd')
+;
+insert into t2(a,b) values ('watuhunfxmjfbywgempnxjmvjyhpjouldsssiihwoungczqkdmniusxjqgqhhgkufhradtlibdncglfpnfqqhydfagsjccplmvqmlvmvxaeusktwkefwudnwzkvrbwjkiceczkauimooxmmzilqdkyurcixkwwgkncgzaljqft','pqvljckozlbxqmoxmrxxtqdacheefinojhzjhjgmcwefog')
+;
+insert into t2(a,b) values ('ckkmsskqejmoplosqucmmmsbhcenlitygndcgyxdnpbyomeuxlenusumnmgftkygggtaexatecaflcvvdkjnkflydhenvpghsyyffplvfgzaazywzaimwzrziuurhuewjcjtlyxzdejubszkhufpayxbikbtgpxeaxzouuhkbmerfvvhqmqlksprqkrncvraeylhtdpkllosmqpwjvuibhtofiypxuj','capiaunkgsbbsmlchqvmnjwxxwiomwrijkpughjogkwvgedrmzygsekcsnrbpaxswdymlamiljtzrbhcrbfmeeaaiurplmvsyspmhzpqpavqyicksvqhflzzbghuxedndpjozceakxiig')
+;
+insert into t2(a,b) values ('rdkbdsrzebsekkowdtxtxgevqkjdrpaqyidvpjklcvpnzwquypoddbz','vzzibmfluxdvncorgaphghtvyftzfzbbbcrabdocpybxoeanuqoewdotmimajeeqbuoxplxsyrpxxxswrceedemkxmkkyltlzyzygoonhbcieudeetvrsskeidxzioubcswogayurzireikhoehwrxxdesfinaxvbuopgtukepvxrjfujwtfwdduffazzrkbozznphhfawvfwqfcnbuips')
+;
+insert into t2(a,b) values ('lmduikrjyjpoxrodinvxlxspqfuhbzqhcfejyndaaxhgubexitsimuqlraykoldjkjlmwcbxbmvbabsklbjhyfzexyiumhbkrtviqurcnuhjwlg','xbvhixdkiyzwxohpsfebqjwceneznmlybktarmbbkiydjiegauhfmqtqrdnzg')
+;
+insert into t2(a,b) values ('ixngtzadhcudmrocfwkrgbrteoxwgvvpsmqdkogimgmgzdbvsajwmvjiecpkvfienvepvpqkbelodiymagihpwcdxlepkszzefobeufdylktndblcntizeonwxzrxwbt','yruswtmwcfcyeedlazobbpogcpimgxodaegjznbwwgikooacihgsjtzmtcnhejuqrbjxpgeknblkzgo')
+;
+insert into t2(a,b) values ('xvwbqylvucipqptrszycfhvvvhhcdulxhhjhocvpizrpnigvjnphoisoyxqgeiwxtubwqahay','mdayosjdkhlibtkzujhvakfjoioqrccueijzhnjazlcbhxcxtmywmvewbghhpcjwicoletqnltryhxiyfkzsyfefuwiyutocebsbujiixizrqsrnfjleefhsljrpjfvyypemuyfjdiqlrzvgalhgcmioztofzhwlqynknpzuloziqhcjiwvmrvzjfyjbfffwnyonj')
+;
+insert into t2(a,b) values ('nzulmjmnfvmkulzpeortzloygglxsyxpallmlbuprvnudkglmnzjhqdxdytayrbxxvbsiebrhbzhplqiclteeqzsctuuuzfqkemalnpnlijmnhottwqbmwjhwsfoueoydinmxtxqrmtdflxa','cjgisdgmzubyhgtqeyzarragjxpxgtviuvnskameutehwephpahuvkqjyvfruionepugixznimwfybvjndmx')
+;
+insert into t2(a,b) values ('mnotoowmcckrgerxzerwioeshignwyeihiqshjhniuputdubezwtrlzdengwdyygmgopueuvvumqmicknootvyvgkigqf','yxwiglwlsxnklehdiynpzzqajfedrwmpvtaxxlmgxgakbovhkpbkfgknnohvlexcjscphbwwrnpilzbqlhfhritvpthgwoc')
+;
+insert into t2(a,b) values ('dhoxhjhwbstmlwdorzetlngvlscxrbkadmdaoimjrtiayeofhhzoflmvjuvemeuejipowkwwmywyurgglfaixyljttxwikqrqfnbdxodcxvarznvnajhudyicaqcwklsxdrxhbdxxurgelmibanjjhsscrsfwq','arpzjdqfobontuziylkohxrbcrnlsnfyiduiotrxfxdlvhgvurlznxpdixapxqllrwsuzjljddytkvnnrooxpcdsaextqrwxaabrpsxfcstcgnpyaaapfpmqlduakctmjzlcsrazhycjvoqeinpslzqbfjscgrrisasecabdkbejbivfpavypfyaqqchmorlljamaatpnekxycfnjxgejzmzdlsnmsqjiybjhwbshzksynu')
+;
+insert into t2(a,b) values ('hobioanrjnvazplqzzvnaifanbkfyaagiwfvsioaenechmonreczw','ipbrrrncl')
+;
+insert into t2(a,b) values ('ochibglqchqvrjpboenbaugnmuuxpwiihsswrpetggbmpgphrppwsfrfstrnjvuxbmrlzwocblbcsmmlrnybyvvgnextlhgxdhdhubcqgzejtbrcwawchfrzwocrtyqdnwppkkbqdvbtaqvcttdnwbezxizaxzxomgvcqegjbbrgwrhxsqhq','lyjxwgrzrvmjzgdzlxcshsedzzt')
+;
+insert into t2(a,b) values ('afatuabhwvymprybaalmjgfieplissjxgdrffpnwsmtluuxnhtdchykifdyrlawnvmafdljwpuyhdeleutfhhgzzxqczzvtgvmmxrjcqbjxuigvztuphpbbxuxmbzspzlfocyhvmqmdnmomykygwoutbvmn','whrpvrvlljmswxlnamxbpidvxkbcyjnxlsejnsxsektdczpssprhctesnlxktdfwllnxxanjtjexljthhgxuvcgpllhoywzrpyqgtksyouinbzhknoshmxrpmfcccwvjffxrshoaybhyptnupgpuxaccuthojpjcedlfcswifdmkxbbyhftlesdblqnpzxfthatlbhxmmsosajlszrtxfngayfwhrexsgaejdbrabywatu')
+;
+insert into t2(a,b) values ('ztiurgfedzhkwnyhauynzznnbujindqfhmrzqhbvoxmpbthbjbkwrhwstqlpmkduhneliskujeyhclcsioyylmdyrnasggkqohgrmmnrvogambhmnhfolkgpcxbpoyahx','zhpivarmcmbfetutbfycvemvcyxabwowhdexhlgvxkjinmxknhdjraqfoyurxuvlfpukjpvfyxahaqyoxouxauezodkywkexazztehrxcrpktirjippyhxezqrclszfzfgyyxmxoigatudldjcyyotbildihdzyxekuteljydrpztovuelzkkaomvrqwubpyfzwvyuxmscxqsmhmnytszwbmtvduwlotdlfcficxwhouoqihljxcgzkfoz')
+;
+insert into t2(a,b) values ('fcbjotsvbfzqgtqidbizabqrcwakcirfqunfsyenqnrhgfxnicilrejzxwwrborpk','dmyhazvzzvmgqjpmjednvacxjzuuxgmzsqmtdnfesvkcsgjouftojjxvcrrlqgrlrlgbdeodofkqowqcsipipwrliwsgxfudsnpzrkapankcblvazmhkztwpkryqvgklppyjuerxyezfmnkngrskslerqbsfiujlrpioehsxaq')
+;
+insert into t2(a,b) values ('jltubyhjgxchdclqisykhszawwnhcfrjzfqdvhpfwrjcskiqhhvmssptlscwyifcapfwrfmvidpjqripvkzhfteganzjlztofepmgclkhegfnlcwqqsuenhny','gyutrebnwdstwflaupouqdbyandzehdodajogrdujjwhiqpsorjvuhrvefeqwykejvxwsqnxpshqoukkfrdhymdopidhryyywnqkgquiilgmqlgfqvyqpouunfsjebnbazhqzcwycobasrdzkotlqffxwkhspfahnixbfnivhxokrftxvvzegbklabintjmur')
+;
+insert into t2(a,b) values ('zorjzxcqcpljzwq','sianxkbswukxkmyrliiqufdujvokgwxvjermwrqkyywlotzbufyohmjifctmfssfwvdoejeegqmiuawvtnembceeefqgzmhkczvidaapzyjdzstrwzfsvvnveciwacexrfdgxcnhgjbhjfdcryjnvgwjqqesqolrneixlajfrzhvfvhknckujvpsnstqpnfhynbw')
+;
+insert into t2(a,b) values ('nygdbglkrrfmwbzcvkrtluospmfijrhpofxaxpyewhwyjyqlujdacuvcpxmhqotbyl','mpxvhqzynuawnzfkdjbsvyyiraydztjrvvyhhprvtnmskgpzyfevirvccaayttwokyjfjyalcuwvidxkhpfnjbgwza')
+;
+insert into t2(a,b) values ('iojyltjyfdoavcpddzoidekhjsoymylbxlihuibqxssyomkuepilvfxiudnibkqgfonlyhqrxeoetmtsakmgpycubmuhejcwxknnehjvveqozbezzwowrhsvwsckrjanticzemkdhtshtlzpxyriwwcxxvqgnmrxtmqgtuaeouzzayrckhmudrwbcjpxschzbidtosuutdgghckzuwbpqbb','qlzgnjpdciwqjylffsmgxloyxgfdtugwumfxplbqdlxcemtqzbwbssiwtuyfuknrpppwwsaxayluxtyvbaiaribhpcpvqqluvqnticpqlkrilmsmlatijtrqacanmspvliykzeyryxdpjhcpkzhpsmyehwwmcfmdvpnjodwpdlvdocvjrttkdgertqyucmujxtejlrehbbb')
+;
+insert into t2(a,b) values ('xuczbdrhpmrvmuplltrnmewhcfylwcnmrfroeqfbadukhgvhvpwwkjrrgzxdqomwnmaqfcnsqyrrbdjrcfxotcbsjjtgxrdjinojatasuorbpnizyttjbxccikyeujqdgickforlhuxvlkpfslitgvafrnnmblqceqpzybytxnqjtjwhlisbjtknoarkqozyqdrgbvfzdtsvuxpthvlnaprwqrb','zsvvjctlsvsbumfwmitsbcjnfzzozgjtrxfqecdouuljmksqkglvrkzixrisdcaafnhpbtcyawffvjfmrembbqryzsikmoegbhkkqopjtgoliwknkqekjmksvxqcnzbhkrwkpikqzzhzssaqfwjodvnjrslymkmcynqpabstclgbkpfepzxbqqquppiceelpzy')
+;
+insert into t2(a,b) values ('engvmqdpgyszrcyxswuqqaoptwkffvqaxdmcyvkguwqsvfygkzbagzosnhhsrpuuocwovkuyoxjhcvclbapwrsojas','nmnicfryplxwrreqjzqdpxdbnendstbbqhfregnelduxlchyrbsoyvhmlqrhmkrwkboqsamluonsjvsnzryfefjlqvvyskhhyarcrlpvno')
+;
+insert into t2(a,b) values ('sjgerqcprpazmwoqsqkgpsybdzameecgltvsoukkafetfy','tvbsjlciuuzhjjuyzglbzkmotmqsynafzfmdvbrvytopendsbsoeiyhufunfpgtbswmirrxxsvilvvrqrywddyvxufqiozcdnhwmmgoqycjtlegtrrsayzoeoxqfksmynoljtbqcjluyawnpsvmvpjamslypcszhzdwpqybpymvgkzyztsoaltzsfcasslajljcxvzrebuwrwfbqxcxbjqfxvmrjeuqmvlrpmsizsewkposuwidbnzeswmzo')
+;
+insert into t2(a,b) values ('biralqiisiy','qngoxchgtneguoflqedwntwmmbrismprkfwthvzscmyaanlkcozhvkmccatinyvlkqdxixqplctcqsagkpjiepuzmxtgkldnmcirucdxhxfebzrgxuhmqcveeeggghuimcpouhgvvfrabzyiiymlyjtnaisaqoeigdgoprulcrtuubftkblkwxxouehyematavbeyogzqepuijkxiljztjyglhugpx')
+;
+insert into t2(a,b) values ('szbjeutggxmsgnoiemyriyzwgmzsfsuwqivnpopevhzhbptkfefjlekbekxgzewncbwqmwnszpqwtsvlsphomzmnclurtiuczkiaatzvhdnlgpnzyyccyecqjusmnvndvenpnlsdkcleemjiwmrpfrxixyexvgofljmtwxyyxq','fzdxysamnksnjzxrgrajurbuklpmszlvkovyzlyogfsfjuhxtrzytdvpzwvpnxz')
+;
+insert into t2(a,b) values ('lpsptfmkggvvfjwzpqpazvlfzsjhlulhnktqknwwbyjhfpsttjpysgbauudvwwomaburvgngbcozkqnpkcmjgpvooforoyqsnsvmdzqiseztrlpegoottvoseqcbdnaxolgxxzlfoygvrtplrgxucmrvgwpfwarqoyxqwelpddzdrcslxfhqakqqjacxgkxzvobbelbppmxstwtjutdpgekwhdvqmbhdzangyjrbytwocx','sqcgbfplhdjtgcrmcnwsuydwmugnqrcurrxjqswsquyuhndxvwgfidfwfrssbivmpqalpebmfdregchafvgwtelvbvskjnjgapklytifcqsbjanxqkajkssqkwmoftjukbbmnlogdupvdrcchgkpnuqahufcxnopeofqwytdtbulesaugzsdaqehtgqwbr')
+;
+insert into t2(a,b) values ('khjcwnxvssgogvzdj','sjjszqneeujwlvxyigrrikphqglgkapxzpjhu')
+;
+insert into t2(a,b) values ('szmpdqdztvjfejqlqxjbyzubokgvooqylajlcimbdhgdttiekepbvnnysihpktofauuzvzlshyprnspotoizbekozacdldohdcnljdwttiusijtni','jdpcyajammrgftgaojszuyftxddiighfmupbqfgwbaokpywvkhwyfxnouumurwtsysehdybgqiznysccxwavxrzojepmseqglrrmlrhohmeikcykchfefgodbqjzacuiwqiwnyrysnjeatnowipcrzonhkrgnzrslvfwhwignlyycdeuajpldhfafwzsniemyulcmxhhbarqxzqkquyvpbysfizijlsyqoilhlplnyufkaq')
+;
+insert into t2(a,b) values ('vthkzresnarnbxpdrmmoyvytbshjkzrpuueaqgmxsecvzrfbbfwqqhsvltsvusanmxmdprbdtqbameoayzcfuhgycgqnanpjtazfjetrnnvfmwzuavxkcwcircnu','rlbwklqhteejmcnenzqgud')
+;
+insert into t2(a,b) values ('bxdrlknlpgarrudiqfoxkmjtjvrimkqvcrvrgegpoeyhpgautkhetshsltcjszavmwtydiqtquzrjmqeyvpxnlsgmsdvlycsatkgmghzxhcukojpnrieyjznrwnhzjoierlzhyzubatpxbvs','qxguxxfaaztbnibcapjibbujqnexyoujmzwtiuyvmvbkmvbjjmlszavvrgwtqkgmthgehbqndrasfsnkffubouuzwiiezyuqflhiahqyunngnyhwfitzoawdziwuqxhlaxdqygzarmsasvaxdfydzrfuhofanespvdno')
+;
+insert into t2(a,b) values ('steckqjnqohpkxzqcusdrlnpkhnfkzjumcrlskjxsktbxpkwsolvhsdxwnukcjhzmfcudlaxevrxmhcsrfarnyljcyjgkmkjiybfuycxargbkciwrtfwkufwzwiycotkwxswkpokgsevvtbkcqaefnogwmvradmyneoqjqrkfsrcbwucyiulzbitbkommz','kbyeeqzpowrelcyhioqpthpfnvsphurtskyzvovybzwvretcdfkplysqlgwymeisqgcipatpfkvhflijupavhoaczkfxxkmbbxevumelnflnglosayzkazpjwaudibjfrwudauznmzyrmjeplrgixjkoviyefjjtvquitqpdtjvnlfezuuxpkemmvkpmiyuosqxossuqewqqsqvbcwnht')
+;
+insert into t2(a,b) values ('hstpaevlucxoazprxaejzeunhewrkccfutnwgzudgqirdigipedklsszlficbhdkftvcfzscwzsmbmitraxwkiyoylwtvxxvauttppjraqqlygcesancafcqzmljhufkmschmpvgjpqhnwunwsgmramjyjidkprwkkcddkgtbxlwzxmmppguleejpcpomcp','xsaqdxfzylfnyzcegajtjpukzhlseaoftqdkuyhfblyoworunrxsqeawvwdpnvnzwetbijivgukhtzhtixflahdvtywvulnahgegeisfvuqymcpgkdysrdggbulkcauzxbcf')
+;
+insert into t2(a,b) values ('oxcrkwdukjuqtqscshcvmgcitaowpelvqlnvjzefffxyspdgibdsqcaqwianxtkghovjxfhbcdvkfnjrrwahoxgryuvsibsmfmuclizpzbfjtvfjnlvqruajobhnejkpccvecpcinyaqlwbougnfvqakukodyfwsgycdfrukjtqiwoopyjfkuzckhjejhogwlnfiizlcpeghilr','miyemhkdwqctvo')
+;
+insert into t2(a,b) values ('wjtszhtpegjkpbaqyofyamhjdchgflsyoughzqnpnnzrbzfichlqdqxfwizsyzptmzmkpgrrgcekhzwbgsipkcwdnraasnbkqhoamqgaktsklfgqbzacxxevzgogxxwqpoqxkziujveuvbicdqllfekpnegmeyefpsmretdawwzvssfsrtwsngpiisxdsmaxwsttoxmvghvnshymjhdazygahzjhlmhkosezsiabngwcuemzasdrskhi','kosnpqjljspsbkxnqqtwtjjzyupouneixrrcf')
+;
+insert into t2(a,b) values ('juyksofskciwrvvhbvrclnysikeukqzwskgqwrhasyydhzaqxgwkhfkokrahmqwyugqfxvdrhtxnpelqgenvzffeoqftibrvjenkfqlsaqfammaaetcznafsvxrouxbbdbsdlghaneyysmakonpskvpkaqztcjsrplvhzeoipadxqlcdi','inqgoqrfbvwvqklukjafxlwjvysaikwtqopologxfqfsiqzaewahezjudanfjyrlarwemclndxsocpgodmbeqgeuyfxgrmvwwujbnjoexwtljiwtqlqsdfeprpdpazfkjymfasffillrckhdocmf')
+;
+insert into t2(a,b) values ('jxwytmqtjsfjkrttipqoaqhcnehlmbwnrtpvomzo','uycxegezzwfvvaxwexfujmjvqkpkqwinpaikmgdchdgldwcwbuaesflzrpeaatgqvlwneknszwoyqtzjhzaoscieutiyjkefouweuqpbazdaeyfukrxcaapiyppyqlahagczeinskqpvswbgovfmistsjcpuoisenxiocbycjgmzfqfevljhdniivsnarzdhhnwyhctrffhocvefoincujexivxikcjlxvlyxlyjyyvskzfuxevdyceh')
+;
+insert into t2(a,b) values ('tjnssslobahwgyphemxtpffyofqsuigvqglujheulplnukasejbzwjlglrghbqsponzldzztkykflpzdlarscanzshasqypigdlqlrefugajatxxkexreumcgsovutyzisp','ksqogbcsxkiaseqgxyobhbpxasdgawzxujdbeimtxwamrrxrnmwkheglpdpfrdspbrbjqdjbgxkossqbhssxdidwrqciydystpishbmsemupoqtrvatjinwymydimwtsglpbjdggyzrhgcefgxnonkbibplkjnyfgodexeu')
+;
+insert into t2(a,b) values ('cshhdrydtlfgtzhdccfyxvuibuachuqnjxmkquvcylsrsoaqcpiydohqtitkynbyt','gksxhvqyoruwhffbgwozhgcwryyplvxiidzghtcmybhsclorjgsppgiqvuavjnygprhrehdwhbsywmqdsxxbxiqrlfojlvimiuaamwwwzdzyalcqeoxunkbsndbfkcjohvcljynfcnotddadjfawstuanwgtzzgtlzfcupltgqdavqbvbohxwjhenlmtxcxtwmwjlnfzjdklychfensbcbnjjrtcvsewhmtgffzggksxqfnemszubsfcgy')
+;
+insert into t2(a,b) values ('ibdlofqepjprzfuhopsihlawvbuuxqteibxtekcsksjmfitfmqetyqazlimlkvjsqyuhkcdgwerufqcyswmomitmtkjxzgpbyvpcf','ndrfedokmwxnuiiwetkytmziwiyxfqkboqeqvrwswkgfntcsilimhsomhh')
+;
+insert into t2(a,b) values ('oxydskeniutqiuwmtjmjfdvnuiadctnmtfedyyrzpssmtwyfithhdlnqfvdsaxlvlddtgtlnczhapdmxyxupzjangfvicdcrpqwazdlyeybjboqshqnmsgxmpjbwxmphxnejduicnmfmrzrjgdlppbtnokfrnvbzhufqtimxofxb','ycmeoyhrovuqpvgqntkjmhjnadrbpddumwjlqkgfllddlcylrzdvlymqrvzzmbgwwqkwizepcwgtyedjecheqadcehcyiaxfxqlcvpsdnuyca')
+;
+insert into t2(a,b) values ('atozrrolotsgnpujrkjxkqzcpzchoskhfpu','blrntgnvfgvkoxmdqlhhwjsendtnvhhkxohxzxwfwsrgpffsgnbelqjyiokwjyztjmnptszvqkvwlgerjoarekymchmfmpyynsplerkmestrebqlsjxkxaagr')
+;
+insert into t2(a,b) values ('suhwwofsbsvxjysmoukdiujxsyhabbmwbgkghnmwwiztxvcuvoz','shgxnpdfteirbhlojtgapwabxjntoxfpcwlbjpwuzpssobotzcafbxldmflzbiclsdikyueezzmeoeidawzjbwnhfmvg')
+;
+insert into t2(a,b) values ('lcfizxfdzonvodjnjunjzxmyqytkpxwxrdhoocwwpajjlxzeygrintkzdcjhjzsovpfuttsoefbyvaabsauniqdyrkpgeqxhvatnazjknulckashgjuwiwbivbhlvcbjuwbirapbhezzackmcpwqnokcfqjevkdedmxjsijjhrgoifxoththcqiag','sjoqwdbrtikwnvexbpyxiyxxpsqzzniymodlflyjhacgviiuunoamcnkuiagjtbwigjcgohujgzwxgtxniocsckykybfcpvnicbdvdwrngvglyzovxsfkdpmxfebkyaqewimswmeikylkzdqquqsgmjlxfrwrqbdhwiv')
+;
+insert into t2(a,b) values ('hupvhuauoozrugbganolvjypbnxupexdafkejyksvajocnhzsfeslfpsxqtburdzsvvqbrjjlwsrenyyjtgatzbaxsfpsstsaljjyydiyphenigkxsiwyxyzdmlcchrsatuodzgzgrpbgmknkzswegmanucdzuafj','jwpojhnorlowbywwrdhcstxwhnzhidmiywuhoiujvxgjfcjozxjhzkuqzbmkipj')
+;
+insert into t2(a,b) values ('modyznuwvkfvdbjnjtwhqouilftwylpbslqgqhsurwekitkqxipgceiizjrffoqgddkmtrovunyxhimunzxtwpvzpfczcdhqmtgmoobvefjfvfirzcerbizabrixcmikgluomeabhjhhzsmnnsshhqtvoytqbzdkltezjnsaxfebrqrx','qbszquauirephxhwfebafqfdzsytgovudtflzbbhdlwmwaqievysqijcaalzqlgdipyyefcplbfxvmdueialxjrrkdbuzkabalobdngvfplqoshmdxhppaprxrmpsrhjudbsreqwhupltyuxmlxyjfsoanzfeodrtynxxlqskuihciimksiobivuud')
+;
+insert into t2(a,b) values ('ibjvwcnpjhezdkwecnoqrjtamygpqdnnnaplf','qytsqmuwbecqqeybjpdtqgzpcmdfgtrgonnxqfrwzjhbqiqkjmyqkqsxtiodayyhebrwekgzhtqxjyyxrxnhhaihhlgspmazeqiqsblwpgxbvrjxmhgnqdsigzgycvncotanbraizmjztzvcyajzuqbb')
+;
+insert into t2(a,b) values ('xwdxspztkctpyofwejrdhfgscxipparrpwkbxteycitzwzoumnmhevruccifdyvvlmrryhbhfbbvdnqxcrzdlenxrwofgiioucpxvsgnxwlqbgzjsekrbigvxzxasuwgperdwvfqgwqmreouoaaawvondqdergcbioeooxofblvwaghqtekhizkiymdiarclzwhasztopopsffflybnavjnncbytjrtqnainwjkotqichmakxiwsay','rgzfieevyxrwpkpuzlufjfkkxokehhrvylrpvfpkbwjwzpswklgitqbuumgztvzfhjatocpqafsdmtxahhhxeokqqqtoeuznwsqwqoynbsyaadyqwzrvmjpvvmduzfuopnvyvmflmxjlsawejpjfzqtufcfuvwbgbbwwtzemncnrubkivsilxtixxbzykkiaaghxcqlurfdswaakkidwbxucnknojcabwozfyioekf')
+;
+insert into t2(a,b) values ('voevsupojkcewaeczdhuzawncdkafpvdjxqvarxfvhmeuwmhxrhbmmvcwhcqaqwyfepgndoyzlaagdmhrygkhelxvsaio','pgjehhoahsfsjvjngvlatmnpclddlbmvmresqhvttuh')
+;
+insert into t2(a,b) values ('dbzhxrsvpfccmfmkvmrljfsyzomsfmtqelipcgqxztnsevkcdyqrgrholohivjswelsbcmlpktentzisfdgugvzkndlugytzvugizpxzzvultbtpnjetdcqllwyjxtyiiexckrknjtgbqsmzgvsaimlyjfnlfizskoyvkwkoqindflxttqhqauoxbrcknhyclt','bywwpogxfdgsfadzgcjxsldpikvcmnughbudawcuxbdeuhclfhclmooziynyibtmianmlbnpwdnumxjwyjgbjryqtaklrgrovqmsvtxo')
+;
+insert into t2(a,b) values ('denoakpnarzjwiklvtaqmxqksoufipcamhhiudmrwvlpgxilcwgcqihgbsuecehxikxqrrthpuimhfvmgbhnbborxehwhzgvylhieqgjvpxqbebctvnyhcrzdgepmcajiqwjufvqrugilnp','vtorzcbrruvrvbqvcrzaduyslafrmhpnkvlmqwwqvtvplyxjtghxprxqktjjhckipxwpbnrvh')
+;
+insert into t2(a,b) values ('qzbtoschdhbjqubidslkmokxhijtjpqdasvgljpwvgmizyujccyozxlkjkz','xefeujjhzlcqubcipzxzolnqsniqwhavdonsszyzttcpoypnxlabgtvybtcsresfwvbokuqpmpviewmngtxagtyqfjuvvexvobvvgsffhfiuivpiqrzaezkvbeoxuzhughbeinfgirrumcmxq')
+;
+insert into t2(a,b) values ('yzefph','ivcrygvtrylijzewdazwozlrbmgbmesnpxxusoejamvsfwgscipkiqdcgwzqdhcbnczugwidomeqplpijvpqufbntfitqexcdgphofvemztvmjiublormlljtetmtqqrlxxaceogfjppassvxrvf')
+;
+insert into t2(a,b) values ('xekrixzuzmmjbowwr','vobrxnzpcnxztnbkhoymiaxayuvembvtsyxfsqjqcqpipjzohaaumjrxhovfghcpppsuhjvyrejafxfeezsrsyusjjgugtlwwxcstxuqbnnwrketrtxhjecnjquhdtkwwouqzitzoxkochphgwhtfimufnokgwcwxnunlhdkxjebzshnxjebmquazcutvnnkjeprkndpni')
+;
+insert into t2(a,b) values ('xrznovfnaoiujfraqtawyhuxcjqlxbsitlbeapr','jzhhlroimljlcdazequzolxwsyjhtyvpwwmwkamzqilnjaefdmifebmkzzmfcnhlqppgdmqdmhsggyjaucsqzrrr')
+;
+insert into t2(a,b) values ('whdrqdhncfnjdrcvfzrmhltqqpaelmhmxajxkqaajhfmgztrphixuxhhmaycznbtpgkslksycwlkqzzalwbzfuxsdshsxehfnzickmozarbkchfnmseeapchvsukzimxrkppdyclzapdmziyfbpsyktiialuzliuekakceloxkvrqzmqyamtdnowbxcldapmrilfxkeujrtejugqmfgcdawjzksghiguerxvoixh','vcohdimhfwpmrzfybjnjxnoquvrmaodzhbzzqyzdbtfvg')
+;
+insert into t2(a,b) values ('uzticucjjlixdsfkgiyggivdwfauuwknsurljtkgxsvglkbvikztrmqqdiklorfjnfbnyqxaxnskucoaxgpsiwhsumvvqhsmhjbmecqalfunffkorplhthxqusaovetoukolhhqddcvxjhsqdzlqjvvzzwbyhucktglzllnvdapefwvxleppotoynlcfbjxsijdaghmp','jrtzinauuptelnqnisbrlpdktadxuwdscihlnpvhkswveklzeozpgmqfmjisavwgmbfoluxondheukjdedritjtgosajyvgpkocxdxbnutygofatdzoflmbjndt')
+;
+insert into t2(a,b) values ('ycymsjmwypnnzbukeyngapimoqilolrzovcivfszrkoxbnkxhxfrefhkgesplsyfilxdyedtgbxmrzuveepwagssgyj','dcwqewckucsnyvqlryeovmcnmnhgxbgyqigwlgmdbauwaiabri')
+;
+insert into t2(a,b) values ('dsbxddmsuvspecmzotkkbymubslczhzactsqdcscivpkqzqbinvudubzoghivrwvwhlnbbjurfpzegzyuffyvydsjxaugwyojqcoefjtnxqqnhvycomdxiefwyezqvjutdanjpvmhmctrlyfisvthntlelpihnhaienigbnfdzabpcszgaoqcppgumyk','kppusqciwjlyoythbxpwsnbkrmjtvkibcarmkbswqblpzjijjyozcywuqnmdmzqklfqicryfzsskmozryxrtosmwqfttp')
+;
+insert into t2(a,b) values ('uobjeapgpycqnzcybkbocardnofydasagnyavkajtrqflsnhcfisvbrqbienopzkavokyauhsuieunhntoslkgnyjpyjdbqprhalgbmswjamjyeygkmglaxjlspsxokrmupqcfpulfwnhhewyyuidhrmxurcyarqbvlyduxcbgckzaesifoxkvizdjwptyxecewfmgcaicxqamzmgwlmbwjubgrjxhvvjeiocxkkiojdhxpotaukelx','jrlofhwgdxbfpvcwnbshjonzqpunxbxjcbrgwdjqvslbqovxnglpbgbffrnvzbvwribqzykcnqsjxmvufmzwgmorshiwcvwqytgltnlfxcapyyulacpiwqemzfbetgtsdthttgqjseuzucjphduydcdnvibjacsrhqakdjorbsmzw')
+;
+insert into t2(a,b) values ('r','taeybzuaiwwrlzsojxbmysrluoslsdejoyomkxapstcrndbmnwdzkvkctgogahnqlmpyrbygnjscpdcagzfuwktzlveiqjkeslhtptlvnrardqygxiccnodqfpzazilehsmcfdamknfhrzcqurypfyrtfrvlaevzhapuulysbthifqrzbddeahdxbfluvbehdoaownytvdbpnsgzjrbiotqwgnrbwtxdvfgelnto')
+;
+insert into t2(a,b) values ('lwilwoefykrxskstxaluzjrjkye','adbxbjbyzvsnypsgesgkafawscelkaocudfzaiktyvovqeipojzsoocyaqxyinnidiqrsaczegogimwiwwdqokczrc')
+;
+insert into t2(a,b) values ('xjkpdzpwmqibayo','sxmhwmkohsusvopwvidyriivbuvfoxtgmogyxcwtlqqdzzbg')
+;
+insert into t2(a,b) values ('ywrxsdcoeyzpakfbnqtkewniiactfcqnjqtdokdbjdtflboktahhzanjmuaioaeyyqnzuoucmzpqumacqwvuqgqfbmpohqlyjokvphgayfnkzqwlpyktzyguhfffaadsbagfjfbersnhqqscommpaidsxlhnjvmlxtzejlmydgdzvbwngom','fssetcfvfosypqyjilbiqecvcflsvmhzndzqcbnmrfheaofbjeijnklzgvahylydbcdzadpoqftsaqyecectvgjrkt')
+;
+insert into t2(a,b) values ('zhxiivyvggstvtiirjehsolkoikrwgvopzfcnu','vwimdkdnelkgvwoqbghtqmczlyajwompasrtphzrjhhjvaspnzbcsvgrcdrvmycrhpvvoujklsqpttjuukkdtnmcuxynrtliotfsbtasqwvvqeecgn')
+;
+insert into t2(a,b) values ('xqrggujemmaaorzjimnrzamkaqizpysgsoqtnpgaoebepnftzxduhapxnuhhcenbgzhpgxnavblnqakfujqovwwhvbhmlkrsqoskqirbzlcuvrzwbmifnqrcxqybwixapzxkblopihcpyvnuvqnbzjytveedqsbrfysv','mhqizukkfirnivopbwmskbvqbxohnphbftlgqcwxhcqktygpgugjsrfzxlmkybryetuwwqlfghskypamzkwqkdvrenilymrxifthxnrxqgatdadfeynyeinjkuhsfwlhkyqojjcaepvwrnkxlpkkykviyqxsqobhmpsvzczwtgwrcrdalgtychhtphtxi')
+;
+insert into t2(a,b) values ('hhidzeovjxjhxejjslpzrztasttoycmxokfuowwqpktwqwvkzfqtjsyxqczqtmkwqcwuydjrycmlfyhqxvprgkjxosymzrmchpelmhjagburbqqlmqkpzpesxkrybgwcjfuqaykosoltxgcuszafvvrofne','ctdoppfr')
+;
+insert into t2(a,b) values ('sqspnzzrgsfujinpdvtfouvfatluasgvbsnhdpikqdgaoqhgyavbueqimwobpepuqyhcbpaotqmikxzzfrxgxsalqmxqdhovghftuxfrgqrvjkcmkseblmwovrkvyrxpqbqdqsnlsqminrjawrecgxidxysddavvybxdfmxemeaklwskepmawsksjctanhyzxvpxcylgrnkstojyinps','khdktdlpqdtdmnrkicuwxyirjgfsoyqfzybhfzahvkdkpapmyvvlskgnfyzroiatgxgdgtglbnmzyzrdffobkgdzcaaavvvpnokrpcfxpyihpwfotvrxxihgrckcxpegekmvhfxcfbtqvlgfsdabecxssajdqlxudlwkdixyxdlvmyjzunyomhczbslwhert')
+;
+insert into t2(a,b) values ('uoecwjzstfpzpl','crcvcganehqsngucsbnygfoplrieeoxefujykvrqvkjqnneiwdqb')
+;
+insert into t2(a,b) values ('ikitjyhjbpebuxquxwkkkednnxrpesatdbcksldpurlofqsoncytysczwbzelpuvgjhotxnvkagajuxtllbtjgxvwetrijhyktvgsfhcwbdgrrhgjkqdfahoqzkzhwrdfycpzevyptjmllgajappmvnemmopcideoox','pqxagnsgjzyowongnfyndtogbskhsxdtkkemssnyziaffryggidybmdrcqhdkjjpxhepwtgbxbgldyszhozfqsmucindkogbelntqyrdbdkpduttvcdqfaixvtmzhqzqzjoympfukhwwuhvuasxyjlomvvroyzspqukgthnqgmxcpizmifzooffnkrkjwkhmsqjinkdxexqiotawzyuebhdhqsspvnxhr')
+;
+insert into t2(a,b) values ('feotrdtyniyqgqdslumcszyvqsonwhzkyvrivhqfbkavtuaquthegbrfgplkyzgewuqiil','faepwpdjdpzsrhlnjzpacgklmdkvxzjxzwmnnnmsrkmsxaumlagoqpnropnxwnmfrzxhavf')
+;
+insert into t2(a,b) values ('odruqdkolorvyczawkedqoyjbzoknlsaflzghorfkojldzlruevzvffqhpcdfqennikhqpqucbnnblvcvicrcmnxwsqiieainmyjl','pojmhvqbuwezfatosxpfeiopofuabcsborlvhvnqpopoyscfbchitvmlahwqqyrcypdzhedonbofsaqycgcjtlz')
+;
+insert into t2(a,b) values ('gcqoygfqscpmxegocqqdqnygxbdqojyglkfyltvputpkpjnigbfqtjxmh','putmsdzvvmntzcyjjnlgbsuxfdmadlxgkqlrjctbntztynqlpspfr')
+;
+insert into t2(a,b) values ('wlmxxvrydzjczxqjinsdstxhmetawwygtmbcimypnqaoxmwigwaxamoqsnblvqbbntsjtebujpmsrdfxnrlxuyevnmimpuuqdjjictanrzdfhzahuhisgwwtmhzesdxzoepxxpuzsgjbhklnlwvgqswqascbdpkvzxdvylzxitxatomznmuaskope','dvqevtjkmdlaifcwcvgjasrtcxssmakjmgfeeinatwjntlwclzuzkftvnixxqswdituvqcxctnrvmhblomvdfffnjiizariysrjovolfmnfwgermmyadmfkkcimhiddqamthbiadoocjepntinjgurfxnzdmyvzvzcpalqcqmlufalbjuohbfmegebnkleaqpemqlhtxpeqwucvxwjngtzsdlnn')
+;
+insert into t2(a,b) values ('wwuoyepgzhvcmpiwpgmfsympdcattqnqfjracjqcnpmhpamrcekkrecikowgmksmvthzsgoeejowwjukrsjgscnibhbtvwugzlb','yjszpibcgwwrrbwbryoodygxtfrgadazqavwssufjlbfcjkhisuinihoenkjscoicgryghsdoibnyycxjfghuimustilyygbdxwzmwoklxivsuucnxwgwukrgsfnvnplnrowmhdbvmjkyajeizyosjosnjltvqqmswzuuyanfdenwfxpibwxdadxbcb')
+;
+insert into t2(a,b) values ('pucuxycazlfonbuecdodpbaqrsdbrxtiqiatlpizlzpuqgtvpzgefsuygbgghnblsvwoaioavtnvdeozovohidacwpgbbaqjrppdnsdvnrpwvktbxdevbeberolflbecvschfixgvydzhrvnrmfyeamnrqylybowkczndoxeboblcoolisuviorbyugiuuhxymiimapdjnvfpgusabrhofkeaengqbsym','mbojayyaktjjfrltenbgwslekgylrgzyzcfwadujrbpaoobhynlnezwmydsrbaztpfzorvlbngnfbrblzrnnudzkatrlujynyjjudwsroqiagshpldmnphhmyvnshfxjihxcaiapgqovunigeoyigxiaczgpviezfvhixmtrorttlkzmovxycocwcitlpqsjtiemustkvdkzebqhnacssbpamkykqvybqv')
+;
+insert into t2(a,b) values ('qpqmpctaktsvhsrbsxnjhqimmhyozygfesbvjgwcjudvszotnpsrhzzqqaissyrcsrzfrmzpzkmyqvofqgieenkkwfqibzocdontlixsrjhm','tdxahkilrjwdqgemisedatrpyawyoeidvrqtzbjsqigasctjhxescuhgcccjhwzzzxbhzorxfszsrhblblcnmltssgbjorxwjqfygckhuc')
+;
+insert into t2(a,b) values ('lqinqaimbxefjbjmcipjiuqsbgsetfivqxtiwyrksdeomsshhvpoavncjycmzmqdvadkrcpfjfvvfbwvnatkuu','fhlcsjrsbclamfpgtenzzadcmgtuyfddnblsumjlwtkpiwlcikccmhrrqaswxonfitmuvvjrmvlgtorffmbvyhxezmxocencdowkyecwmqqbznagxypqeelyimajiqgnzfbplgdpzfppapumnfpnvroguxtrcmqbijvkajqhbwitydklnqczaozovkiskwuednptrtowak')
+;
+insert into t2(a,b) values ('gxrggwnkmzfdrwazishmqqppbivwcquouljbcbyndfvklprydcmyaceprhmyoqyvkpmwffxnfomnomppiogkjrddenodsgagzfxoxddyode','ebrguazjmrhyfmbmsigfqodekmlzegnscivumnhpfyuhdogbpehqceqvyerwoelkvurdutdxikwztvioqrzkucofodtiwdujiytas')
+;
+insert into t2(a,b) values ('ahyxvikcvkfufaashgefnjwfqxwshkyqajwgumxfbhgeovpcilgxbmupdvnudoabgeodbsjdpirgphxagqqmmglbsfxuskwwmjfkccbeqgytlttkbuczvdzvhyegduuwlijmfmlobnqhhxbnjhhwtpyppcgqjlwsvvaafawzwfikpoqviaoeietpuyhmxmtbtqpemqmmeqsjwpqsiequaiusblxuwhjaddlzmoxt','ermcjiynuwgkefanrtczpjtcedgilzvaigqypfatnge')
+;
+insert into t2(a,b) values ('keibtlmgtadztpnqyijresvgyf','ttwtxjxxnvzfltedasmxekysxozsxaazdbafomylfmgolqxtpyqiscnovlzlutjcqojjpmzyeyylpqzrmwdubexwhwqsfzew')
+;
+insert into t2(a,b) values ('yymspjnwkzwueiuwahogehfavyjucwtfttcnjojonusejepbgeeqmgpgonizmcqihfukbazoydqjqknfhitzbggtancxaaclmquvyhoovwdpqwtnbbtyilqyksvorfwoocjrrwzckidmkbodkmoyssmwlsyymgpxfkkgznlvsvsillmaeuqphemzxdcnfwedtdthhmaxhpjngsuuugaxynmetznjdtetdnamrdtqlwybrshomhfkgknt','imrazrmatwenldfstascsmbdhiyknjndwazgpfvdkfpglrtuzwfrbnlibyoemmnnrcbijwhpckwvwfnxqhxsolscwzrfwbbpfkfoszswwswpuqtzlwarvowytfthvvam')
+;
+insert into t2(a,b) values ('iwfntqqyoeypdzcdnmaztwouocssuvhlkixvcvidjzfblcyuzkbdcbgxepfikklpphxknnxabribcydaziuklskarfakoskyshuehraqukyjfihwlfycakcmjkvbjqcdozjzulgqqnkxhpwvnyjdrrqiwzkdzdjilwzdfpqvyfeztdvskldjtrfgmdmyvjpegypkzybgwsysougmsepywstfogcykqhkjjoohtritcweslhchbtsj','fnnfisjjabikgpnypjgzvihchiwwcfkygkplykrgcjqvfzmvtimkowowaxpdzrnafnhaxezywgeuqdesmmgzzfhvrlovgltkfeylaxpuptdubqvauoyqgdhyxhdaspqxmabrvnsexmkpflubxfdsaqscynjgxiqdgrxcaxkemavibnzffhbppijcdfnvssallcwsmvvlcmditddjmzmqv')
+;
+insert into t2(a,b) values ('nzqpcnroxozwllhdaaccfgbbpwtdnsrupqkdmktzmseuzsyssdokgwelghmjaqxoclqgpfvestalxfrzxepkkcytrilmskvfqatpfweiwlayzeiahetucntvtdhvidmscsjihtfmlsxfslfgfbypxbnwmhucmapmsmwicmkbbbokd','souhxlmiboredlregqcfebmqetenypfasxlhinncscrukdoeeuzyobxzbumsxowylwmqzxtnhgolotkrhaaubxaqrguquwjiisuloieazbslhga')
+;
+insert into t2(a,b) values ('mloxjozueyfhrghpqkuflmizbrxwzpsbbabiecoiotwrjrgxivyleickdsodqdxnvgdibvnzcrylyveylxwt','rhnsnbeiwyiutfxelneawzcfzkherinfksnfnzciutrzmqjinwoerguxlewgvqofxitnlhgdhxudwkgbprpok')
+;
+insert into t2(a,b) values ('wojzsdhomdwpfvlsaramjvmmqulhncibalqkrgicxbmtpwuqnbvvufmachefcakntwkmnhiznpfkwuskaeivlduzecbpbcioktmzilljztdmfqwguxwrsyksnfwheatpehumvyibvbsxukstbquvjkpnxvxdajyizzigsxwwmynybojsofxxyomdllqcbmzeeimtflseskvsoswnwlgjnsljwusnzkb','qscsqvtejjwrnvaunlytizmatjidbeyltf')
+;
+insert into t2(a,b) values ('ynkcnkrurwcqpwxbsmnmzevinwmwsmpncvldunzymqqjnukbxxxcrkfeccvjeljmqhxoocececalrrqugh','lydttkweqmqfpcfajrcfozcyzsrwbtwwdfvzshshtlayzdgdcvhtrnewrfhzaqsrtsikovepxhnlivxfvrbnjpzxwkvbcxgagbtqxlksinkxebixuxcocmdvsolqdpjeujqevspmofgcmsjrttdmnf')
+;
+insert into t2(a,b) values ('oeuieigoeduzlwezxoivwgnkylhywulyplpogqrhdxfxrxvhpcrmmzdrfbtxcztagjufmhzlirbedolgusotrwgtexautiwudhlrrgbgvfluqwqlpcdcywammwonzbyfnczmdolzjbpwutsqrtemfovrrluenkiwqsblmtwnfyllkcwwpl','takzihmvpowou')
+;
+insert into t2(a,b) values ('tbylveqqxmiqytkfapnnmlhmcuothqlvgtprwjdbtgronclgweebkoavvgkwjoowlhscbyqgtdyhpmxipqhgxllltstijpohkwqvdzkezhxjplmwjtfxoxeclecsjrrbaxpifjjkxtdcnvqib','ynxkfffsknuiqmvhskyibexadhrjsthibbbslkdhlbjyrioediwwhsqpwligpkgroozwxajgnkwuandpcxqhlfdkfkygobjlnmslqelmactyfvpafwknomuiobyrreijhjrpygfnpyqvgadybtylbbgvtnmpqlgholstaiinvwboqiitipxozkddbnxgwkarzwdelqoekkftzxghidmyj')
+;
+insert into t2(a,b) values ('impjiktiscceufbkmrwldqolrkqpmnpasxtjocc','ofnmnqdouppwpecwlwgzlqokmzmvfzvrodhdvkomofwazkamvcfuhlnpdclpfaepwztolmnbnicplvqjgnhmmtbfnsicxnusnhsppyzptkkkuxqdvzeovwmkqxebamskwjdjmpptvqkimimwtfqpa')
+;
+insert into t2(a,b) values ('vxeajjjjguvxuawfkdgnuyyvlgxcszdjqkzgrsroplsyfmtuqouyrgeunqbkbtnktzvimipjdxhwzupxbsgqtkweowtmfnwiordorlfuovoqcuqhvwwzfiunyvrkybjwdgeftvshmrqslkxmgjtdbzetrwjasliwq','vhzlbsnketkgraztncfeeynufiuqmbikzpzlvliofvlxaltmnhdcvvmvctdlxmgqamstqtgozzbkdnmrewgclykenullguaduhznvcxkbbjscytincnlklwkvzwzutjwsaqeoayfkaxremjurgejdgmyxtqtxrfhjkoajhwsaxpbbpxswbiadjfsczjmmojfqfmtlfxuilfnffqspsupoqyugutscpxrtymc')
+;
+insert into t2(a,b) values ('vfmwrvpveipyrewmtxjgjalxwyiyrejjuyjfixbchewnjbuscvojfdlepgkkxysygdizvyloorajksibaaingozzhhegwozhryfdvnarlxltiwugdvzvexuyyadebwlidifzjoasmbdxnbyvfcxamfchcimfsebgionyocvefrnlapgiwoubofndrzugoahoekj','hdakpervvbvyzyckvlntuhmbphfdcfgbajzklkwrcdrjxhkbiomhzxupnzxnklqboyjvcreabzcapgqsogrbohcyavgdziuvpvyjqanmzumblyklgnhzsejbqltvfrntsapanpvifzivxaolju')
+;
+insert into t2(a,b) values ('jmsvtjroytjggclwheqjjxtifqhqoqnwakhuecuicpjxrpxlpogofdyypcizbkydwolqefgdhepnusblrtxhsdbrwkifwszbytbjaeindbtqevpeszmenpbimlohllgtadfnzbphismliyxzemtqgxdasewzbewibptdylsgcbcglglzlpmnsdevdmwebngmhqviilbrfsjcvdtjdtquzxrydgexmp','ytylxnxoakbpbghpxkegmbqhupgcdizijv')
+;
+insert into t2(a,b) values ('xlpiwjjpcglgz','aawcvc')
+;
+insert into t2(a,b) values ('dicdmnakjbkdesnlcvrzieojrovctwtldqcvxbjbndzwaqvhxjihiosijkalkjtfhly','rjmjztrfjeapbovyxukatqrprjtbvlqrelfxjpdpxzniuqhlaqpasaevvkuk')
+;
+insert into t2(a,b) values ('yfrvwhlmfxgwzrxetgewermufnkahtwvwiuvpafxcqbkriblveuutltqgfvfxobdfqylouvdwrcsdgwvvfijtqojdvmouxlsdovbszywulxnoxfwaakxassplbjilcntrvotxfiwztjhnhhaepcmafajs','yvhloogopywukyljhlsojcumfdjkgjkgkhyeytneipfykjtnrqxmesauhhwimpaaubfutybhezgzkselhjegbmzrbbpiggagdpqcaukzqsshlhwsocswzdraxncewfcpbaapmbeqbuweozisihtuqpvlzpulririgtxhlvzpsuycftosdqpvxjvvbubnevjcmsvjubwyyiklvtdsdyofjingbijiepycxjwspsvrjwerhzerzcypy')
+;
+insert into t2(a,b) values ('yycdsldebgqacfnvbxzdhvgvsmzymedcljalgjqbmlyjhkitxlpuzzqsvkkeykajuungwaaiqnfxf','mhgsrirruuktjcxqobgtvgwofybvpbhqntfsetpvstilxdiprwlvwakgaufixdybeiwmhhhdtvpbxcruehmgulgdbkhwzwvmtkndiqrjlbarpeexwwykgijcgjiickikprhxajepnlvyruekbzqllhhhinpbdbj')
+;
+insert into t2(a,b) values ('nwujklfzdnhtzqqepecfircrkysagdxofnkabnanmmgutdujbjzbswputgelawhjhxqsojmwnktdmvcbarglyivfotkhzefhwtwleylpjmwjupnkeyhrazwifonitpckz','ptaxghysbkkxytypptsbpkogcmtdxiaqouivafmkhtstusbmdvnvxqkeptckrujtdamnlvejisyuxhccahwiilnovmxsojxrrkdnjqocixukurffsxyhwnaqcgzgmfoxgqfzxemcvsakppwbywskgtjxoxcedjavgfqmyxy')
+;
+insert into t2(a,b) values ('ajjpfekodswkrgyndkiqcur','mxddsxowijgudifsfpxqkwpupqdvjczzwlwluclmoibqpcbxblnktkprfjnuasrgigrdkkaiwshpfgbkhjsqvwcuxvtdtrai')
+;
+insert into t2(a,b) values ('snidabklfejgvdhxozlpqjgqgggqeisplopvcejvzgvxrevgpbnclpyexkioutwjjrxiulsmoclaidqlkyvftfsfseirdrobjkjuiomnqtuxdahaoujoryxniksfmabxoxktkeuqieekyluqqizkkglivbbicgowvlaofhewoxribgtztwtujelejmv','jvrjdiitoyhboigtvsszzakfavziyimpekiacahasszuxlawyegxmxjqewkzscwamxybff')
+;
+insert into t2(a,b) values ('ylimohrxmuufckqmyiuvmjeifxdypvtxtaefopamjisjafgachxghabqfiinubgkdaofrrgzpoxigjbpjgotuepyjpteionchuovgdkrxjheypekqufi','kasjngopbrgbwnhceyew')
+;
+insert into t2(a,b) values ('qceeapigdqsgkxhkflztfqbwxqylygnebosfydhbvsemnnrhuimzadzhihrvztbbtnfncopalxu','jxdttnhanblmytzttfjfpdkkqcwlbhwyuxxzsvjsowezrresdtpcthccoufracdkcbftuyrzkreyxnuqntluvxowupjaucwpcmrkkrzhjhotsooidlyamhkoktlrbjlflplewarvijzznwtkdwrsquefjgviaxourkyjibmkwtswkrxdezlanpoygxsuymbrmoqrjwdqdmgkbyolqgtgmbw')
+;
+insert into t2(a,b) values ('xvlbirqkulnbimnjpozyzenxlmejthic','sdjhjjepulapjcbxgnxawalv')
+;
+insert into t2(a,b) values ('hnelxmrfjnphtkozyadhccsvylbompurqpltbqfnnpktuxsxzwkrwplfljdqwykspdryygvicrgnlsapfw','vnhoxipwlaiqdgsjpuahaghxdtswzdzjjafvwuefxjsigesgsnphrasfnpbgwsfuvqeouduuyunveauqxtqqvtqopiiibzkvasxnvgcgzjuyoeyorymjkdjnkjgikbcjyvxplpodfkuqwtefk')
+;
+insert into t2(a,b) values ('ysksdxlvrgixktvsawbxlfygsfutgvujxbzznpnygfpemjdktrmfykuceohcssfoomxdqszerpvmtrdqywuyaqiehcftmdlytpfeemosuchoelbcylifigquziuzztzxuurnwjvnuolnjmkrppifxpdgelgqurwroiapjaltwbouvftjxogojxzoigbwfpfmkvqaioeeo','zuenjqawzvdvxpbhlkszlkodbgofplugbzspfvnhymrckugxspjdvwzvjcoofbbdsudsjuvqgqwztrxhfnxufpkjusnvxlbxwvyqebgthqvwopagvhymailuamljlzfaekwvuqtbbvsnjegrkhxjrlbahvtojvmzsunfniyrsdvoxkylnlwbsqcysdscqbjkoqxozuouzckbeqlvtjtzwfsujqvpnhmswie')
+;
+insert into t2(a,b) values ('miyqbexjdbcztvrofppdnjlcpaxuvgctyqbsrejal','yvnrasjqsoobzjcwtspvpqewbwifjgwxwgtoutz')
+;
+insert into t2(a,b) values ('msazttjjsxruncwhqneiormwnokktyswfkjbrxipcgyugjuzjrvjmquctgo','swqsmfdmvpgoqxgylmtmcannnqgtlsfzfpospdlvewfspnbmhylnwdifjwwwaorulnsafxisdsvdvetiqvtkodjeldkoiydpmqrnukdvwptfuhcctpibuxnbaarjjkjctcvzeomdvkuopeeojgspvdanlgbbsmdybfnbnpmzysuqixlmesceavxdkvphjxdw')
+;
+insert into t2(a,b) values ('lbiuuxpeykbcisgzvqhnlsfqxbfwubkatqpfkwyaotrdqkcbvjyrkwgznofdtndjlgjvcholdnqstoilvjarhafhyyhekaesdsgywxrrmyiacodaskhaxalsrrgbrjjpz','qtkwrketdaqjfqsbhtr')
+;
+insert into t2(a,b) values ('aelcolzdqbbrszlrlvcpdtvetljoghqezkvclazxqamwlddewbtfrpqbutdneiiwrfxtpkgcncsmiczmqdnytmrfludszipwpwntlpwgeuavcbpycjnpiymgulernseqfcinzmxtpgujtgvfgngezxdiasjywizkbruaoismaytgterzetaa','jqlyddevkphawrcjqswadchpojesskevlfejqqahttugpxafpnevhddlldvymrkngzeewxxwxbbngishgvewstnkfuxvmhhcwgbmoczaerzvskcyqqprvciaqmunybnicstyjcedibxteutifeastoyoczlnnwmvqjzqzsumloiacdhzhvgyoqwozvhcygrvyldmvjvyz')
+;
+insert into t2(a,b) values ('onlehhtelayjpavwzzcelmywetfmskyoxqbjgflguydmwaqtdzddaaknwqhxgdimhoxcigqtlbzdmoiwcwcdosluqxygwwegbxgzdsqmnsobnakidmqhluofydsawzccfyqelzkktuizhickdolypqmmgytrqyutuwbkattqtwnzxtdbwkbsnuxbnpfroghuhjppzskvcfggvmghwpqz','bnleylozhum')
+;
+insert into t2(a,b) values ('rbamzfvjlrkljwfuykryptzupajwqeiqvsabnpbopmfshwriyomeqmenibohkvzjwlajsdbppbeihlvpsawujvidacrakadcs','lvglvsszchhdhzyrkszgcnirfvwpwmwutuiarpnmlmzmhdqsvcwrhwdanyfhueohlkhthvhawrilwrvtmmymur')
+;
+insert into t2(a,b) values ('ffgcprgzghaubstvxvbsudfzzxzrkmqlxgecjclttxopmvnrveqfvmsgtvaqvwhphnmpuxcnbetgjgypmqkxfsoabsujiaxvinagqgxqnfpxfypkywkkewszynqxhhpxbiyvpmlkpkznotjtqtgkalelfgsdyelcxifxnonaavvqcqsjwbqqnynbrxmxxkgxrqaqjbthegv','uelrmcexuvncidzqpdtifuuhtqtqbfzpbullctxzelezdcyqfzigafzjgjftgrdbyagdsdhfziryhsmsbpgjgyomgjegtwbumvkznkjvwncmevchuqrwruwlxwudyespbqjdslatvuzsaldznfxhdfzhijgobhrfxqfzfkyspbzkbcmcichcjbyygkykzthkpirlira')
+;
+insert into t2(a,b) values ('bbpypjdvopubronsxshjkiaecrvpvqyiomkclyrktssnehbpyswyepnccfjuwurneoznmkyvcgjpykoggvwmvifwwkysxxmzmflhkahcyzkzkbslinzkynfknebloqomwrqgtnlntjxxhpfnruuienxgwxzeenmzvyoiwnzqczmuvrygjopltnoejayccxjhjcqfpxorljkwgryjsulcr','eosugvvnotwgtpkaguwtntncmzqfblyewvgqzfdmjqcxccbzkquuiymyxspkeikplfcakymgnqqkhbqbityphqooitlmclrfoljqevbyamslfsujlqrumqubnfeaqozymukmmajpwdocprkfftgbfd')
+;
+insert into t2(a,b) values ('rfbqqeiicxwxnwputydghfjdgaagrcfngynfvsdrskottcdianrqsvguyhhebnanbqwnkdtpdosyjbejmmsdyxrdgljsdpmqfnrgjagiwbeojvmcdjwpcoiddebpkmfcnszxtyesjfnwaxxfdevhlykjasz','feofickzvybshyrdmmuuuuqddnznscqtqegikrasxoyusdrgrnjhdarajcsrkktilcybizjrxckozbhfcqutuhpxkzhfhvbnxffdgwrcnxwpxjfbcrimxnkrrjpbmvrfxqdlqwsnkrawqrzyvtohlphctquidalmkatodalvsmaaxpweirakbigpgriyqvpqtdcbiddialdmhoczanfmpizajtryfknpwpvezxwtddwvwwnfoccjgr')
+;
+insert into t2(a,b) values ('enjwcjadsigphlkfmpjtjlxljdpqbtwajzmmpoazqhomfcczokb','oqpzzzregjbkctbzsuvhdrxyusmtwmmyhlrknvnmqqaeywgpzbbarmvdurrzubbnmvxirbwrrgwgcshufwpwmcsnuvwhydjjhmzsuhabexgmvnizregozizgudauvcglerohftgatmbjnfoqkphylximhfsazbyihpkvfvateqizqrpsyijsqxyegifdlwgebyxydcnzadlglfaqtuccuplahoajbbzszpwueevouonqetbxunxegmas')
+;
+insert into t2(a,b) values ('pmijdi','cbfkerhzrauemucjdaeasjaxvgunbjjtrgwulxivrwxsfanamenuvytevfcbjziggzbuycobiayeldzmwuqqnbuwxzbwvgiyhdxosttyjjpefqqemeuofvfpcayaxcqbtdwnwhvztebwzmzqqwmsrcmsvnwzgpuejhhicceemgienwufzgrafwvwcghhtwnybwiwweicihbihkmb')
+;
+insert into t2(a,b) values ('tfbvmisutdkqizzmgrbwfxdoyjujmfmsukrgxmtinqhqihywvnfihqzjrbwdusxkeymxxiejoinydcjnwrlkvgluqxngrjzdfxsedjcmfeduevplnfiumosskrpryogilnxjrlhwynbljzqyedfmpljpydvfitekeisymsledef','vydgqeumlvvykraegvjuamjeubcjhfmzbniqzkiewvyiwfjhmlskgnhuycopywiewitveakuxgjcgzvgrvodanbjrbaangmgisspgkcqpuslehhntjhgmtolrhvksjhwltyxmnbqusjnrjjquifiixgsernfkvkxprlmecshnxgqwfglfszgdmcwd')
+;
+insert into t2(a,b) values ('tineotizzbdwocqberakbggyczdftnaxcoaljjmvovkzkslrzndqajwfgmqytxnwcwwlocscctdaocsuilcctigvfneaajekzsjidddqvnophdzxxmjefaudbasewktaasojfsagrksqwjuqzluprbhelkebeatdndarvzrtskmvaamlcxyuuzijdkamaiofxtrazemlquodyidnzrl','gwfiybjlsvbzbqagqacpwckvytjiqnnlljdxbiwownalaaiidohhyjnlnxzqfdckhroklwqnyqsrkejcbebavfhedvrnadu')
+;
+insert into t2(a,b) values ('obvlqmewluwjbvjidajxesowmpprisgnjvducukbsmbqqxlklzgbcumqrdsvlhhmxfbeqzdgscebtfuetztgrybotbwriozubjspkjdniirkshlyxluhgwdvqarnvhuihsholmitgjlscogdlmostkkfmxtqlszdftemstkfnudpprxrgudlojkzqktutcolnctcpvldequntfll','spymecglyujzpshxwwrjphztvktfcdraiqwvuolxukoexnwhozjyzdkzcofbbjazbjwinpuqjbsbsdbeapkzdpaxbvbglcukrioabnyculyhvfsdrrfpzuvenywnlpfgmevjmphbllzlenvdkobwzevftusyujsqbcvoptxovuixzvhvvepb')
+;
+insert into t2(a,b) values ('ubcwvxsuwzgntcniucwn','boaqmjhmhkkklfdktrhdcxaoctcswykdyxutokpqbfbdlafqjcgsjkmlpnzeqmyjojyssirixbkwrecfwzrjixywsfprtrhfnwakzdmosdjhwbxhijypddxuxakwydzgqnnlvcabajigontdidotrqyokjgzriklxehfgnsmbjremcbkrtxlevskmfeoaivypzyhaoluvsuwfiysvcgxdxlcawkpxjyjpdxgnlbfhcoakphtbgpwiiafkzeziz')
+;
+insert into t2(a,b) values ('diawryugpsxfksxoiwcegtonudbunmmmoyhctzgnrzcmmkfabirvzbytffffrqlkveealxvyehsirvimsiqqvbqudqvzcegpuixrkwslyfhuqktxkbrcgdicmbxlsgxhjvbyxsuhiwunrehnolowxtdqfsqtygqqiuhqeqmisxgetysmxbraxqcreivdxroaxjudlkxelkffvcczjccinmrxoelb','tpvirqlwib')
+;
+insert into t2(a,b) values ('drfcqbqtcgxizcrjvsqanbctaukkgrpxbrwcjhlfpqvdjamefpfvntaigrmipdhwxwcvtmnsvjizznzafjfesnpaicsuriabwftkqoyeigpxjvcwzxyvgsseyekxqspyanjdyupqvnnjveoccteffk','xfqyqcooqblfnmwbekgytzrefenvqckmiwldoelrcrgsmwowfgfhhqtxgjkpywswclrqmwtzwfxvrhbwkceavijbgzgwxuxgzmqtyowxklqscssicpslkzrsrhkhvhzvymtievlxkejupdtabndult')
+;
+insert into t2(a,b) values ('rukefotapresigapygibvqzovlxkqmljzoloimqtwrudhlewynpoqodaakdljdlmebbefgywvzkhyodkssgwhmxugdcjjvw','wlcfchfynbympfsfijlafmebseafoqlyhhuuhannjawsilkyszyeczybwiryzeoadyqnxtrrthtgbbquyqkjwntfibxwkeqxwffohezzrwpgcfshconqtliouramwcexwtfaogpwbusihzzrspdltbcuwoplufbdewsvbmjfpsxdpyyxdcsxnyaqylqdhhbxaohrzijvzywtmvycrsnmxhdug')
+;
+insert into t2(a,b) values ('nmnyxedcvtjvpsdybccjydrnyosqnsgyzynkvmbfbmbojchfjqiornznqkrtznnrffmjfyqxrmfqjozrecxcjbqstpvwgorpceymfaioprojjcdtqriwsqeojewmm','rljdazptwwxjnjdtouwkbqfhfbqfhgsdeotukiqhmflgfkahywohfcdqutrqshggbcwpzmidprdocnsnckidvtktxrpffhtrfalcsghfqivscqklxlivbyqzfynpcrzicupuflorquuorkzwanjsseygyn')
+;
+insert into t2(a,b) values ('faeauqcecdv','shhistzbevlkalbhrnhqlouzyjgizewaenwjxjnydanssjmbhatdjwlipkpwdmtkdqrmjjdknriaobatswkqfinwfoagdpcunzeljhzvakycvjmasahwgjdgdxhcyjlefgfgskwydxfjcpdfrwfhajevabohvuqlflzdzrzesg')
+;
+insert into t2(a,b) values ('rdaozgjxvzbhpgbxojomloiudgppanienkhupusj','xhfnyalupfzcckdnzvrsowkstjwjvpletfuubwpzkdkmydrpjcqrzfslofuajivugdlaasqfocxxalvqsqaalgphodzagzzujvylielkzhzhgwbkyyxprfghxofobyvkmiwxxwknmnnqpdcoepxcqyrxmqlwtodxwrgnwfxbgovwhotisqojboehzujvljoeftoaqdvbrflvpdsgprkypzmerlzeabhuzzhzt')
+;
+insert into t2(a,b) values ('fncfmoqlzsxskzhemwgcqkkstkzqkegrveotqjskknlnfsciqpkxlbkyozzleorrawrjfqlbwkzrapygwurtrtgptw','ljephojgtavxxcszqidregoryoezwwkhktctybgjykxjyyagsfltfgvyagxlmvlhsacxuguxtyzuzsxmtgdbtdkswnrgooqctguulvkutddnlwwptwscznjmkrbcsdirelneemjxcmxlpdvgpjrqxkknmbwhdjgdowdzprvxzunqjhjtipcgdarjdqknpcfsnccqukdyxxzcffjofruitkhuablwuviuugybktyvschubzk')
+;
+insert into t2(a,b) values ('ttwuhyjngrdiagvcyserrzfggycxpiwjgjbvnqwtujdojbxmgtzifbtvfttqtqkyfjebasnqnawaylzeexituacdfwgvsjqyuhbfwdsbeuagjaytwozxfcbnylxklgghjzktmoxebxmihigqkqdaqywytnbxcarwinaj','tsjyblfxanetzarobphbnpidpwjofxeynnlw')
+;
+insert into t2(a,b) values ('iycqwwitaghjyqfgvxxhhagcybapxtjhibqbtoltphlybtcdyssissuafsldxvtrdtpadmkdeonwdfjtimafqrmsptronsvtxzhpkaahwmxntefwzgaupdfwvwgcjodpbaoexgftvriueajoslggqsknyadtpzygazunceixenwbob','lozhukntcuhownktwldldvfmkivzqzdhuiuhsuoo')
+;
+insert into t2(a,b) values ('xpffbpzvoxaubpeitvgfpidpwotjjwhqustddgeeeiiwakukretdiuyuscepyixvcbedigureonwtqbpvvgkrdwlaxpwhtjygsggvgxcikfthxccvmztxbzrnzukmtogzipabwgqyyv','wmlrloqbbhadklvwyiwvemkgqtmzsjskdslcppaqceninoanngdbwylyhhnu')
+;
+insert into t2(a,b) values ('dueehtbhkqousdtucvugvhdfnsunfogsfcxeohfdcjucepbvhritorzoevtcvpnoyphpjinwaaovjnvvfbbvremgjzpxaulbhubdwtpurcpmrtpozwrzbwhdhmothobmqmxrlyznpajzanmfsewyxthfbowawtxjcjeyehyxrurcybcrevy','qptxctgytubewgylvxcitvxyarrjfu')
+;
+insert into t2(a,b) values ('dozyinbxlojynrjzatzrkjcbbnqsoskxqldathaxtkuriaqzjrtcwhwtvh','sittqw')
+;
+insert into t2(a,b) values ('qcltjlpwjqpnjmchxkhprdcbqbrvxcvyeaohscggqhuewmxtcvjvputyoqdnuxwbgwtlwnzgfblriqmykeejgtatadsyhnipydmwcgxiezozuibuiywsvmlczbnykycrauukbhjuonlxpmmwiypnyxmjbkbjmimxmkmwekgglfhjfiediebey','zllqvbvtxeamaahygfsywsfeiyyyemszeqnsuxyepzorvdraeolfqvdurmzgbrskrdgrerwerseevfftxiroptjvbjlxqjigvucxwgxyqtqjxjouvbrvmcpxgdcztveyreuxcdvvhwcjvmlsnqzfdlfdpqvagtlqgcttwajgzrnwbjwcjchhvvwynyqjjauycgjtvl')
+;
+insert into t2(a,b) values ('aljaizsoorttbudmjgtbazifwlsdwetvlxslmhlqnroxbtwftjppicwrjntvlrylmtwaecoq','ovzuredxfsveweamcsdgvskjfmiptpmqlfcyxdmkdvkyqydtkwykeblhkpdgggvcniltophfgmyojhnlawsfsjgjwslefqwf')
+;
+insert into t2(a,b) values ('gcyuiwz','homenbtytahrossuxssgnmeivimodtovqcduxckfdpantgohojtgbjpyyzznecjjwsszcuitmifntzffhjxxnyeixuqxttfiruxkdaawvcovrzhusngazysqnfprtifunwolryytgjoobbsgxhypmytnecphhzvg')
+;
+insert into t2(a,b) values ('swgntgohcvednusdkrnsofwdxpjisdoommtgckhwvxakeehdiaytbtbwepsvzmwdrxxwtcklempkrfzeglzcihiuoxojdafsrchbbkikbbqqirowslddiwojqrtpflsrofttirzypogzfwwklougvmxdurxhztsdvxgcszwaznitxqwtnqkj','yopatbxhvjszqbidatmeeyixlejrdpmctvguhlwweuauacqsmlgzyixgsxrctvyrfheeeuxwlcocuplaalqicgbeqthvxaprkohqkekbxqqnlsksxrymrlicvjntuzme')
+;
+insert into t2(a,b) values ('jpotgiiixcoghgteavptskioaigiujoacopcxlabwekquxzpacmfvolbrirznuuirpclmdcycvbcnxqtajnwuicnescwoqfumejviovqbqglnuhjqpkybzncqxwbrlsftsuoyesouyngrxzviwdefiplx','ahgqkxgknqxvbsrlcxplwwugzgpfglhtizddgofjiubtcbqsdbcoaftajdbrdbamsaqggwxiummlunodroknjqwsbholkaohgsapnjwjcegelkjrwhrkbsbnfz')
+;
+insert into t2(a,b) values ('irskabwzkhgvzdjakykbmfaqshtbclpwfirhmvpxjawjejczlevrobwpaacxssrbtbngimlbhvbronsffqmzibvahaoakexpveivferuqglbscibqbvvvumfrlslhdqebolexzwoomnmywtjjfmrzzwuanmzatarxtpohnqzwltuwwpfhqvvfkwncnjtrjwagxkhdaqnazifdjqfueujymtipprdkmhrxsvsoemifkkqcvpfnvx','mloktkvmgsezhyzawvwxvcbhtizoalqprjusgmfztzrkjvp')
+;
+insert into t2(a,b) values ('sodguuisdsiglfcivhyconvqligkwcjzvmvwwzolugcxcylrlibcgbqxmroqphrrmhhfepqlfbjtauouqjcs','trtaxfjcrnujhprumeqaidtvbgmgjyeufegfckawaixicemcgxjuvxdtrpykjblmmlqhghzwbwtgnslpxgoaqlrumeehbxgdigbdgwhmutlsfsjxuzlsiltjjwkudpyrplagxyzjwjrrrdbvnqojlkcegsx')
+;
+insert into t2(a,b) values ('ntrsfqivpqrtafclrmvksajoc','nsweshdqsnikxhdqaptqvmaxjcehbbubpyuojxsuigtiwjcglnnjjaticeihjqwefgwirxvdvjfnzrmgabbcfxtlqnafodiyomdtutmaheqdocdcduyopaawvpjabvilnuwclqswofpqogbtglgramezeidgifeslyglqilzpkgawyiibqbrwclohmpswuoqwxurvlobghecorjzvihicxxdmdcfqjjxtxhvgmbrnkjrheaijw')
+;
+insert into t2(a,b) values ('afxknywzzctxvknrxhbtmimgpgaabrlszmbyv','vbolxjnvugnwnbcarhbmkzbkjotmwjlrbyldbyglfdwfqfzgvezrihvjofsblhdfxsrnowixslotdinepexeylkkdbfcetepbuudktvvbcfaflorlgwncdgsnqanwvnpgopbyexyldtowlmeldadzwjjundcufyscoavhohvibedlwpyzmjfwfgiebslloccvevphtyjaqsnectclx')
+;
+insert into t2(a,b) values ('iojzmcjrufkktglmpetpoykmitxlwbnunxsswlmotunzhcqjytvkzlemqpwomunkckquhgerkwwngywpllzseojaoayqdynspgexitlerlukgwlmcyxaytxizjlmuyyawuyqfwfqwckqowned','zebbflqysdxdiharnlcjsflmfejwfxqonmpgifouxqnqnxeyeddyuyxphgvutinjnrlcsegywriwvygtragwlamajxwzqsvuoyynndegdgmabwdhypitgosalcaqiyrcrmbssxmfjuqurvpnunkmhxovtlcctpfmwdlvkyqkeybegylqbfwngrjyfjedapuswifrxuppbyqqcnrjdynfaslexvbzzkopfmkpljbctpayz')
+;
+insert into t2(a,b) values ('svzjbipykiiujpcjfkvhrqobkqtgylhsvhkuzaknevjckqmrkxxdrijjiobdofnysjuflqyxdizqixzguxhfmbdinoorvpnibzcqerjufurwdqkpsezbsekpnsruiwypjhynrpuiuwhsmtbmwswqofdyasjqijreckcawmycimlkkxdiplfxedfcqkadjncqfxuywndkyqokklfxzrpwefbjwratmnsevupb','ikvziazlurpxstbll')
+;
+insert into t2(a,b) values ('eioyjppqjbtktqbnjhruppavxxzdrqeavmroiuncxqdshzmdvecyyfqqpazdjrsorjkrbmyxwqkmsmrlxrujpitmkilfskwlcvhynkcnkrurwcqpwxbsmnmzevinwmwsmpncvldunzymqqjnukbxxxcrkfeccvjeljmqhxoocececalrrqughmawauagjuedlrkydgjbsvsqrrcyigms','ylinpucqvfcepvabilpfxueazuuozbfzhnidjezfceseulnxlilner')
+;
+insert into t2(a,b) values ('wapyqehsqxbvncindsyhgwspayuiciwxuaiwuhwzghllehaolkbxkyxpjtnwtubwmifxvvwsceahaepwrtbmzgyknwqlplsigoaynxzxwoxvdjmgkhhrupjbytraboeuiertxmwfgtwqyfnqwutjsjboznrooyqttaljztyvpocziaasruyorbuueojgerdgjwpnljrtnzotsbqsrzlleyrudegswtrufabzysgzkbmpwavqrgnfcxjiuyrilp','afjajtdabebhsheirtoqwqbfscbzjxquuypqyzuyaxgjgwfwitcryexifomcjtandcfocnozemapoyjtkrlwyxejzdpsqjoleglcnkjlzhfkcdklzcvjmjdandktgizpfupkbzwdiuwjzvkihrthkfhsoqgpgyxdzaookzcdrlrqvzzxuyb')
+;
+insert into t2(a,b) values ('upskngteqthogbqdznawtvuzdtvvzrauhcpvlsppwftieddostbrzqepapsdttninxxvgvgpemxfpljayclzfaquvfcwsmdnwilwernnicbuueyhqugxarltjtnxphgkgttqatapfdfytgdwohnjgymqakkfvdfq','wssspnguflycejjmgvjiqctiijxyclayezhiduhqtomeqpcvfxjntjeoukrcsrtdflhhwswujwkeuircrbpjyemhguravqqpyarpygclypbbxotdvxwmlbkxqrdcnvjgesaeqsrgqzacjtngyvgdaitkgfsrqqbwmxxretrtbrrrjllfilswixysgwbwfuvkahvlopyiaddckyvevrtoksympozxbrsdtcogjhlwjggmuv')
+;
+insert into t2(a,b) values ('sxndrijmtwomrmscpliuvlwolwmxpxymtzm','xvdcyktckhsgjozicqywghujgzfwgoxzddegzkrxqcvbesukhjlhvmphxgzymqbrlnvydmgxkrkwineqzodpe')
+;
+insert into t2(a,b) values ('ixdkzjqvoozpighbygqjwibvywbaosmgpuzitxdvyumvchguknibukqimfebtvtjlrxironekembbmcxjkqhgcthwosomqbjltlogfeytykdimphcohdzniivbihdwseimnpqkqklhqvbokbrnsnnwofgjjibc','pqktewwcpbsvkrgjpkcbfuyzvmiwrfay')
+;
+insert into t2(a,b) values ('ryajzznsmsyctkigukzpxrrrlxpnqezpukmigfbsrjaaubtjdhsbhwwlnehoqfnekegaizczfhnjqjnzjaofcrilxkxqiewvbffdawcvcadguvkeefbxjaknqtesgdtgvireleoftxmczrjcxdhxnulxbwasunxcpasgfywpdfpzgquxzimwipshslmopjilkuhtqvednjqjpp','oqfthnwyaiycngipcpktadhixqtvcsuxuupokvsnkbaokrxxxzqnebxjizqwqevlxrgdwakwjjvyvmqhhxmnwpbsmmgjcgbjeyxnddhoqbxwzxufmqhvoxickwbrexcvaahoyczpqbonokwtpwhjoyreuknqddnnkiwghmcdvgznqewidudbjbmqqmrgalndyftaaojqakifnbqrjpeqkiokmazezhvnhueobcvf')
+;
+insert into t2(a,b) values ('kctudwgobdpyxrtclqjlpeuuoxrrtzlvlpvybjyusncjcezchtkqsuubfpseedmnfgheyogtcrrwqjgprcktujoyjrumsyetb','uwdfevw')
+;
+insert into t2(a,b) values ('gaxsuojtsyukpvpojgxbyhbcvxcwmiwrqjxdocebzxdhzkbncypdclqwfpvsrbaltkrquffhbaztjuzlnyslkhspmymsdrlfzmpbvnzwaabkortsosgljnvmigzichcqpyxdlqgjirnqbckaykytuik','mqauvmelgezerdsaqtkbjmrrtzhslmdtgeqqnlmwsjjdigjbfhnitdyqmiemudtyfefwixscuykhwvsjhiolbeduvetmeichjclhcdmebrnklsvvvdntvvptuhtsydjejohzphpnhapxbekkuleexxsozwtgylcwphhynsggtlkcejkwxhgiihdullnbvdxraejaitgftbcbcziqshdyurinhyxaxjfyxvjtrjaezqacsyklyipss')
+;
+insert into t2(a,b) values ('orlgggeydqovhryvdnbtvvtszdtfyqnwqyzjhwpdcgvlozo','ltshppmiknxoxujyecbvitzghupfmwkszsuisqwfgcqlzegvepyuxvannstqcrbnyavsplvctrggccqycuufurttvoanulaxbdaamftmcvcephhzmdhhcshgebvhagbvoylmnbnpqojlhmgzckvycoteajuiudmjascwisqkecczehijtpnkigdymudhorhen')
+;
+insert into t2(a,b) values ('uhhxftndqogotjexgizouzbmveumixacyjiaqdgeeolejkmtzpauddbzekcjlizpwvawcbylljjzufygyytv','nyyurgngzgyvvdugmyethcoadehiqpvlmnnkbojhumopvulxhsbsqxnihfelcblgfcaidmexhkggeuucwuukbpekymrqfuresoyzyvkocgabqgfovbhzgdvlqnmsmkebzjqnfbbutaouqlffynbtymqataqagubtzn')
+;
+insert into t2(a,b) values ('fijdxtmexfgeksopizutaarvaqyalilrnqckuncbwifratmatueluuvcoallnkknfxsdpobecvzlqbrsueeifvvcyjisdsqbhliugfrahfyjulvqgjnbqe','zwimcblbrfqjvroeuvabtcgggcfmgyoyevcdqywdwarweqsikpvsxogxrnzoyvanoukfdsnklyfwwtuqdmhzvfoedsacovacbxqasxrxiaaq')
+;
+insert into t2(a,b) values ('lgciiigwuhmvtcjjtszxxvublwsvbvbywplyaehqgpunhtsepmtebsvesummmtcusztzngotlllxynmctsxivzvgprlxelwxfkakwedfpltqpnrmn','smmzjhgbgevwjzrxayekpalfytgatsvoupgdosnlclkppomwlmjulbzgrhucsurkbqhdwikfisrrgpopviyuzoxvcfurelghsshbjsusfckqpwlkrstvvmzwqlqfsenxghmwbkodrkdegdslnyunmp')
+;
+insert into t2(a,b) values ('gnuaazfctzegujonasvnscctpfsjdodbqnslveyexpdbgirajgrjajgvzrquwaklfwtifnlpzljgjkhzhukuveyaqpzkzydmiu','vxovqyhcwrlfsmuwmpwuyvvhqenmvisuizdgnnjjmccglvsieyjvorxcrezuaekbcezzrmfidkqxvwlrobroctikokpwhmbbqifdggxwkqgbbstosgtqelhvyueomlgkezqjqxmjdsnnoxmbktihfcwjjrfrqejhkeqedbqfrxvbkbboeqdtsmdwvxpywtlnvusndvzbaxdkfnkutpjfxysilxjlwzjwtxaaxjptodzgqtdng')
+;
+insert into t2(a,b) values ('ulrpbduyyznishlggpfdmdkqpupacxnxaheogwsb','jozkhwgofbptijmzusswrcopbtvkydqinqpqrddhkptcolvtmftepzfonwbvvwemmvgfmypkznlmmmfycitjfynmfvsqacfglnelhmafyaggmobxtbjrc')
+;
+insert into t2(a,b) values ('yjfmaifnlfcozntsqppgybiflaknfeeqgeowzyciocddhriqvhklmbbgeflgcqiokyqzldpxkbgjncxnukntvxohxgatsaqyhcupadxdraqdjldzkfwpvbidaivihhzofi','wtcfsnepynoqep')
+;
+insert into t2(a,b) values ('sjgnemiukmtccghbnksrkdezyltqqdoyzwsjrrwpbamjlnhjuyt','fpfbzmvcyjjmejwokmbnsqsrtmoimbqgnnfywvaqamuqwrhqslwrtibbdtpettgewnjqlhbbqypjttlixjemavgfcvyxvawyetrshenwqmrsuosrhtctkecnwfmhdljyrieehemfensfwuizypoxnfzbpaa')
+;
+insert into t2(a,b) values ('aneivtpyvlfszyosbvxjncmswwuninipzudpnggatthesnoeuymxvjworntvyflejlhonfnfrgwuzsjnlvbcegmuoxqebishnqfmlydpkdemgviuplkywctibcfjvobaglhhrvqnkfytympqjzndhfqdddnecivkfavnlwmepkufhwmumbpztgkgghknljdgbaizlasagnoivdcruyadywyylosqy','jjclnfujnknbvjvbduedecnhyeklozvwefqzenptjylxvnqfarexdoativtltznoqcwcxtrisqneqvmvdgaxnacsetbgqtcovxxugwnuvetmlewymomqyfxpeofwytvyyrgobwkgyzsrlivtufksrwstlhzzlnztribnqjwwfmwlrtxpglaqczdrkpptkxxbfxmjnuqpcfzswiejcgesrajwivtbxejtboiydyalv')
+;
+insert into t2(a,b) values ('hgnxvldgydexkundbyhtuxtrafevycasmujncuvyvvhteahxovnortwdeoqrskbfgnagfaohhetalzrmvebrbgkncreqhjgaqshamxnnojhzjsfvygoilhlxfmpggiyhqrdnaskwqaoofya','sayepaxukgaugginrrnmgrtvqqnliixmuylravglkftplyrsrazubqfvkzjquwxmhugqajkzfynbrjgenpwhtmxqpkwfegjofejrmmpwawmkubtucvtupuhtycswipnltvfdqmqvjtboaykiiipfgwykeppbiaxswkoloaalcnrntv')
+;
+insert into t2(a,b) values ('jbdjizddyxruosdfmojnotfjwtgeejqndffksomxoungpwgqfdeykvkfqpqoczfyncx','gomhknfbgvjltzbjewvmabpqzbipywsfwxezxaulucbgcwrftayoasxkcpnhkegqozurfkostjjggytsfffdnmwdwjxsqmstkruqknzktglkotqauxhtkjdpdditcvdwaggvisqteftexrkukqbazomkyjqjqeuhftlchmhtnghfhcag')
+;
+insert into t2(a,b) values ('luvbpoyzzfgxuoljxtmhmyuxgockmlobeglblavxkxqrjtbf','naiuyzmsdtzzdembnrjmsykjzkvjetujociexhvyokdbkvndcoxqrvgbsnkgeonuourkzixlegawfmhkblhecjhzglrhyualkkvalgcxxnmsyfabikedyddsosiewibxb')
+;
+insert into t2(a,b) values ('kgijshmsetkzythsgaqbtoagbiilukxoleqenvwbvyzenfiwtvubewxovlszudmptrcjqjfetpuxdmzbxehmqtveqarqvrnzohfatxpgfwlhootnrbxejaqkgouuhmmrtjmfvgamgrbaljgrfhkicpclhzrxfycgrktaeyelmegdqjzfjd','shiwnyvolzushemgekifdmgffxbagcghlpqdqssuecksebmduwrlmehfroyvpybyxqvycsqvtzuoflafbvdcimbmvsuptdmutvnolbrpdfgafunxaciybxgpjufrrldxkbgqzhgenfhxukagcjsezrpisterfqrjiacmkbatrrbhmrokxdqtiwqbtsdnhkrsnmvid')
+;
+insert into t2(a,b) values ('rxesqlzngalhpeiohlyqwsqmuwmbmgzlyeluvexmjwgtysaf','apxdygzqzzdtxkhtgbsywlaxnuphrhbrirmhsttxqjydyiytegqwrwdbiomtrbcxbfcqacftlrvouoljoxkxykuvvfxejohvzijglecbheqirqmtpncjjidjbtefpacuertpghdrmphtygiam')
+;
+insert into t2(a,b) values ('ddabkpxmfbauhplpgfpkapmwegrwshqpnhrauhtprlgjwlflgdegbwpjzcrmdhmtexv','sbgjkjuewhfwpkhifqkwnchahhewfxkaiqdvcjpuhtspupuubniarxefiaclzznrsbymixmurypihyzrloijfdwfqqjjvxirisqrameeahebmsjvvgxvqlgnlrdlwgqmcvlqybomtiefhxbcxxihppfjdgoxffwpnqwfvrdvnkmrfkrbmlxavwzjznhkjhaynrutkdziktjfkrddudbfhntfrbqbydohciyroaxnudgnstmyqobslyokvym')
+;
+insert into t2(a,b) values ('f','zzegrbxiyixfkeopmfknacaawfkhifadhpfolczbqlmgdggkapfcfevmnlmkfnqezrqkavhogyxzdjiygdomudvfxlnhrfybxgiklmkgpuhanbdcrsfcpoeehrooqbrndfmqizixdkxthbxnckrfvupucnkwftrazqzpppnuyhlnxvfuplsrbsaqehgvhxdhtggjllbqajcesbjlopfrhxgcphhaarjvacmaogyltmfoseizeelpz')
+;
+insert into t2(a,b) values ('esfnivpsfozhgahfkiwyicpteiesqgkwrcsyaulhnshwglxetkmnqlkxkykiwedmdzcwfirdjjwbnehplemzqquummttazpiryulgxaskjciyscdpxrogzsrevhvbbsicbschgdvmfh','okroaozemozivfsisyzkarcbhqpoabgqqrrwnqfvkpdhtgufwxvrlbhbfiurjizqazxhwrmqzbnqbhydrtzfhbvmbgqhrlrakevllifvaezlvjvjamhoikedwefmhehflctaiffrbeqsnvxyekuvyoeyrggrbeoxdvcinqbljbsuyrbzgvouveeolmksiisbslxaw')
+;
+insert into t2(a,b) values ('elqezbbcvummnfkcbukxgyzafjoxmmekewpnqvmymwppgejdytljcffyxaskygaffpnlyhkphzuabxinzpkbhmmcjdzwqiuhrutmcmncgvslpffekzaiejijolj','coadbdjvrexzvolehkyqqqcnocaoqbpthvxxwvetvmviizgbvgxzjslmfqkwwgydlyvjjuwfcnauxnrxqwlaepdpmflfhweqmmgnvazwcpgzlimpmqqcfghbpttdttxuxsbbtrsiolvackyjpnaivordpvapcsjccilbrcgsqbkkhircnalqaliglsfpzuyizrokczjmshrnlhbkubakaqpeosuvyzt')
+;
+insert into t2(a,b) values ('wapquepnrtizflihtylinmauoxdwfyvallaorciyitobstpozienxhjruzjjgplvyxyczjmczquchbsmyliyjmtelbwsjhshdlsatxosrcvqjydgpwcbjkwcnhguceuhgchyuclhumsjfabrqkucxjxjeaojohldmmuxfgxinvgenvwdzungvolmdrzmobioiqlmdnrwafujzbsgzrmpntgekruwkszpdnjjfi','gixathxmaoujerwpehtunctmuainruyksahewixrgowtphljqzteamebszlgcpmjtouvfokvibpargcua')
+;
+insert into t2(a,b) values ('gfgihbkbosdbthlstfhxvjzfvaateyyplznmcpinwbcpvaqsiammapnszezfqnuoslywywomgfeudgctmsrvudhytctqpjjbxxdzwsxsbqrwvqpwdwlqsjrpjcuuglskyp','aqwcdrltlghcnxmsvrlvzlouizhoydjvrtoadjsjkxslouvgfwjakmvhaulhbegeeerpwxwtxstavkckqeozfandmpaulqwqbuogvlwdrmfafdoqitxrrjuopehsekbfwqmxkcwyvhppdjbtgexbpyqzwwvvzsxhiajfwukmxrjbkllikcajazwybisoetjqtsrrr')
+;
+insert into t2(a,b) values ('cjlobcboujkwdnxvcjofnevnibsgcvdynbicmojrdqupzshljfxhlntzyqjqhzylqbltnooivpjivgjdbhtuvwisbqtgtvfcocrjyvqtavzgqrzibrvdwrumjsfxinwxvzpkgkzbowxptneovqynenrtaaedymcqkinpwibnptcviqizpnprmnbmilcabulgafaskclphgryjzavvknzfwvbpvgnqobgqmkyjqjtljhlh','fbodfjeobabicyzogburrlhnajfyksttokvwoyphqxkmpwcjkoiajswmxpcmyyuwmzzotarsjsiolnkrifimoccidndfqqdlldznrbwiveqtiaksoqbnigxlqaeppltrjxwihvzifnnfjqwhoqgdmcuozudacbasidkmmdquviifvzkaasonrptrsqubvzoiszcbikrqsbiglcamjqybvewkvtabmbrwitprr')
+;
+insert into t2(a,b) values ('beyzmzxfxaowdgjiddcstomnidecdcwwggmqnsfoaphqdghsgjanabzcvvnyutaskxekwwsjprgtebvryzanellaetzwwsnvswnfbxpbwjhftcytnmdmbhtamgcgeuimajdjhuojhvqmsjodogzvv','vzarbfzqfwlvxsrevevgpnwijnokalesaiursqhmzsrihwwxysnxcozwyfinxaxczuvnzbrxmoxmynljriidrfqobktlhhjcsbkpsnednodzveypsxpfvramczoskxlgeaqgncefoednrvtwrhafhjxmbfryfhyvxv')
+;
+insert into t2(a,b) values ('qbymgxdzzkeqwihjqgntlqnxlnfeirtvbvmgchjacbacoqtfxrjphzveihhiavntgredmogytyqyjgsztcslplophiljvmrhxfbhlbgpif','ivnicludfwgacdoykukmlicmvsljwocucpqfruomkzqwycspapvvmwvpsomgobqxsrkyuabgwgfksskgawefmttjlgolhgxyndwfytjnovzquwgcsaemdhpjajqlpepdvostbbsquejicycxujwivrenrfizpkskeadzorcbsegkbvhdqgxvdcjndfazydngzanvyhlwnrxwlzrkypenkjzocwgdkufkewfilqvdlirdetjwtc')
+;
+insert into t2(a,b) values ('ffwogaomuntgjesnjvojarogktkctcwfoyoovbefzpmpuemzcrsocdtzpkguqgmxbninhmvqbovysigxothinknwcnuphycervonohqhsakrhorhplxmfdt','sbwsnlavkieifputbvzurzstazepkiljxuucbrgbrkcqxyhqxqjubnhmpqbfbpdgjeivpiqeutrpdzqehbwrzbakfbqvclrlbdyxipaoeptcwaiyvvjhqdfhavpmnihqhoynmyultotjirbmivurszxdlqklfwhuggfwdzsfuzubdwvmelbwhfjobngstfpeaakygwkal')
+;
+insert into t2(a,b) values ('zqewrvkdafrcbazskcqgnnewpnxcdnqsauiebmqwwqykhohldmfppbizgblutmxyjrgquwylvnpkugkokmtydipiszexfziiaoinzoqhhqeirveydrumgbwcnlggqiirwwbitwwegsvdolylfdiixomhsvklgjobrwqjjwxcdtyyoqslwinnpdldrdjhbhnqwqujzwsdpkenwhdiiwkzzwwxsednyotmfxvluireecebztdaclfdathrwm','grerqlnosatwghpdngnifoqqciwxlkwrvdtlonajbcqwhklheyotbgewvpctbfiarghutmjrovfcheghelwkvclgumvxoxkxhyzthqpowgwnnyvhhiqehsrknjjizveqbemgxxloktqlckmsqixgkgepcxiscbobilskaztegngwncnzdzxmzucrpegialdyeajxxlvuezslsiox')
+;
+insert into t2(a,b) values ('jcuzdsoacuacibuvretkllrmvhkjwwpnrgegeovjccowehekmmalcdtjuhbdvgtwtxozjqpwoipwfjwxduwvdelixhvuqwcjsntpboyrpuijzklpdppfijfokxxylpsghfyqsuroaqbpkgryafxxgimlnhmxucpt','xoenzanrgdelkeqjlcygwueixujfxqpiucxymwwbbhjujwzx')
+;
+insert into t2(a,b) values ('rhhjqvpjjvtknvydvraiwlsjlsdlqisufnmwvgelozexgumrbcerlxcbaurxkqdkpvzcnryfxfipbmrkodvrtangdquknqatfapuwpiphpmvwomktedpvholkxtddibblzqrdijdrrkczmipjidbwd','peg')
+;
+insert into t2(a,b) values ('ynozqrbvd','kekzpvocfqsuaoybrcgaodcdrthxormesebxchgosejgsikdcnfioincjaayiyikvoeurhsukwcuquopfjfbqkartzwmgrgkvvpjsuupbeqkrwcvnrhaqrvqhrueqnnkwxkjfkadlccarwabrraepnblkllqxnqcgyszuvpdrkypzjgprpm')
+;
+insert into t2(a,b) values ('wuwwogxyqlegqsutzmrgjixtevbqlnudpzglekegcskusaeeunslxevmqgtsrcdtarlgbjivxdsjgthvgwynpjtzbihkhhxnhwkmhfkczrfpdmjeezvgxpakbearjramslhuolezhuzuwfpmkqldxsufhetifzbeqnbayriqsknrqgovugnupqdebtuevwxcianuq','iaxnecftfzfswfkhwoniuntgzkqmxhekdvxzusevjumyibgttmmixfazcmyvqozxkefnoauhzmmvdqonaxhioowokxkffdyjmugccyjnyzgmseivnovcxffinqtxegjmmaedfodfpltiwejuqmzhhbuzqykgksirxeopunsfp')
+;
+insert into t2(a,b) values ('idxsybvvdgzerlzoddvfxyoqtlurrrbeqozucxdikvbqnuvvjlvbnsweboxavwrtkminhjunqunxvupzxruquithzqxsqktrjygknwewddhqlibsdxvbicmbtnpylqomifsqjiyhuiwyobggasecokwjupvsmleaynen','afwgjuxdjscwhpwiwbnboqvdvbfvqinqaomhqqlkcxokwafidzjdmbzomsebuxwcjcwimlthwlqpcazdaualzmwcxpvpsiokybhydpjjhzsdrugegprvrpehhnbzbxvtpcqbbieplvaslmuxiofcqemildjlvxjshmxzjkqdtwvpdohzaeijpjuumcnqobuoaybmvnnsyxw')
+;
+insert into t2(a,b) values ('x','nlmgrfyofogntmgcermmyuqsburdwaulfptytpkrdcicriiradnbscencmcmnmgvtjqljdmpsqrwicogcpumqpzfchhysweupphbmcjoezpvmvasqvczzfabcfekqghgdtikyrzvwlhqs')
+;
+insert into t2(a,b) values ('vertjkupynunirpgjauftqxzwaoytrjsymfjxuulpdtnxikybtymxwfdppprdptqnacrstwabpktwvcbuselwwxnjfkydywqxairukpiarnqfsjvlfitisjezfswjspubgytboemxueqxdqktfvrxkctixisajlolpgilwkbgmcywoutcnzheufsdakiediauqmydg','gucgzaxashrffjcmqolsxkaleqmesrpjyylbmertgmkjwjxgxahlkouvevnjthmamjsjjruayhkqqsnafejmxnhreuxmkbyvpwshrchrpyzhfhaqlvwtywajlqwufqtmutrxbyklbrtpuytqeepzdgfovplfwaxjnnm')
+;
+insert into t2(a,b) values ('fuhocbcuftdxwrryvqcomlfemzymbnarpfrffeiqqxamlylhbwmrrl','tqvhdxzynbs')
+;
+insert into t2(a,b) values ('pkkaxmtlvnpuoluazpeppjmbctivtvfptuagbuvporhgenmkacstbovfynuwwmhkyirfwawdzxtspwzancwppvywpwkmjtltyqwrlfsysfdumwwlcwuxvanezazcn','qdkmaajsywxfkyruoyedpgcquxlnmecsfkpidanekhjrcvtqpkdhjotvalwxnsveetupzaaokpofshsigzoecgnoblcwtgypaxcysehrnorwewcpjenjygxfofzyknpiwaraebjrvimxsppgvqzkvdvyjdrgjymposvwjhjqtuwxqhuhxtzqtodlfvwwuxmrbnvdjfntgbkwzaxtxfmvs')
+;
+insert into t2(a,b) values ('hfwbugpmqpnxvubkjfvdqjsrdzauuohkvcygncceblpyhieupgrezpfgspuwkovqgiilaorjjcrmwdkclmxtxwwvakbumuqzjqooujgcqjjvbbnksphdgytjovtdncmzfxubilrsfmpxkxxospxumqkksqhoqpxnogimcfdtafv','mjpjymcnzmcncjpvgdopflnwtkpibteptsafcqpshclqcsampajndqjnruqkmkjrwmindtsqchevewpzqiiebpkmmmfqmktmkuugdehopcwdivlyrpqriccouxwgytnkckdrwuqygaccvtikilrmdcpmmgwsurrdwuamqhhyjhxklkeygpqfixhgfezfanwwaailel')
+;
+insert into t2(a,b) values ('nzftaffehkyxfkkoevlsadhmecrvdqpngzqngggsxulngsnapzzmbkvmvbibjccdpqcqtzaakeflrudvdrmccvynxepgucrnkoceeloyriwwgqrpsjnyglhnupeeamnlwqoaxgzjguunopokbeycfimmzihsbclpcwvmg','onwonhfnobmzegwpkgtjaxuufivrdgbgqyqlctlbjonsphpfchfrlof')
+;
+insert into t2(a,b) values ('flrqfiiwqgbsmheafsgnrbfq','hfinohiyjkhxzajinomzvtytngwhsjopprnbltrbmfzzfipbvodceovlllbuetjcobjbqglchsqetkdurezqfkqzfzqlscjtnarxamtqmadtccxmtdk')
+;
+insert into t2(a,b) values ('mfyscruqnllqmaagdkcmvgjcborlw','zmdpwtjrkpabwarjpmvbcriffkmaxrmuvougxzogwxyrzmajnvkynej')
+;
+insert into t2(a,b) values ('hjnmfuyyvyltdiahchimktgdidysyowovhxywabsvliajbwryatlcgotbfnvweswubfelzprekwcewdlcvkuoqgtyxhgcpxsijaojrgujphvcoicosvyheqzbispnlhfoajpctcqyckvgdbfejhvgovzkdzcnqxfe','fsjslrisfheuy')
+;
+insert into t2(a,b) values ('pifdszkawxxnwzpbhdriklzccaatehbdqmueulgyxlonxgjkfngbddpuukxgjeahoyxwmmtyqoodgzzwprftvgdiammgucxapnwuisvtplswkvjkhdqmdhpwvvjvcbskbldglmqylrbjxztur','qtfpqdilfhtjdxyfmymexhsnachkjcpfofnesmuxsfukfoejkxvvuqhouthftkgehviqfkawaokygcuvjwfwsdediuegflxgqmbirukmqmnuvrtsrorcwgndlso')
+;
+insert into t2(a,b) values ('dtfnevxobipdnriubrvwbtxdbnegnajtwgkdlqjjqhintsrfaylctskjtlpjrnpmlfwihhvqzgypfmddtkmqzkbozhhnxhlpvyrcvhocljhxmvxdvqoogkhpagumduyymewtpzawfjdpgmqzqorlwrxanmwtfvdqxzbbivkrtyddgndzrervhjftcrufyfhlbxnn','tviyhirblpekifznlugophfkdbqzowoauiheltizpwidzzuacctbzwlfmduoouqxwbzznsdtebazagydwrzqqscgubaz')
+;
+insert into t2(a,b) values ('tcfaxdhzaxaqxaphpxvgaeexrngrpmlgasoieviigmrxqhuallkdtfqxxac','pdzvofwhkxjurireubcqeyqruamrlnfprecuvrn')
+;
+insert into t2(a,b) values ('tuybbxpybktcncoxxwktuexfiubqmjzdccyoesorceiwydiatncumdzfzaojnevysieyjlvmybpgvloilzowcwvrqngfxvxprwbwithxjjlvkeubhkbhnpzjylboeryjnefjhgawlmksoucyeajomozpyrkxoljydqyzrixaqtfoxnnxgskefddqupbunpdvqpbnjmiipgc','syqdxwtvknrzvkryygcghvrmosoybidwthagegtwtqpibkssnjlgbhjluykkridybphdyrzbcnhdxcvqjrbmbjaw')
+;
+insert into t2(a,b) values ('xxpqvbfnrrawvzkfncatzjvesdonrfrushrtwpywtelcdykynjsrbzatetlmhywflmdjifmbejfjquazsrgxgkywplfowqmgqeikohlliovzjvuljydpdsvghpxntzavvmcpffhhxnimdxwwltegisrqnwmxzotuozcahyredc','pojprwqqdssgnrlstkwbykscyrmkafmojnjkouaersqqixepjsdmgzdprngziamulxvkilhuvtvpyqxikmuubydgoppetmcjihompufpchndqumsuzyyabwookfqrarjdjlseotjkcxvoxgofvssdegilecdynkhcdnzhbhpfkerkmhrnmtjiw')
+;
+insert into t2(a,b) values ('liftejsdzxtyohnqwvnfkgncshftuwprjvuzaqjpbktzmtsauyoghsxzhkaovalqrpnrtnrsksuafymnxcoxbvzbfkzscmbipmyntcufncproqzjkoiubqhfxcrnqscmwtojroublbgautlhktptgzhmdajecfcvxxanbrviaudrnoenypgqoe','nckisadhpqrkjsfllnvmgyisgbzybjxowgjwbghiryjsgydeabuotqryecgqzkkwlgcdbdgvyhedtddxborsxhctheajvazcnhkhaowxhblvsuhzsiixggbvgauqcjemrtoyczdjqqnljzwtepokipgptcgenkevvhtmtaxcbykjlwelaixfymvwmllfaqacquibsuikkbesdvqeihlfhkqlbilmmeqovxruefnqdl')
+;
+insert into t2(a,b) values ('apfuwjfyyobwcznafqeewhfyfzrdutprkcvckmcyqzxjvsxppbkvdxiwqjkpkgzbldwxkcybwywhqarmmuchursancwrfqywvtthpcoccphfqztfwfttjgowiaiqloogvjiwbeeiqwpqkypxeivriasfdkxgkgsihxhszcanulcgqjmazrpgdserankjskbdvzgltrqbwzrpjtimuaqjyutqnhyt','magpvzfbstgwkavxrjyxcxfxbxwdkmcohbimxduowgchhoalmxodihjqamnjmwpjhplifoynejoiuakoxpjhjvlctlmfzbefuvlcdlcsdthuubsusuerhkebuktybpzo')
+;
+insert into t2(a,b) values ('lklcelyqsmeqzikoznrwldkmgaefnrjoejoebzjmdecmpmbbzybsnuakgfidzisyvvzebdsudaaawuumxcayxykxirwaencumxr','gdlkeegeemwfibhcltjubbhtynhgyjzbpimppwuqdcmlkhdvcsnizknmdsycqkoxocirvlzkgxvvvzupmqbsxqrphyrhnxqbkdlwksggbdtttmzfzanzemrjawpvmmqzpuvgqvgbbplvnzqnrtoatcut')
+;
+insert into t2(a,b) values ('odxaoopdmyoidacbrlownaocwkcivnkebqvbchntvtwvheosfrydvxrswppdxpgzpkiwxynutsbzcwquntohwpwacbqyustzvgtkucvonsrlfrirwmslkevsbcdciuxopcbvvxtxmgnrucxbdfnqayaofhuynzcaydbbmkgvedvaztkxogkdidywlbgfnbolrwlyhdkeoxjmcchlqldjkgtikwgygqyivralqgbyuseuslostxeqf','igorcbbhaysumyqizqcntyqjdbvtqzqmxmsltdrlmbkzyxvejzuzzvlmjxexajdgjfyccydfdtgxapqhphyekdmgggklkrggqhpjjbkvlkizhodmdxjclxhqkaanunowsprxhkquuyj')
+;
+insert into t2(a,b) values ('vgauxqnwedlebfbuhdfynpjuaonoltglnqupethdbakacprgkmysmkxcscxsvkuurlumxbfvvbdecvanmkd','myrzxatzawhuygkywbyhawonpagfjpntpxyqxaqlqloavazaejpztoilnvdctlhfcpudinxkfsdmykdbsrnayudferurqjcanmpaonhzy')
+;
+insert into t2(a,b) values ('bwbtriwvblozlelxetzmaufquiuzmbpltbefgswidpqejoiiipndvxndiusceceuajtzlmkmjzzwxauqihfsekgasjdysyekdcrwgep','hreklxngwdrpxfecutlzegldepbdxigwiaaanrbnehseflrkfduosptnhcbumvfwltrbujxwjebhceudanxkgboqtvfkryijvpcgnitnnrfeevmzuhpmumrrfclu')
+;
+insert into t2(a,b) values ('gwohbfcwolwkeecbapjixbietsgsfrxgdssyjktydjnveblvzuignzsfknwhidtydxfayrrnopezfuonkkgheqijomsdllmzuyfyedtudmkuctrhdkkxnzhbdbgzzbynulntkqbpgosmommrjmvghjqietzdwovutotdledqrkvydal','ljbacwdkqswsuvidcqjcaqktzngyvrhyifvttbjtbfzakexqwblzeniifzvqrrbtkdpfnecbhifutnmullpqqephwvxzqzkqjywtmpqsuujlfwzknnsymfhuawvdojwipmqpwlhkgjuaqrscrhvzdmoixmlpbxzspewxepzhdkzvlwnwsydxplagnyaiemnhsxukazeyfelaceotufdhyhvfnts')
+;
+insert into t2(a,b) values ('vcexxqanarvkyugvxmqneadxyavinprxgchwymmpbxxcattrexdviskvajssbajxcxanprypzs','vzwyjqfufxsibgszxqyholeyrltkaeenktfxstvrfeojlqorxlwkjdakrrxirviwnxszjnqgfahsxcfrpnohuygkaechlhpkfjmsyckkeldfhupfzbxsfggws')
+;
+insert into t2(a,b) values ('fyhsdnldbvhgsbbwkxarheqjqtruvggcsbygpwrwwuiyqjgjgrrowowwigha','rygwvud')
+;
+insert into t2(a,b) values ('wtyexnoygnwtwsoianwxpxzaukrgjvcxyludmmxaxiewivwwknydpnpjxjbloghiutfaiafuyuzmdoospcefvydhdtexwwymhvktzdbyvpkrwrtygucfwdnzauwnwebklhjpsxynkqhebhfkzknsodblyxpygpahmlrbnldhvrkpjnzadptehuyarddbfektfmclfzii','eflldjguxiclcoervfaoozaikmimuzgtamfuhijmglxvkblvlaoqsdjvvcgizkegvfltymseqxkqbxcflqzdlehoyzjpjnjnzodukwjhsfymucmeiujejdtzyssczsbrbwxqgqdujwrsdsywdjwbxwvvpbtasftyyslvybhzghxemygfweowwwekqvfgpoulllrdogmfbtyyodzehcn')
+;
+insert into t2(a,b) values ('ytpaydqmshqkwomgc','wosukitzg')
+;
+insert into t2(a,b) values ('fjcnfzhjhdxvxizvjlokjkvwornovxycwovfknndsknpwppaoadrnrewgiqjllhmpkmkrfsvggiwiqclqszcztwzzbexqadcttetirwnvmwcrhmwyeggypfgksxllqkmqzgayffhqdewhaujpdpcgyxavqbssagyvvwgpkpdkfxwokncsmjdvqoxfuqvwaknmbpzlcbtrhylmqbsujtixpdlna','bqdpnhfurxfqxvmvclqapgelhomfivymmjwfkjnlxyfhxydkhlxdtvhrkhqmopvzpdfebwwmvofyteeuivaodvzwjwtmubutubmhfxorgszurwl')
+;
+insert into t2(a,b) values ('givwdoztqusikorapyjtyuvxdtwvhtucokwqghfubfygtcujarhdbxjfnigiuuintogbpmuouvfaiuahuuedmqxpsnbsbulshvtymclxwlmqogzi','oczgnznihxadhbvwcwlojotxcypumeeaimfvhmineqxjojvhaozdynsrogvbvpaijjhykbcyrgaetjxdyjlhgfvjwujevsipkdadfgfocnmlynlesuowecttajppnipfuryhbtlnvsezaasgmwiwwignowsfq')
+;
+insert into t2(a,b) values ('yvwjuyeffubzkydjxwfxfyjdvslsvqrqhofdaijnnrbsmukjktlnaozsaoxlnmrdfqkzyvancjqdkkmyffdoydphnhmzjfqwrhymkoqlpeonhxeugfruqdviduhqsbjzwyndwukyqrcaetuzpsdgjskcrkffeykwqgkdsvouckjqzlqbiasx','quenigemffbxecsfpwahmbtysrjznkvmqzoeubfoffjivcpxfsgwqamsphcpjaygyekntosixmyugttjpadmyhjlxzhaoepwielyxolszojhghfxzlxthchvqvxogclzakbbgwhuevkliszakpouuwisdlyehcjutbpyzgswmeiouz')
+;
+insert into t2(a,b) values ('wgyzoakackzdwuczsmrqwljbrdlkfxrgyxbkgokdqenbaqekwgtyddhmvsynfvokmzihkturaakxnvjqdcrfigomilcywuywchjkkvclyvpvkttykaxgolsageatkqntjosetfoomepevtkyouutxyxttmsojddkaggykcyqgkx','uvuomenrxgbmvccdjcpkdswncgzakvituplswpkwjmqjnputqmyamwcmzkcttjoycoyajbpygyqqmfqrjgvxahzbpenabeiaksxgtecohrnpykqmqteevawnmluxmfufyxcebokpykviwchfcsuqxnrwpkzpwjleddysykw')
+;
+insert into t2(a,b) values ('awlzkushwefdbmczolfyfrfcxponarivxfysurembqatofcbhfladefpvnijwysyihsqftepilyukzcgfljbriplafjngxafaxuxixounlwoyqzxxwqjuiwovztldjoowpkcnafrjiqnnpexpsithdqqiupkrf','qtylhtnjzjwgrpwccyeailyflhnqztavluggelcafepfwxklqwqmpiflwlsjicvyphkxqhpmvgavqgwxlbksbzadbypxnggocjczztvcsaro')
+;
+insert into t2(a,b) values ('jhffncnyudpfygjyykalcexkufjpzeulogniokcnxiijzoeobjgcgtsnqebfzjngomntrmpctiqyvpxrzshyxkcfjkzgqteyfdngddbipqgimrdlwjehqcdspscm','hirgsvnthrrcohaftedqgetutfkdvznujybtecqzoswvpzklwjouggkunytezbaetcgqduxiwnnrjsutxgkwtgpbpgxctludoaetrjwuubszgfelxmdvkcdxwjuzvjttkotxpfodgbqdselhsktnbsmnveghqnvehihczuycnavugouahbccyktiotapwgeqajkgdccokfuyoydnprwbyatcyg')
+;
+insert into t2(a,b) values ('ubkebswttpzdzmnhedxaxtjtmlfblvetfjadfjzclutcholiahpownliprwvknemiowwbjrqmryuardtgxlzzfdfqchjnbjjouvjbktslwrvcmutilfnguqpgnujcjp','emeeexidbehgimurxfpexycypziyadgjcqmjljdiyznyhhvonhuwqmsffrkppeytknrvpzefoupgepmfnjgresgatimuvhdolmfmpzswrusbfchqd')
+;
+insert into t2(a,b) values ('ouiqsnqlaagshvroiwmcobqwkprgbudaphqmycrximxbhchlqahboiyohxkktpqnggysnttkqagdkkoeymknzozsubjovxdybvzbfzkeectoiwjdryrcdexksyyqgrlmnnbksllyukkwnvcavoktynftqblljahkrdrygbtsfwtjxjkebhl','bdbiwfdqoinxvamjbvlegnrjtdwwobhnshjuzevztdhhgbdnfxyeaqwgsogmnaapkdqfrhvscimikuerjfqoggkwogaxqulhwpkzrpvmtfvwnwxgrevqxbqwriixwkvzhhzsxnsktxmsuchpbjbannxkcqjsgptc')
+;
+insert into t2(a,b) values ('wocfhilaboqvccuxnielhhqwchesdq','nxicxqeskrzyamzkfqgdmpiitwwzdiifnjxbvngldegizpxztayetosovwciiaietmczqdchbeeasrpcnifvstxbwnqvbyqclcvpfkunbvqxuhsrvzglighmwdfkbrjxtktgkhgjave')
+;
+insert into t2(a,b) values ('lwajfcxgjnmcdlnfutlqkkcvohixbilwmpbscypbpjcdvxlkttplncwxynadongtojkosingjxaxkyqgilztvqeynoixobrvxh','gkkvjbnzvbqxavcijcuuiqvbzjrlhrfbpmxpiiggscpwjyjhcuqibliblajjpinlbpyivscztjjpttvoxhsulrpjetsrstelxxibrreaebj')
+;
+insert into t2(a,b) values ('pvipfqzequiqibovdzioijwfyhdvjllncggowbauhfkaplppjbwjuqozsjmcrxcoltmlhmopheaqehabdvydjacgukfkxfcajdhquqlbdinvjknzuxoxcqpyjjpafzvrukunvtoarghkia','puxbnkpeyqikuivaxqursfqfmoujmmqrpwokaawyvmpwqdllicwxmefgokbldlyklewpyetlcfewllaulexvtbaxiiywsatrrlhxhyqelqlwcudagibwdsvxwjetovbspklwcmenvwqbulwnxxubppjvspdwnaygptilludiaw')
+;
+insert into t2(a,b) values ('fcivgiockwridijfwvygmkabenhmvrre','lcpiaennowstrxpewrkmwyavabtqemziblnjieyvoqfpsrongllhkylvpddxpclfvmywsfsjikyalkoxx')
+;
+insert into t2(a,b) values ('xcidvtjozzrzngufawddaberyczqvetniunlxwpskqzaawmahyavuqebmdkljgamlteowjncdhmyaerjgytswszzcsxukvmobdofqw','afpugkrsuhiepsujymsqqozxegbaihqxyzhyxbuhsnotzufelvtoebravxpklkndhlxmgdvpgbltkcyzuzyjrqlioxwrimcezxnqczjnqplafbwbqolmcydfnorbkkhyhycvusztfsvxhveychvqwdcbwqstvzpweudxmxegkuovohxboofwhoixlbefrvqltbilublmjeabdmfcmjvhmemlib')
+;
+insert into t2(a,b) values ('vwjpjubbmcbiukvfviqpybiieewobougenqziocnuvuxusknfqermsjqttrxvujesjjkmusnvyuidtjxjustwpoecxaiuhboqgsrbzwkgdponobjnbvrdqsuhqfuraqnijzycqrsaznthyzbavwcbhrfkcgqlltxaucxohamchqyctszzohoqygrmztxaziqntvtaxyudjoarbpjmtehqinabgcjltcjdbocgdakndhqucdfminv','wzmqikxedojk')
+;
+insert into t2(a,b) values ('asfgpisukunhduhioopzybzzwxywnyjwcakzgplwfoexptgiitizwzvtjpzgmeulteiypeawoutzofkks','epiqvgzhqwyudowsnxyfegzalwsqanunsztbmqshnuxugupldfapkziksrjagsktpmpmtfclvmodevdekvhfiycatfyacfximgieztazkphvtfyzlizycrpgwayb')
+;
+insert into t2(a,b) values ('dluabkjsdnpqqmtidzetacumkeacjwjviqnoyuncydnlzyylgogmlcvhniugiivzpwyaxldepreiitcyhhafqnckslaobglwwnutldqiimrzqyjejvpeoljdihonscbfjfpsceonoyvgmipylywsqx','usabkxntgpvvqctwbadsvlkmigyvffukkpxhuzwoqhityhkyqyarysrkwthlavpqhibngviapcrewbvuqadd')
+;
+insert into t2(a,b) values ('xxf','rmflwtbxwswpxqbymbyrbugltemogoorklbhqezwzxpbhipdnkzagspghztlsplnbmlrxxwaxookdixlfbttoauedcbeuxqcuokwolgnsxaqgthkhpsyofrqxwivrqdafjpoeqbdspozaileeazccayghbvfmhuelozbjdwqaebjiqnszhxmoumqsxkjlsvojybutbrxsusingftyihxdydzmscxxofqedjiwdsimhzklzoblumzqljndaeo')
+;
+insert into t2(a,b) values ('uagpuhhvebjbiufmhxzkhaqcrehupbxeeertrdwbkwoxigeixmblsnnvinuztjuacepacpjalpladvdzqsspdqxbrknyzdubpwfhxozxngrufxlnkjfmuayqetceikfcjsgkhucaprtickxtvtwtwwjcaiuavqgxwwpbuswbtuebvdnddwwdqbwcdujwhyraqefkoutlzfph','ddcurtyjkyirnjlbapuembgcpmhktgbxvskljlgjcmffvzstcggpyyaeydilquvldynzofoxhhxlwmcmwxtggdcyxokffnrezpgthrnzjccvrdsjlwmz')
+;
+insert into t2(a,b) values ('wxbogscubbzljwpuwbqidwknumeoyrsaplhgmcvjitltpagectapfwgegnbhahtfqnzpyslvjprrfhevqytfgfslinwruzkrdyfnjgxmmxfqiagiwwdvghroskjuahiaqxhjdblyybspyqdksiurpvyduiayqqtygqnpbqxgzajwjpcqcycveelokaaujxkvodhyclm','xupgjndtjurbzqrarmntohicvvyywwgdbwexksoyaesxfyxffvyogjbguqytdeyzzjzdiexmygzqtdwfmuepkbwvrobqjherqookifaioaivozxaeogoylpaiufhfpdbplvebzvvolfcjkbpegcjersecdwpkygkmpaunalfinedtcnnlxicvvtpwstdgoovgflrcaqellhfgidhfijafryahqidvxgvbgbfm')
+;
+insert into t2(a,b) values ('evmkbaptvpllorbbmzfxowxnwnmwgxeguhthnnbxnjkvqadyeheqqxtjhddnqbhakfzwlctzzxqvzoaqiahbayjqqezlyuyjjasqrqkiqlleztjyzavlxginiwzcjnaaaesvdxgygfpbubikwhzcvrntxnngpzgnwvvvastiwhnhujhqpluslggmkanawkqdbzckmeignqeydudqdkvfednbhdztkdqnnmawidqvcmdmhedaesrsqgbexvsf','jjwignwagfzgubyfizrukejnjxhmywoducfuwvcfsywoifxfnaljcmblwjbqemsnhwexaixncvnpurkouy')
+;
+insert into t2(a,b) values ('kueegeewlpnzhbvijrrdrhfowgwzzsk','wmpy')
+;
+insert into t2(a,b) values ('gxagjimfamzdt','sdrjrtijsbrxbxmuabgycvviemisgzxpqxslzgatecit')
+;
+insert into t2(a,b) values ('k','ayliktbbbcwvjgyxxsxegksjqgnmiqlelaftmftlugejnvqcstrgwooncjfgivenssvikynxmjfrdyhgapzgbgktdhe')
+;
+insert into t2(a,b) values ('utawhvmgkptfobzqwceijciqnibuhxtaddnrlrshntryddwpqmkkhcyxdlldylummvlbdxbbxdipxeeporwyfbwcmdksdrooptvmtvnbkfkkrxlxybbcrjsdolqoqwkxnqkxzeyszwpjctcxlxzuxedjmfddtewktikvfvpckdmdusgkknij','smnychuglcujqpsduvcxgxouylnzxwzosafbutweanqquvjhrjdpnhxfkbwjxhaxsfvobakolaghtjulvnbrxrtdrzqfqgqplx')
+;
+insert into t2(a,b) values ('ndtkqimeqwvlyiibcquuqlfgppdgdffzyrcnzcjtbobbnidlorbgyypnrftuqeucndpkgohzxazohdwblejfahzrohvayzdtsulidcqrpygmqy','hqhqgkplgocicgiwtvnseuuzcxvxbcpxozoqygajuzqqroeseficribdtrxzknvhzsqpowexuyxdb')
+;
+insert into t2(a,b) values ('ikalkjereljbpwnwvnkjwkzikmspvadwvijleetdqkvbcmqvjmewvzhrigobugqfdbnndnvnwtlwgsvcecbmrirbtafurstuqixbyiidfvzzauidivv','xlplvqcpkrqacsyyedybkairdfefbpbwihydwjrzkeoqxfsrtxarwrivrfxflasgnxbldnfyteuezslwcqnufogtuvmydiomhmwqzjjycvrjpehmwqvouwvnkdijitoitrdvhyksptlasslqnp')
+;
+insert into t2(a,b) values ('aaskkcjwgrvpllotxdwtimkabspsgqyapodifgidpewbppqtimrmchrhbrnrrgrnylnluyeklubcfxbowqqxynravqltjifviglvfewcfryhllfqxvuvdgcyapndjxoguqjf','fnotryltcmeeyxvsaqrunbfmsdkiezmnqxyybpkxmuvgelphsseercwyzhxfvfdcwyqsdwlnrxyoksvekkqevlbpmoisqyztawizjjbtpctfoywodipkfofjxrhjjvgxkojxqcyurwszuuddjdfwt')
+;
+insert into t2(a,b) values ('eezrohflijqdwrbcgjknhthkodgglaoldtglddamfpzttlqyfmyrklmsoumiszzhuirydxcwwdbkqmjqfyaaansxqaschrlsgkuqxzhcxucbctuweujznganvjssrhnzedsmsxqsmitzzhynengiuffdmnjvcpyeuhcybzjn','aiixdxijzdpfwzbnavrgfispjquyycifosttzzotfcvlfhuxgyeizydyylwylfxvrllyutenffxwaammsumcxywbthdxadabydgzmlqcolvegjpj')
+;
+insert into t2(a,b) values ('xklhuhifeynzwmxlrwmuqfbanimwrxvmwxzpehmkmdokgudcejuelvvpplmhxozpxfkcwpnmtpaatuefkrkrxgwox','pdbfgekhyffqhhoinjotfriuvrolinateazptgmjthktienbnqsihurturdthuezuyoqmcknfnrmkcuedhzbasmryowhkqyomcqplrcnlxfrkjalapmmitnhohrbwpwdfeqpqtingonhnzhlsfcxefijcdrgqfqhnhieegesqswydgrczlzyetnqswskgdakjwrshukmjjrmkjqrwulpclbrjvnzybazpbxolttilixzce')
+;
+insert into t2(a,b) values ('mjeviakprdrqqdgwoxphi','qgziaqrvbcnbw')
+;
+insert into t2(a,b) values ('flhychrexsxswgtuvtbrbhbdonytzpjltlhvryuavvmedgceabjskgrfclfajndclnilsxvitwfgvuoxjvvfwknceryszxqmydayvdjsxmpcjbdggcachefvzfmkvwrwbswyeijbpabyvpydwyqitetkrmlxloxllfyajalofvhdllazwnhwibnmagbnegcfcqktqfgrdwyhqppxhq','iaitxooieivwtqrcubadkzpbngkubfjhkpjtxhcgwstdeicfwlngmvcfiauffarzizyh')
+;
+insert into t2(a,b) values ('hvgeastefrolddwloyojbejcogsirnfccfdxjggqrbqvadirgannjsagkdscjelomlypcjnctqztqgrxzczcdlzhbijooooljzmnwanarinyndszwjvjzavfbedaqiwseswybpchniklpjejzlgzqtbvepjgqvqeystexbpfystyamwhoqrabmajxxjmzwkanvdotzs','sbnjpvmcgkroudownkpweciwvfbxarnombpofzsicmjncyboejlmrvhwnmscaoqibdnoynvyjlzxjnftqeqbfofsftfiwzceggemknyfvvyvquednstsfvfijerkzztprxssifxnoxqchtkwfcrveepbpkkwekjvnbrkwjsquqffnfbfyqlohrfxnixuczzasdvwnfwglnysialjxbvxsxcjpcgrveoosglhoevotplflmzsy')
+;
+insert into t2(a,b) values ('lxawqbcfdootsvogctvrcwsxsggeeiizizawzxhirnnxnyedkjsepqefmbkaqrzmfgvsvigbefymtokzdzerhgtuojnbluoxacjahdfmomjmbsghahezvtfuwrugaurgshpyaskflkfbwzsrzuxujtwmnpuzyjevpijipsexgncfqchliofkjybuuowgdlenhwvasfxwbeodqakuhmbu','myyvzghnvmhiziwzmmblqedbyfdsetypoucntxsympknnfjwhrvfcxojizcwasyiwuutrdaafojswvhoykkhlswqinwigjthrexi')
+;
+insert into t2(a,b) values ('uiohgjfwffnsholbvkcggxcyzxyxb','imrogisctmkeqyrtjqjxxechurl')
+;
+insert into t2(a,b) values ('xaudtlbfgqipvneczlcxjtryaacekwdfzxwzwijdrwxriauhzjneneunbutdblefjuvwtrscevsthwmbcolhtstcgfxxwyzqnlzfhmabcfyljuoobrbqhkffzleqreretbtwmuzixbmntouupaoytiyotrffvbmdkwnibgmrdhvyhyoneoncczvaigngbeyxajchxhpmsn','telspmghzoggazvvuaktzhccdzxfztetymybzhaoyqwkmzbkysvvzvuoeoihvyetpobeeavnxnnvjttbvgcyxfghpbobfacvirzfwstntaywtzqsqwzgvlipxhyfjdsvftdzwkvjsliomwkelbdpzqifpvyhomffpepyzqexqjxlrmmjlcncestcxbwhyrttfhohbgouexchqzwpiswtyhjwryhbhi')
+;
+insert into t2(a,b) values ('isbebqonxsaloancmdemmclyhsajmuhmtiwvdubowjhlhmwdiogvlq','gefheaswlzftanfnyodpieyfwiprlkvsduwd')
+;
+insert into t2(a,b) values ('gisxozmmxeeyqisywdraldvuitwkbswspnjtsxryvyotevgbnhmccqqgmvakijlyurnkqrntgaayhbwiugetutyjxseyoqztiunomlrkgsfqbklerqmdmeqtoxsebuzbkgxbjfikvpyseuhvhfqnfgdjlizcjfslxkrwjbojelvnoshiqbapfkxujjvezhiwhmgtrmpwaqupzknwjnspcpgkmqyxfcfkyvsgxmmxq','bslkcoveqihzxz')
+;
+insert into t2(a,b) values ('jcdxkygvsybenjhbsnpymcohwiwredxazmdyitifdrbexjlmmdbnhbtucfwdioboafewhixxqgfypqdeepntraphglehktcdaybymkzzsgosiltoofcmviaxarwdtldpdxwmuhgkpfpamubybsjwsmssnrnjztekgnmozezkniplhmgbtdvwlvnoccxpd','bmsjyrikagpqghrfbedspeaoodfucrcdjivxcokdesfjukqqoylvrnkvhvqzlwkdmdlftjoggvmsfwpfddiazsjzxhurmpxolunlngkbtltvvd')
+;
+insert into t2(a,b) values ('zhjurwwftqrmsaunsuhegwolephccoptszheqmhyeoglmtvfnjmnauggfmaefnjoqfbpevevomfwpbseuqfeasurqrmdnwmtdxqmivvzcgyoafcuqzgoplrhhxatmpfojfjdkwtivmuemanjaemyzawjvmhnnngmobaxfndtdmtqommaql','jqryoywhattyhwrplttcgumpfkfuxacoconlnryvudysbxczmhjykxsfktvpqsc')
+;
+insert into t2(a,b) values ('zdqbnhwpczpcyybwiznyafjnoranvplhpyrcmlmwhodlozpaxjimcibiipfabecjwrwheigbnftjlqozxfmatzvuydxycexmbprlwqcctvpg','yaxpayakbvqmfjkv')
+;
+insert into t2(a,b) values ('mwrdbywbci','gjobywykakgldbigwycjwdxbeztwfnqfpcncqusfpvczammijrskcszfahdlwkgdbojglhjvshtsdwxvvmlnlkegicmemvbstalmxvkqzqomhgbxsfqtcuqmfomkflzwchyvdylkbpdeocqvzlkbgizcbottdsfeizgwiqonqnlsgvlduphshuzijqbdhmwlgbhjrpjxdedmcjrzxiqnmhvcddmdvjnflnynvapqubfsaraqkhawhvd')
+;
+insert into t2(a,b) values ('ckfierxrstcbtcslbbsgwdokpusnkluivljmmyozbcvypgixyfymazbhbfuevwjiuegiuiponmeuxhrexhvtsarmrwpfnwmwollurdhgtuzglvhdrlcomdnhvvhbqficmnwxuuqdynyotyrqapckohoswvllokjfnncbemorekcljuvixyhgchphnhmugvpnuoapsjfripmdopxtplovpkxjikwlkepwtouluftydspjuqjnzaymxrjwhmc','fvxkrizdoerw')
+;
+insert into t2(a,b) values ('ydhjgsfraipdubjx','kqhailfaqeofvcqxjxgnfeahaiktttstkvlbmaqqjovqyiuxcqruknhzltnrkljsktfqflhlnkwlyhyhffzlpsfbxlzjibyywaqrsagxyedbvwwrzycneimvqlzxexommmxddbwbnmhsxbhemvppsvqfablpogpwlwcmetvmaopdgitcuprgajfxupkkftfxdpmafpwszxpeac')
+;
+insert into t2(a,b) values ('vyivgnxnmfhzucvusywnuyqzjpyhycinbkcgyhyiyaislnokqcpqryajbgnluhqllfdliidimcmmwfkyuuloytczhjtblyujcbphzcgzhwnrqhmndwyulxbbhoogzgmtwcqrvzgfuvpjpqieuvzt','rhxsxujpfdjgqchsmektzvvnnjsglgrlgqgxpzfeujkfsavwitzinrwgbwefnrtunph')
+;
+insert into t2(a,b) values ('bkltwfnnaqluzcczjrjlionvgnpgeeitfjzgmjqjpaasdklftcmbpn','thnatcbfkdhejvttwbpblnvknedwrzlrtdrtflzckdraggwknquenyvsveqxsxrhfilluzkuctdslhttpdxprbdzjofmcbjksokdvzdffcqxizplwzuulsqdgnhzemugqyhfmmgztuukhuogvstbiyrtgzeyrxbktcigjqihgnkpbmrlxkwdhcbpfipntibiwmnhzyjxyrkepxzb')
+;
+insert into t2(a,b) values ('ners','wboaaougtyukfnyycaeikhoknjupmiocsrabprnubadymqjipdisskzzbifossbhyuziadz')
+;
+insert into t2(a,b) values ('qzamndfzuwjyvridmqlusaxtdj','tuhruqfecbltpoggpvkbqeaofsjkwbhxkbhythwmnonhvlpqluyqdtonjqanloszqodjiobkmexfyirezmfhvzyjfasldmuqwxkkgtwlkbcurglnzoaflxcbbwzloddsnrtxfjxhzykswxbqwqs')
+;
+insert into t2(a,b) values ('jcqvbrviarbjxvwsibkqbtxwxuzwspuaojtbfuuwsnvpchezihnyluvrclsvfxuiciifrmwmtiggtdlfbynazevtuttasbahffibsqwwhrbsesphxnvkrmybvnencgvasccqb','ngydvuhqcqvildwdqrexxmveavlcrpbszvsopxzkweiymomurcahaxvaxufpwpckkdhkfcgbtpekmjmtawbwqnqjjbrfhctmhwseqbnkxkjjipghkcoyrkmdpjxqvsxjwtwekoeckxnddaqjdjevdmvgvnakhxmngmltrxxeavpfvoutidapthijgluuafhotrqwwqdrxvkgojkzsxmjnttkmasju')
+;
+insert into t2(a,b) values ('ozcmgdkldzidyquurrrxaxdkdsfpzsutfdihyxstjnqcvubimwmtdoiwbbcevaihrckfjvsxcynnpfvtokvbowxrrikwmcifsptybiyqnjdwwdlziek','xexdrcgkpzsvsvijpvlrwufjhbpxghrwzpoxhrdxrgruixfnizkcozncuwozirkowalammrqbqcznnqdruirfcowtehacioacdkbpqnhabsgleufsafztlalfislsxzqdapgttfsmuwsohpyeolfigmjtgg')
+;
+insert into t2(a,b) values ('wgoqqzhxuvnaibxlxkmgmrtvgrpadfcdgiqbncdeyhcdxjhvpgrtfaikjpwfibhnviermqkcehyfazywrznslhibwfltgftveiaksiusrotkdnhnjhgjilvodtsgiuphghxesuuffemflpdsmvxghbk','wtivnrupuzzdaulpleqpeaagjbrnvzhlwwklsdhuewzvjdiloxckkiuahylzjtsteprzfwclujlqgnitpmdpecubsrnbewzveepqgmyqcjilhgefxnixfbtulcfedneeu')
+;
+insert into t2(a,b) values ('pnwzgdankveujmeyptowzgfmqxfdvwglcyjcwwpxauqnkglouxaoxztqzrnfevagyayfyltjpmwnbwdbprsygmqeedjfplphvhmgikjhlagadyvnbbeullxnploqdhlvvcrsdnxmaajgquxdiiaozsxjuvczupisscqjxurimvhwlhihmkpdtsuajbxxsyzmudmrfzmzdltclrydbjwqcfshycqheshienjxpxioveoczidfguu','cktxfyxjcekkmosmvcqzpyibirgynkcxhgyuuqklqetsmuvdfpinitbpmgtaxitkrrqboannmvzuocajlvqqodzpyiplvhlncwizfcipmttvtlvfllqnyaxa')
+;
+insert into t2(a,b) values ('nojokwgaukohdjawenlcueehyopdekvtxxaydshmiwzlstseptkmunplicrokjipishmfgxiszurgpxopvywilmnxqpqwgstwkoozwjwfark','cwfwgojsafunedqnqkirurfsitvnhyffourdsiqaaslcpmajldabuxmehavzzkwmtwvmgczthyoajytflpjazqoswikirziopcebnpkoavptd')
+;
+insert into t2(a,b) values ('wilhrkypdjalwjliqmulgqagyhgdoniwdizenduooglmxgmrlijnkunopplgctj','vihgvzhylbcfagjbyzjhtwklfkapedxaeoilquegosbwjsqbbbttflryksvadzrsylvbwqnierzqqaioofvhuvdvuwcnplnhiwwarofdzwzefxubcjeyipliznrkbegbipyjamivzloqfqahwcwysvhrezqxwecyjjoeyri')
+;
+insert into t2(a,b) values ('morlnfqictkxjnmxxgzcpjdnhdrbkjzlhvoewbnzqkmejqxvgkpbtfxcyptgcuneahzmikwsmhzekskgtpbfnlzkhazfoqqoaqloqudfosadylnsyzktpievnruaivwrkiqfyhuinnwwdnujukzdoltjikpsgfnfovhaehrxkaxodcrjiugixcoavkrhtepyjlxqqnpaqvqthvsu','ppzaupweqfhbhjfkjcykpfnwtiqmkvaylxrtswbuzovbzsawfjirzbdryhjbfpzeowmunoijpbhtqgrcldghkgxutospgmidggdljyzmqzsqdynopqzshfvfzikeehqoobrczzkrviajjrmkuylkmuwkbjjxksrwyhggiewclve')
+;
+insert into t2(a,b) values ('gklhgrnakcepoeolvrmzymphpyouhskyhlvzptarnglilrbbfiojwxyymxfoppheenxsjzujdjkubfppqkzlmutjl','cbferhnhbrlgbrdlogouyfswmpcatlcmhlgrmvpoentagnscbrvw')
+;
+insert into t2(a,b) values ('cxmpuetfzokskqyrqhcnpemcdqaajhyixwbxckoyzosrkkibyboy','dopqyfulznthfwhbvqsigncxzcgmkdmckolotkpjqdwbqysyhxvmbmyhix')
+;
+insert into t2(a,b) values ('gaulfquhhtpdkoljjmktjrqbgepixyawnzmlxqxtprebjhxdwzmfcwosddcpksrggrtzkxczqzjxevtasqcyjdpydmjobxmgri','xombaggeazifofugnkgfrrlimdymlcxwpajyqakabpjzhrfdvdpoygdxiymwfaszp')
+;
+insert into t2(a,b) values ('uwpbzgikghwtefieoqsvzcqygjtcdlsmgshhbhiicjnzjqexpejtfdnghapadevosjbgoqodsrmoasmakttuoygptlumgigvazjrdemmiyvawtbaizobndaaoqebgwkllphbttehazvljgjtvujvduboahwurpszklqccwzahganzqurmjbmwytj','ccnglubyklmyuvgbqueqyqejqlmhlgnjmdntrhskncinrzqcrydxzedzzkhbactewefvidgpqscwndqtvhhizlqdtctusebrmtishonkbjwrstcrenftymyapvbjqsmsnimjkirirpsuifjtmathvgwokvcgauzlgbxqugcgpeilxmir')
+;
+insert into t2(a,b) values ('xkazrdxkfzrioumxewgagifiosubjoqgqcydgkojlkafemgsjdwsqaybfdpocdfyrpofmivxyhnjvklbxaccvtoctzkeixgfyovngssaeyrtqmyeirggnqwrfeytrcryfddwwewkqrcdbcbbaejrfrhthlurnugbjrmnkahavtconzyvtbgiksfobzghrkdpnllmzmgibweaubhqpbqwyfttt','bufruounnjjkwcbeqorfzpvfsqguzbpcujvfjtrnzlpsfnbpgpqfrcldwazzkryubldenuncjbhwjn')
+;
+insert into t2(a,b) values ('psukuplzugmkkfphnojpouwtobxcmtaokssvxxohzdknhebdzhthlvnteizkdvinhbzotlzxtnirwldbnxrjyimnprjlsrysahiybokpcefkzndruisnqvrfhmibvzdsulkscflzgergjmaoipcsfateugrqiqthvxhhrfeazirahkctbsdnjobkalcluvzdlwrvrkgirvodqglwfacixvzriskvmnvgzwvsyufszde','hlktxvcrqnpawswdgppiairkrzmrybrnkidxsybvvdgzerlzoddvfxyoqtlurrrbeqozucxdikvbqnuvvjlvbnsweboxavwrtkminhjunqunxvupzxr')
+;
+insert into t2(a,b) values ('ekfilqsjuenufkfppxmrmdxatatlkbiagqevwlyyidrwttnzxijntdjshxaqoyuhfzucyxpxaukygxwuvlqdnyfethdyhmjxavzhbgkezhhftvqzepeaatyjqaj','xhwskhvudcdoqropfojqjrxugbwpffiosdintsteimbyjosxysjyifhnzlsdmslmqfwmazejxvslbmktecwcdxnvnbxijkgfjwwsjublgozbddmmoaunagadwmeiciezeyswkfdtvhmgysbblkptlepyvwcbxftgdv')
+;
+insert into t2(a,b) values ('rdcajtgjesmdyxtlgpdszonndiulwetknggmbiexwicizjsnwduilfeyxymfrvpmpxzqhwanmtcgdcbqzwdxryisjuhsdgeyfzoehfdffumhqoaoctokpavxsazrntikqqa','qolbdcivnnbmhbsigejcyhzteiewzcjdjdcxpnhuqbuycwcvxidebvyaszmiyogbcvtcpjopjfugnglxysqfvutxktshjmtcavmicttnbetldyuofyvhcqusjnretczjhiluzfajungjuhzfsdocmsiudbiktjpbzdpadkpumuilrlcszxblkapcgfuzoqbhhxcddtezjdqvdtayikmwdsefmyycgvaqyzsslgdgbvofhyirb')
+;
+insert into t2(a,b) values ('pfudzlkuvjdpeukzlwynfiynkbvoylihxmcdhcyvfewjjieagtcsjuj','aftnsczleeusevxdldhaxyhgvqkawzqpjomxaiisuirbunfasjafwpimqyovxyvejtajyvhrqlkzjiwpwdpeceuxaetcdegcqjokyvegqyqwxaaxrnppmbirvetnsjjrgnqifmvksrjhfgulucdiumewiekpjfdumpvnajx')
+;
+insert into t2(a,b) values ('irwkiaofxqlemejmbqntfhrnmmvyhmbvfywqgijnjjttyughbmkbfuibnepttmhstwozmzuonbfxupuaoblgnqtmq','mqekcwzsqosyafexurgwtsawlayojsfqmjquxpgcftbquqjdakzvkfdlhzngnkkqetnwfvarowtfjigjbjqoxhkgjgoqryynderdezdaerbjbaoohijsbva')
+;
+insert into t2(a,b) values ('ciqptydzfzducjdoxsqggbsemjaagiudjkqigkokiedisjrcxxosfdpmjwarqakxkobakyoyajcgztvlrnqvfwrwqddxwvigzjynrhjaxlvgpdytaixjbdwxnnkeivizgitvhnqfjtabhtanxjcijwzbohepjcauduujtuvumbewkppseihbgmpxnkbvhgrzqwwaiqoom','ydefzcnncqvqrgljkeguofzrwfxohncorqqushcxunmqmnssztzpjazciluaeduejwtgdcgavykxsncbehjtmxwouxgekwzlmtvtotesjchsgrtjotiduohadgchyydeqxuitiqwxdlvpfbuhnnvnyvzrnqwgenprlqcupqfxozdwayobeoyenxehpqbrmduzlhgazluyiwnowakinfhnjuhlapfzmbnygc')
+;
+insert into t2(a,b) values ('bomhttccontjbhbmsbrlwocpphpgqzchwykweomantlxyuucmheodbhcrcagzrxosazenbjoeyeqbrmllyzxpsggarpclcsoxbtuiuyodnrflsofqoiefeevtmhwufa','bogxjwxdfuzwgflehykvxhcztbvdyyfirfyesivuabsxgcjgqoppfpkormfkhvqdyldirwwucvfqiikosgdyxyfrbcobotfbnqrzlrznjzfqcdggupbetxiuumrquaaomsrrmhsnmzbazjxhxgdlbprwavrrlyldfvcywsekvabhxeuiltxexwforrdelelqgslniujdrhgyptnkidq')
+;
+insert into t2(a,b) values ('kexytelfxltzcqfrrreistfjfjfkpulxdrxornyhzfjgvnaysebhotzqukdssepwlnhyyaykhpuqgeoyobxkelvehdtecpgfmdghizpuwxpcfwrbeivxdubrrsjnqjqmfwgjkohwsgoejwshlzgyxjbqlxfyqjkvomcdigxkapezkjvdctvcmwovrbnnlpsrpfpjgzdrumq','wjuqjtkpjdinuwkukuclvfusdvanjtzhfvfggqrvubyhhxuchkmwuokclwbzbenmwajfsjuphnohqhytjbtrbsaqd')
+;
+insert into t2(a,b) values ('iguvsmzohcsfygpqsxkhuridgmwifhxyraxzhzmnukygbdbnwmpwsjawcrczxfavomlgeiymjepniivjjrtqetpricdkshqhdsjzbsnptwzmpklibidqgabvilkasyvktfoxijbpdrmke','djzbkzpuxaqlodwlvutkqxdvqzjefhxwbgpugnzbvrmzmwddcjmcihzyzsyeeyubntimmiyfiitdheiwkaogigxajycpnsvgsvkmfiddbhglupocjaeshmpxherazkskeskytmpldupgnexldxaoujbpxcfnzdczxgmgeqxmjklxqmrtmnbrlewgpgmjfpcbcjmmlyfyybcrekxeravlirxdlqk')
+;
+insert into t2(a,b) values ('yfkuvadyaxznsefcgqlabficngglmbgshkflrmtjsevhjfnpzfbllumddjxazwfgvxvbyvgnvzfpyxjmpacoobkgslkdbjrdeiqpccaknejlbzygyrugafhjlehttbzewswwadhlgkpmijxytxuryhljme','acwhetyuftfyejyyzezalzfvstpebljaizhyptxgpxocecttuwxdayhknlplmthehvncbkluivckszfnmguvzbwotzzlcbkixdij')
+;
+insert into t2(a,b) values ('idvorkumzoscrmbusofvndrmjdvqbgdqtfuxmlustqimfkjcflrflyblgvmfumfdzzaayqpmnnizxrzhplhxjfltesbrqyhvhuehlqsizttmiqbrrnurhtjasqijhfboastmyh','aiszjmwdebsgalzzioismnvhpprohfmsmxfjlqugwkclgslafslwjxwjudbickbuyxoslqp')
+;
+insert into t2(a,b) values ('egllrbqukkdlvidgcqoqcysazatcalpssrrxeitlcnifwtisikhfvouvhmznvlmiozgzyqvdjiufljadpflvhoezulvkcqgtnqlfqbbljrrcdowvhcidnhbgcqqcpuipbnmctetrqjromccgvuhjjztcluavdofqsynlyznngfkxspwpxrpiltuenywakwxpuzaswausbcqywddwtixfegwemswyxfwnaktgp','hzjuqctiquqhyoaaokvdivqzakyjjgbtozbscvyqumoooolhvkwjtlzqxjfyaszoxpkxcxnvqlzmjissplqjxfwcqrfptddvknxqnzhqdkccpsszjacqocfyoxfjoaewkawkmmbnnjybdpgbxtxkeclckmvoqhfqcoeihclblsr')
+;
+insert into t2(a,b) values ('wbgkgofhqmmocfhlnkzgcaqewqtjguvbtfxlruyrymnjxnejmcicribjkzmaulgtjrgfnyzdgayuxwwhbyljwiteygcsvwoiawedxhuskitymxzefhlxmlvifsrhye','toyvuwixshsgvljxhbbnscnaxuxukoquxjsuayhzxafobbcdgqsbxxyblqiqhhmmdnbnwpbavxaluakoietmxnb')
+;
+insert into t2(a,b) values ('gstwnzarilfgiyptlxngwgcfzlbytbinlderqlfufbdigedctezmyyxpcojfhmenefvqlwqjyxxulufgisruqqzawnvorzdhyrbkgvciaauldjqzqgyzxvjlfymbttlkmidzlunwkjucergayrsupirwzsmpwocs','vpmqeylbymstzhsvsjhcuifikhhkrpxqnimfutktycieprawdygshyopsqsdqymkoaniliqyicugjewiydozktwqmzqqtksijwfwuthnhpsgmpxnmbxnmlnvxtnwniikfwgnfehpzlxaqwsppptmdrgzzlisyawomtxvqmbywjrbpjrjbmcmfhkkrejgjmwhfjcwxhleyoendwhlppvopnghqvgqhs')
+;
+insert into t2(a,b) values ('mahwhfrrdrdyldieajxujfbsqytueiwkptyrfabvuiogptphnpfwtdarbigkcsvblfwlelmlohklxaktudhdgobcshmjctnbsmkrwaiwepnllfvtkruomdnkybvdlyvivjifxuyawtci','knwsiiegisazpxwtonekjtxnotkyqzitkkxkxdogrvxmdigcqponffwbhfdmverwjwyeonntvlgarwkinjwrzedmcytazgwttijmzkytzlfgcabdokuevzrncfizhoqwztkohnzfpmjbekrrpclvlsrieqzuvy')
+;
+insert into t2(a,b) values ('tlgvywrwlbppwdemhuhhcapqzxpoyboerlaxcdbvzgoepxrivsjjfwjtszhtpegjkpbaqyofyamhjdchgflsyoughzqnpnnzrbzfichlqdqxfwizsyzptmzmkpgrrgcekhzwbgsip','ewxdgblhzzyngtlybtdjukkirlqwsegwyshszfnutejdnfisobtvtvzlaarstemrqybyngsfsrloitthwzkkkovzrhejnrbdcakkfsafasfgpisukunhduhioopzybzzwxywnyjwcakzgplwfoexptgiitizwzvtjpzgmeulteiypeawoutzofkksbbpkmtrdnybeulxwmjdiqcgqyhhfdtdvsgzniwqkyhpugteefeadydqvwiv')
+;
+insert into t2(a,b) values ('hdgbmmflmsglkesxozlsztptbkxvpwmcpeuddwllmalzomrdamrfsudxmfhydthxvqnunugcpzrwwnggxgoahlddgiwbmokavlfgwdvgrtlznsoxzqssdqeptmuyfiubfcejaficuetjyftpaxfvujmopapgzqmqjoltngoouiqsfubjgiosroujfbripmpuxwvnfslltiwrvvjvpiqmczrdpzkfcgghndmrfvzjvdyflymgfpklfrw','fcevghuwlrajtvlteojrutvujzyhkkdsogablrzunuomnbtiwlfefwmwzdxttmmkmubuounxjgzimdonhrtorlofteikmgnndpmbfkryyneahldejiekpaqpbcbibgsptypodoriljvizcfagolnjduzxismpzfivbktiuscstszgyuhtfxujpjjkray')
+;
+insert into t2(a,b) values ('gmeceerfbtopdgewpvruncfcprtfmsmhzdujygognqnwwugkytnebuqlrjykittaxq','iovyuehyqoweukobfqnkjwxtlsizqgkmtppkbqxznamnwbcchgcrrbapplqhlwqcxhnbtnoosbjtlbpsposzhdcbgffkvueuxpqjefnbwdjnvkqiajjqfikdslfbszrfnsymwqjdzthtsskxrzeydesfoawjclwbcxsbeyprmcpzxgufbtztqzpmfhbicjbk')
+;
+insert into t2(a,b) values ('sckzdvuolrdniibzsxfrtwfabmbiekmhvulrshydsajlgqksuqhbsyakaezyugevuyyukiqieryqqbxkogiecnfspiibyaijzyhhkosdatbpcemlavcnqzxayjlapwbrngdpxzarjagtlysopygpyuyzjtvtzborpscsosdqvrate','trmjnmuczbvltumwlkacxysuumgoraapifmbhkyaqbdipgthatjlqlazfcmsbitppyujxzofuzarpdwpccxmwjdmvzttnsboynijcbykrkeuxrokkuoepakixavjmkqmytkjfaxbaxdtmhnecyfudwzgymeiqyluanwcxiyygohmiieorjp')
+;
+insert into t2(a,b) values ('luopbdxrnytzcrulnrhygjhmlqxjytkhrgiczimwpjshoxehtvefnfghejbylyejhcamqqrtavbnjwlcafjttcuadihphabjsdcvllbfpftuzbdltascxzvksymjqlfkarlnxpecdpysalwojhiuwimmvzciogulnnptnvylqvdqweusazceclzckknwrhialwpdsmtllagmzapykwxyhoqpvekjjedochrmzthgihimhd','nybiifpfzmubcgujasziuwgiggegdiloiqclogkhxmdxlpfnckyxncojatahokdfvqyntwwcwrztjtgxswfmalrdpxcxtnvrvbtafgadwdozfqdbfrnmxeaiwhnjurgbhahshbfpetjavcizsnzqsxqxcxyiyorkurceeqrgtuqiqfidjufopdqlfjafxrgvvntlucqbobvjagyldofsngikeqop')
+;
+insert into t2(a,b) values ('rlkndgtehhmxwqyyeuflzjrgozjssbdknllxyutpltkfwrmmxubfbfxngxfvekfeislwkyyxezhybuyckpffjglgzoobfddsulnfckxmepszshejvewohwcjqrsduudzb','lwziouhlmsflwldoysbhguqsdkpatpunsvpqecwrilqgbzepnuaobfbmfsrvmxtdlurlovmfkelhykjuatskigxczmikjgnidgzrinnkfsdizwmwzmuiebkzltcj')
+;
+insert into t2(a,b) values ('bdgnbhfjemeukjqyslhzvsvwnxjlbarchxojetgbfoymfxuss','zufhlzqmhurgnzggdtmbtkukedgakdkjpkvinfgtghajoqeffzghsdildfwafzqyqymxzmfrlztkxdylaajfiwssrtxddsamxycfekpksnfilmikoiyqltlqywigspahxxmcdu')
+;
+insert into t2(a,b) values ('mqmbqxgmfrdhqpyoitwwvnahcfsftvzkrwbvtfzwhefbcdyzrfsztqfovhdphkojuzftbbgrynryvuxtistkvqilritroutqnwxoijbtyikgosgwgdstdyqulykarxtvjnkvkfmiwwquxrqqoont','ncnfvfsnpjvea')
+;
+insert into t2(a,b) values ('okhxwa','dlxemusjjsgajebxbddncjlsfzi')
+;
+insert into t2(a,b) values ('cnymfmqbqvrwemdqfyqbehhhyeglzuwiyrcmnlxngfnumynpfxafgiwinusakhbudtlbfiirunyyvjxijzxjzohwkxsit','rlwlninihergpzssrdpprqgzvoyyg')
+;
+insert into t2(a,b) values ('sqkgxractftlayjacwoevycprteujfelaiwttyiqotzgkiwwvaabasznsmuymlddwwoihiqxgixpmiokjqcdpyquhhrdwuchoybpcrwbajrxhibtaaqcssxgcesbitlxvjjhycovmxdxnjaymzymijkcnajykljfbpxbotbtqwpxvjpuuxvlrggxolcbvdangomlwbhbbnethhaiomjt','rwoqvonsiutncpmznewfxlryxpmsatwiowtwcjdrtyesecvyhhnrwzkswvxrrfpxbgtzryopoeeziqznpoynxxmpbncpurfglxncsnrxvbxtbvuhzkejjuzcpfuedpwjjtwpsqfurafaqkmvzccgsaiweodkgegdldypvmskkwlgmuxncetoudpmnhotoybzhotoobxctbtugipubjpjmpsdemsumxfakgojscjqrwv')
+;
+insert into t2(a,b) values ('xzicaecprdkydhmvkfmzzlhnrgsbjrjpazwxuhabzusexds','hfrfzsprpxdnbomwyhozcxvxhjziqrzdmetesqfcoqlisaepvpyhrtqpirtbbrsjnwpdtxxrykuzerwckh')
+;
+insert into t2(a,b) values ('fhappgwfpgwuckmsihusmlfnqfwjaigsttwwknimwrbajhoofmowqlxxpbngheghupylegzyvvvvmvnfgrmsqywrkthgnrmfylacmljfjrctjeielllpdybzkcjdapvaujdaqyxfhmoityfnthlbsfbpvovlsicoeaopqbvhqnfwrbbfbrfeyhdfeyddnsysebduxsbitrnpgmvjrypdpgaidzmobyxtcgmhvbswmhpqntytk','psxmaknahpuijhpfrldlvdftzjcucsxieimzellzwgdswwwcnkhygutqsjobtrws')
+;
+insert into t2(a,b) values ('zqofaxl','htqbgvxlcbvbhdpfczgviamuuvreynmuuagouxuvnimshetssdrhmcmfdkvqwftgifeiqhhbnylqhmsylulyhjewwhdwnocxoaolwbzwmzyniggnggtvkppaxynanzjyncmfridmxlntteumixoouluyglrqzrzi')
+;
+insert into t2(a,b) values ('wvnjnmyjkuktdxymkbvwxtlnkeysdakyrpkhtthdnkwzkgzbxeokdxlpiymyrhwmqlswupgxdrueynaouedavheohesrahtqskcbnnvrpnubcbppipdervthsamenegsyin','blxriefoukrxjmeouzcxxlhgwtfpdditdgdovdvtsybpodlhbystnljbokwvpvcxvijblaurdmzdcjexkvfxskezjhzghglldghgfdsvbjfckt')
+;
+insert into t2(a,b) values ('dpgwtxaibnjndezpkyehsknozjbnuxnnupfoysqqvtncocdnrglowvijqjaggxggbmjfofenrvtvoxxcbkjyehsabbnnzxazwxzrrfnobybngiqtkdgtvovenlsgmxnvrmeopvhvkwckbgzkuvrnpwjzgwqoocmsqhaysjfwityphywbjcmimvlssvjnyrvnbjqttlaklvnpvgcdlcdwhmablmtgvxkxiupnjgo','adzupbzjapqhlccpurrkkwmqmgojicqvdsaiipbljbgztgdkuzakjlitsvbrgyjmoxoipkkliqoyfggdqamrinkwjxxjvblnearovgheiaucddkacqvjxmvgvxebqgyjfduprquwnxgyhdhdodxmvfqvoqk')
+;
+insert into t2(a,b) values ('ijijkprlmohhvvkgxil','agytybpbyvrxnmfrhrxtrjhakainkevcietsvoqiyxnwyugidkqglxawmngrimqliewdpvkplkzjrskgadivgfvcpzsugaololrodtibskpwduxzdcxpmpilfwribruljhwgwnzixcyjujdmorxaokocqlwzbhcghgbjjbvexlvozmawzwdfvbszbbzkdrjpwsbssajmfzfvjbwwis')
+;
+insert into t2(a,b) values ('obttwtifooepfegepnzzszsnkihgtusnzklqkjjeavzvhlamarcpxiniogfibxvqinjowwdortsmpenxnrycorptbpmygyjeipzdgdkqtxyzjpzrsuybegsdyeniuqwowceaevtezwmncysanwycimshwdgasayywrvbisceersvfrsrtqdfirbkhcycqlrdcvcsmyjbgoigxfczrxwusltqlahvbhmdnkfonjtsvhheeiqsy','onqdbqyqgebzhqgsgiukwadrjggovpjatfrvfypyilwmvwbgjfhnmdbwyylkjetzhdycdsqmkwlzgkjstblxmbxjwbjhbhaarvbpxfnvdqrnckbecvdkcodorrshhvebtwddzfbdqjrawcswcdcejazbwyebglrkotggiwheyuraulafhceyavokknzbshoxreegkzasgxwsknqeihfunsopyroixp')
+;
+insert into t2(a,b) values ('ilzdmgojyqxguwuqbfzgvmuihkxnbaikfnnnfdkfqiegkcncouteargdcpeqszwxxcmsnkehmbjsxmoiytasskhsrznbxkvbvlaobmmecmfpyrikoclcbhzzryjmo','lumrsqyxxaftngqfrgwxhfnjgoctjzqyqlxvlhwzjuqkjffxcvfhdbiddfjmbdvzblwnklfnkgszxgyysvjmgdhxgvomovosxclfdlwphddlvudzjgbpsdlquteqnljjogleledesncmwetxpkjhtsbmyddmsuihcmb')
+;
+insert into t2(a,b) values ('cinnledytthjcnasdurllfcsoogrwosjbjerwanldzlqjdzdvlwdsdrtqfvevdbbjzssbefnwgyknbclczpjimvmzoxgtbsjhifekmcdhebdzxyflmqbhvccmlltnyofqxxolznzsoezfhbisnni','fquhofyimzotziowffdynilxzezzbpzhgilnianxjkmxniakjjyqskkyandegytxpabybttikvmghjzkeqefyxorlzqudxxrrftciluejqpucbeazeumorjidjsisvxwhcrsjekjzbmirkchdnbkcyxrrkpntnnojgadewjqlrhcbucnpipqwgvfladosthfu')
+;
+insert into t2(a,b) values ('htyzimhlzfvaoklzrguadipblmijeeeieicryujyheoutvqzhuuuja','ywhxtiokoyonijvucirqbcsdcfttiypajkoopssqwlndtyyfwlzsvscefcqgafnhlhmggisgrjrcignlkbxkdhp')
+;
+insert into t2(a,b) values ('aworenrzgwfupjtrkciwxkygohiadzdpndwvfibjwylfmoshsspnjsurfjghtwyflnoorpxiccmhxmzssiejqbzrbvwoleyvgcryzppvqaxiextnadlrbjnadbvfmwydahyaqpnqkshavpvirdyvavoykrrjavgpiecvqmlqfkrnkxzpwhcxeamigtqbekccitxd','pxxqheywnczvvozlolvvlcqkwxobqyxbfhjcokfifchjpiolasstvghgihkxfdrzogftgpmpcwzzgdvdwlybernohlvggmzcgiesfmzfoxflkdzjorryfaupvwrbnsndgwctptpktrmpnjhvjixjzmypzktwobqnuyxfjljwesedordjycgxgwqbbkgabitwd')
+;
+insert into t2(a,b) values ('vzryvacqaicewkssmqvuvzgxkwijsvitfijtylvmnrtgpkdbfooovzzjflkpwhpbvtckyxtcczfnfzsdmmjrwzfumxognzhecwzrcgzcvbmrikbvsqgfplcojvkzmdxxiknjgydggqkdh','dbkmoaqpecutmdrtgmwxikviisuzeigjgdgpxrijamijwfefprrzjccaufbtpupex')
+;
+insert into t2(a,b) values ('ucadddhckudcyc','bkxgfffduitphfagwlfynwgbinwqhhlgphosxfvoqdjktvmvjbnuuhtofwesebgflckwajbptgextpixihuluerjcebweecvhhtcfkpdeiadibataiqlestlnizinuedmmqcnockkrdpnqgsphwulgzvemhbplmpmunsmivbendfgtmhplkykmkusrnmxrwkackwvp')
+;
+insert into t2(a,b) values ('shbblaortdcdjwfvcaqhaogbznagckmxkzcvxsnonvjpbzwmoojhjyeemtuiirdghtrduytdmeqfcgwsxkcrhyziklhpumaxtizpqoknqxxfgkburbgruautcksnrlbhkxcvnwcdqsljskiqswszjpladsqrpsrlwirxsvzodpghunxpwsrjeloebyzewoigsmmhud','pilnzoaidotkgrliprgrxywlnuuzhaejvqcquhjxxmqomvhcwmmfnevpumiwfflaoeokhfpsegqzefwflmnglsnxubmirtgsaodgftijmsqvrrimtegvijitfzhyrhpvgxxsixqneuydgeqylgfupecksqgguabtyc')
+;
+insert into t2(a,b) values ('elsouslytqzegpxhumoddbkwridqwimjxjmewwximquzqvwzxynzyqortizwgzolxyxaetqzfaftxinthmjlugtgvenmzjxhiihblefndlporwltyopqdkavrmquwxtkqflrxymzmsxjncucrgjankqttmvbeoukwnkugstjexwbfmkeampugxgdhckosnchcsvngrvxaotdxxrzxemscpcjypurvhvxqalndfqiubrcrmlpeiku','uxcnnodsyigdziuzkljnwbqubcbgimuoduizxfvgtkfitajjfarawdqtkcmtuddanezzdasqquhgwalcyndbcjkohcdwavbwxobagfvfulefanivapbqywshvlicr')
+;
+insert into t2(a,b) values ('wjcoxqtpnhwoguquyvfb','ncugskcijsyolsmryhcsu')
+;
+insert into t2(a,b) values ('ulbakxjprpauzbmjybaaywkhycsgctdzjwybqgtemwieechktcnygyfozaynjernjzjxdusmilwfdwooqkwljcigdyewfzfnzcgshuwcgbaxptxesowqtekgdaxiivngbiqqqtntxhutsvjppfyllbftcpexgnetorxvhcdtlnlaquefkdnlqfeezutyvbtbuvtyptubjikqexlf','kavdkzihpylggyxvsbbze')
+;
+insert into t2(a,b) values ('gvupxwhqrmxudiipvjywytygepetmzytfjizaoxkvagjpadgwbaoltwfeczslxeafwdcgqcohiodexmbonjrcndaekvoslquwyjjoqyvbivmxtdevhxmaamgrqe','asmodltwbhoumfkeldfdyubepcmfgmaufjjxzizungymspmbgclwrkyiqaitqw')
+;
+insert into t2(a,b) values ('lnnfguvvdsmrwkgeivuyjrjgqnq','fsaviuuoudruukmyahreuavnwzdoqidxgvepbiyvsnsildlfjutkmjdqwafsuhbjoimokbrtbugmhvrduhjjsuxqcf')
+;
+insert into t2(a,b) values ('dvrgdflqhfqwtwuywlycxxcjrttvsgubmtfnuiywgoxhgecatvxkuypmvrkdfryrfbabvspgbchhmbndnwtfrulafqdqvtbgeswjvaqqpjszhxyvjewquzwvzgarbjuyitiadezclfmienshcellszuvpqeayvzwbrpwauyxfppkzzihmvbbdhwrrvofblajqmtmezkdjlherdxvocsjiigbpcemcyjghbihqnw','ollukhoxvdq')
+;
+insert into t2(a,b) values ('jvqxkoxktngcizznegprikqgrerufvcfyriqirkhyijqpavdupzpqxenlvrvccrjvtfdlyirzxlpyvdgncqbqjhdrindfsmbuywicfnzglzeaaoyrjfxjokbjiznkdjtldoxbgumxakuqvvuasidcuebrdkrmtzssnsqxecldoadxocjhygjvpxayssdfpdmwftrtgijgmztpdceiddzdtgywndhvaxurey','izcevhquytteicmkvqkfiwetzuyirtgfpeykynznxicezorjjycsrr')
+;
+insert into t2(a,b) values ('bxmjqhthxjxlqniut','jsxicyfyxzsctnehizzqqqgogcutbhapaaxsedbrbamucvnvgxkcjmnjhrmwqmlerbgtyqzwdkavuxaitxmfitfygqroroxpvkxpiuqsruhsxjqesdqqbdkfknzgosnazfgzejwzcpakflnaukxmootkzibsxfjyzkwnsveytpifaivkihbwpicnutfmejstqwwwujycxobylqfxngntusalcenyskktziscld')
+;
+insert into t2(a,b) values ('mydercxidvjqjvocqmplinpazfbwsiaezufgjvmaztep','zrtcwfqbtzcfrtudpzkiwhizxjgjnazlawsaccnreegwbtfsoxmuimdfryokjboughhxupviwrfztjithutlosckzswbtiiqguizlcmkkepuqhrdoylnothvnuavyqgokbhaoxxhyfbndaphcymkdivwaffqdbrdwhlyylogrbdclarijyhwblgwcnoepzitwhmtmfgmcaxxcialfxurdvedquo')
+;
+insert into t2(a,b) values ('sfkbfjudxzqdorzvjocpfofrtpkgfrlekjokdqkcpjwethudoqvkqevcaonsuwozzehaoototuikvcvaebnvlkibcytfsnbnldpjqnlewiejemgcpaycwqsdiuhjhhhtyqjjligzdardhlvelxpbebxbplzglsatfuxbrrkjwwkaafjrvgba','dqwgnxvkrobcvvncjtlvtoycwawxugtgsomqquhyfaspbcjscfafqyobetfitzbhcrokmgqzveaopzjrucazkpzqlphycbdoqewlorvsxnllwqoazgchbrmvglmslsdaappxorclpodomhvvgqcvwkdegmwewsdmffahvibcagukuqmuttfwzgorxmuzocydautgzynqucnoyetc')
+;
+insert into t2(a,b) values ('zvqzzyqqrgnliutyhynallenfkyddzsvaqloftvedwflzzsrkwrhtaiqwmmnseaokpgbyctwwptuqqhciujjmosguksptztwkjmjvsdfmoaqdbzzccyzokmzyvhbljxajbjkorfthwrtrrqrbfjtjaqoxlbagcdjrmmrgmagiqzpbsjgirpfwskvpnxojsplmhbprqvnwdnzzpumfajfxaf','culyhvfsdrrfpzuvenywnlpfgmevjmphbllzlenvdkobwzevftusyujsqbcvoptxovuixzvhvvepbkdcbfzvaurtejaxzkjihhawyfuawjzmfsbmddzidrxabexzgvkirtsmiiofzovdntoxaaxvprysmtutxhyxzojqhpzflzphgdtprlmawxxlieyivirdikhftlvqultiictesjbkqe')
+;
+insert into t2(a,b) values ('prkulynjyfhshobykaznyjxahwsifgrpwhexoodiqvrbtfyzmmbuetfymgswjjcqdcjkvvtzuaghqwqzqjtlxapzpkmlpwsyscfobxiocgfqqewcnkvpritbxasgasfjqwudxixzcaiubvkgtvnenhtgmoulxnavteicbkgyuyuhdcfdskjrkxquc','jdzafdeudmtthsnvkynjzeomixtvyacvdkbipfmjlxshwvyrgpxkvtlyygnpxpvxeinlbmmsetafhuhfmxqqwnutlvmhdcrvsvpuxb')
+;
+insert into t2(a,b) values ('cntrlvtjm','vrmpkqdegtayojrbhrvvavdxukyqsmwbftmvigwvezzhatcvisqqmahkznzrtfsbgvorbfxlshwogsrywijoiekyejnsrtmkpvdvryrghyzvhanhqkrpbxyhylevugrxccljylrjqpivfvrrvqogkoeqvbkupmyukdedseawbdoforcmqwxx')
+;
+insert into t2(a,b) values ('ocmjlirakuwukheyrimxajqvvxqindmdqfpmioesetnahagbmfnzapoedkm','itrvjfdtpsbcscwhncynavwetcfcmiriylfzbhrxzlyaqevyxowvqoevnsqwdbbdolzlvszgpbyol')
+;
+insert into t2(a,b) values ('jvlhhpeqxtbdppojnvxbfxbdjkynlhxliinemrqlytasquabribmcslcvzswk','yepquourkzodhumaydnkzxtaksfgeiyypaykbwwebqltkaliaqgwexwfiznabcoocgroflmfdxciggtsfmlpvtcxztxhrwvibiwshxzamveenvykmqkub')
+;
+insert into t2(a,b) values ('rnddhudhfsqrrnsufhraptsuvhlfeelbqhpfbgmdqrifixdistxbxcoctbvwwmlrieaischwnvlqiqrbzftbpkilrrmggur','fhchdytnhkoenwxosdqionwdnibybelnfefdqczhauhqqeeywyotiaszfgjlipqxeovakqhzwnslphnrfoqycqtpgnhrdjjlptfbgcjzawdxmxjwgntiqetpuqomeueclsjviuxrgubfabcbeemzluunqbqi')
+;
+insert into t2(a,b) values ('rxzmaserlaffaqgbonnjgjcoqvgxyxbhfezcgbrhsgylokzdulnrb','xwkppikmwijhdbwaclikmppllwesyjzkprxomilzmmpzhpgkompzipymeqjnkmpzxmitswrvzjdonbpxkrbgmgpqlmnclsrgvkoruzfeneinyxqqgomnhgaxyduszjejvaoirxqvmpxatklwkkiqzfweptzuhpwye')
+;
+insert into t2(a,b) values ('mbkdpbjfywuivgzdjlnelghxildpvpoztejsosskeegfmzzrprzxzpcpkujkwfmvzlzskgjcrkytdnmrktjxtnniqcbcsxpxoxkrwoajvjmlusynezfpqcalkvphrigoglyevwwwsmzkgdffdkewnclqkupsdwrodpziwllkmmkypmjqfvdqbksrezhljxdkykzsvibedqvkufudeaghbujhckbpubizrdcxrrdcbejhfluvckwyeayay','qrbupliwcqlzqacuohgqvffkeixpnxhpzkmkyhfgsgsrflylgdvrletjnpmafpxxsodxoqjfudlvqsxmfvomonrjuupfhtjhsfbotiaqnizttylizuiugazcwjvxpojqpujkraqwokqwepejcvavpjuxataljxtnyinhttkmimffsfcybqecleosqde')
+;
+insert into t2(a,b) values ('vqhezmvxpsrshzrnlwcfxdhytjijqjflploflsdzzxsnbbxowigvoxnerrp','msiwcwslxqqmmjydsdsgwszsjycscgduidevfjhivxlsnsaiaijnfsbdfrwneoiivhfetzdoi')
+;
+insert into t2(a,b) values ('hpaswjxbdaqpvmdicakslnngqrzkrfssvtmyaanfkxgltdrfzqvuufljlfldgcsvxwnfbjxjqzjwslcrluhlpyoebkmsmumqke','ryedvmmqoptzccjvvovspgxnkrmifibtqh')
+;
+insert into t2(a,b) values ('tpkfuyeaqwdfnkwwacfuyvzhoqwueacuudubsobtiremxokrmjljhehgjegtykejaxfdijmjikcwgyqrundhezyrezrzzgkwrfztklrfzwzpamiwmduxghfsqhlcfxnpogwziydnzsxefygnazkcrohmipqnuttunjlxeilfzvlqcc','wyyhioodipirkfhszdtrhhpuddgvwhkciapxkvmuelmxrjwszhthudtsljyegactzfvybdfgpeqbypmjkkwleypsxfrhfqszrsctjkeiszdeviaczolkzvzookbuhsldtbrzwwtd')
+;
+insert into t2(a,b) values ('ntutztjdecvbxjnzjrteljisrekdhucizshtmldxonforzhfzdwbxiaoskarcabgxdykwbsfxukxekkibgcslmspcdrwqwszmykzdvypodlugmovsaqrkectykytzmlmufszcofvxmpfqgxsbtqrpzucdnxksjbyislqwqdyeddbhvzlvnnvawybeohjlnuvehybkcsbugbfzhyyfuadscmln','fzahlgxmsybgorqaneygdfwerzznltfncxikveluscdesvaflugmlfndpwitrphvynvhvfapciyzckimfctysrgcdufdrejcuvcapbauzwzoeillfxopkugcblyorlcszuuggyuvqmvzaalgcpdcojxnvu')
+;
+insert into t2(a,b) values ('hkiwyjmajeyhtlcjxhhsrqkdfwrentdmwu','ycuhncnoduhasttjqv')
+;
+insert into t2(a,b) values ('iajftldbtjgvatovuaomfmvjypouigboptktuxwmpkenvtjlhtlawfjamzklpcczzgqasqnpaczxpnzoravhfxprroxrzzmoaemktfxhitwyumgooulopzswuuorqywnwjxmjaypxlaowxquohfwplcfynjqfkoiegqbxnlfkwrvqebdkxbfxcgnddvozqhmgrwxbdnfvsvvhgmfmquz','mfcscoghrjundxuxpjsyixrrakewj')
+;
+insert into t2(a,b) values ('rllngkxhutcsijprnflwqpcrtuemydyfoirpubiqxsjyrrsoekebh','bdgzqchsblvnutfxsrjfdvdrmaqdawpekbzgrigribhimgmzw')
+;
+insert into t2(a,b) values ('wvqtuhpshpsvgqqrcebspsxkliolojmmwwbqqtbixbiognpuhsepoxblovnpthbjndtelftnkkczilskllagvhzecriivjafpaourozhqzdsyhinrdrolajlzfwhyyvgpckozlnifvsiurobejvexiugigzpkcecnqshxsqwoearqblaiutjsymzqwinatkjdyrglnqzcouyravmmjztdjviobiyfybmmymiksl','ychymnqybhlptkivfwvatpeurugaqhzgkbeyzfphgbcivhmguqarnsgzshavhbxxixjbzhgosgxxcvxendpfrdvebkrofrdkrwnvcstgicskogtlpjsfkmfjfprvuozbzwzndogygslhtwdddlehqyiexxdbrerlzsvklzaczc')
+;
+insert into t2(a,b) values ('fkprpxowuyjubbhqjlvzylsledsqplmlsscvloxzwdcjpdilmaywisgroxiwzjakxzveqlpckbdgkhzmescrzyugm','shyefwjnofvubdijzkrjyfyxnabfwrpmfrwiihzvlugiqxphwebsjxmuyuszzyjdrcgcbvnbaaxptlhvkbisuvdzomgpplormgmoujjijuaicslgexqltsxvatnavdfewmlljaecjwbjbumnetuwgjfplcwgycfkmkmzktchopmecreoncjzpxkfkjprqfurtqjilqcerjmxnbnizajetfmykdgjlxommoktfibhoubde')
+;
+insert into t2(a,b) values ('xwprgacpprzrjjdqhvdswxannhlfghfdjihktrylunhmarcdxvwydzewbtxndjjrpcxvuudfasnparyihkequjptkxmptpjulmilmjznylnthtjghcaltgffdydkxhcgxxxsiuwixrhilslcnxbnhgeimaudhkbbtesolirmpcbapssgnsqbuqjuruiassxikmfyorhdsrkpkntdzjrstynpyjjsedvsnqvpef','qyukymjdgynhoyrlxnmfarjuadqtxcvjadilsfmmnoz')
+;
+insert into t2(a,b) values ('sslvzlhpxefzfpbznnqsymsdxzgvvoqcdzycgfihdzwagkwexijlyhvwcdjjhmygigshbkekoncdzkgpfvrdloeaxzuhhytatkremkxsxujallybfpiaitxie','cvedxyhrmlravxidkuclnaqgidxistqdwiophcbbcryysapdkszqfotmsocsqyhadxuopbtiyfnkzyqmrwaldsjyysqvpulveydprfreyaizirtmpizvnvrzxjifcoccthugdmthzkpyyrszmmpljybatljhlmxrfahlulqppwlysdouumtfzqmbsqtnlcqxsxnnbmmvaarxepxlymarwmqwyyhepnfjemudxarmykvbdklpzd')
+;
+insert into t2(a,b) values ('wddfupixlvnhkncfwtlcbqpgidimiouluggnhjhfpgiondtseevhhxmwfjessyucquvuzgylqjriinjbfciqjijgosmkwqfrphxkzkz','ecvmmujgxxcajxfwtoiyczeapgokbwjksvlqyikurqdprjvlfwbnaoavguzvznaavuuzueopfraxeqmsustfnoniltjxuhbdqzuaoiucvhtsamgovgvgshxzbdciromjxcoiahrjtujalswuedtfarfx')
+;
+insert into t2(a,b) values ('mexbkigyauhhnvwcgauvqrhloamzagmqmymlqyxbvectoqkzbvmfeistichnastqrmmkupdvitpjletttrffcqlufgtvhkidsuroytnuplzltxrjwewlfuyguh','xrrmghxiakszrxvxdjqmbzgjdatviouhcxuhhdfrdppsejpeqpshvnfriqkcdadkxuelcamoejugaqmblvggfipocebczzuqkzxzizkpttojfpnrzmmrvkmpzjokffosoxbigkaisephwmkzfjenqvbhuqtqelrnyugmfyrotbxukfxfvfnxckhoezuxgqzocrcowchvwzvqscddgdijuxam')
+;
+insert into t2(a,b) values ('xlvgzifyoocvzqfgxtgjgbmkeuxkurhdpqbmzlmdkiqqecqdfxxaqdbnyjjgxyvzaclpkbmitjxtzwgzvbjyqhmhalzxkxivggwnbotvecckdlrpeiqbqfybkbphlmwgihyqqmeyosgedpxm','iekzwghrglkvfhbiddvufqhqzqxqxzysteefcyfppxfcrhyuhbscwirhzrpujftwcwlamzpymhbsxzzyavx')
+;
+insert into t2(a,b) values ('ngqwgpqoxsiaknlufzqutcmlobqptbfcfwznjqnusudgzcqqerfdgqbhgdfaalrnvpptkpvfcqvhdnoolkopmbrgmycinfbozwnppdgriyajeetxktahazkdlrthuzydhmjvvitdecoqpdmhknuscrzwibytgfxmtrzhfppsltlhcckgsx','darvxaqxwgdhbdhqfuoselmdzlsgcadfzkzcitufazspqizyxwwzfcpyokltuaevfduwzvycdehdugccrgfvtrwknszupxlxipepyfqdgxvqxuypwiuqwprbz')
+;
+insert into t2(a,b) values ('royesgzpfuppvwpivhvejuovjdlftceaqrajvodzvkbtmswocmcrentlodymbjfiaejszgmvlrpazgiqpoclxgnkd','myuuamyjjyvsxczomkjhwtebmmkekgxxlzmwxflbjvhhoovuudqucwwcntywlvmkyxddjjrzaepjbsjxjfzcehucgjkwqyrgrgczeqozmgaduonaidrrogwushzrnpswidxxuiynoxagzaafwwnmmsraarbyuilxoxknrguxdlzlerbmiaxbffxaimtonoohmwevpxittpkljrxvqxqfbtkezvcymgndaxjyrnpjmaebnxuahejl')
+;
+insert into t2(a,b) values ('uwdbrzijefymoxgisnsakoambvnjvzjlikslxeojoiljsglkyruwrwpbqdpgyftnrfdaztnkactymfncznfakwnfrlqgzpwwvaanpnyonqjdpmvyhrplptpquyheavremtuazhcyiqrxweidxxdateweroqlmffrhqrwtifdwamtbcohedmqrrdfkvwdffpdtkchtxizawzwbczqfryfnqxkqowhulbqmbnhdihfaasjnbmhnimk','jncrwciapplhmqgpbkfrurqtzybiugzoqhgirnpswwfphrqyionewqadfgcbzsmsitfyanxhnahnqrgbelurnpiubgcigssofhjkzedvnoonrxakzkofnjdymzifkmqjbwpoeahouveilgsanqhiwqkdnhoxvtzzjqcphdwbvunxisewymlgsmhtqsnxjdqtpcybjdptfunmuuvwh')
+;
+insert into t2(a,b) values ('qzcnahznxjjcxmyonefirppuagybwlfiyezcxylmswaugkjpymwjaikjnlmlsrktvtzvbahhguowrkceiywirpfkkeznjqznwkghdkccjedospxpgwtnbykptmjsltwlzyiqqtbmfufxcxcxectucdstqm','bylooarkbsnsgeimilcqoqxsxbmirvmkluixtbbjjbapfzhngovljbszwdlgwygiuxaqqzaedladkoangdtldshynxdkkseclogwuzrjoewmxqekstpzeqwswvhcgv')
+;
+insert into t2(a,b) values ('ehhowgxcpmccnxonoyexylvdwltz','nbvxpuyayzrrhkvhegkxkfksmsfyvidmpzhxjsjnzmitebinnagwtbpvtdlftkrxwurwxongjxjcuatebmpdrrfpdvwmfablogmqjlgpzcsyivtuaordlketvttssbbexvfpgtgpczicuulzyvvkrixkypvgwoqosdhyacwsofcmaoxowgyakiyapgkwxpgeaiosdvmjugzymmt')
+;
+insert into t2(a,b) values ('alncifmictgevhcbbqhpuebpzlyuwpgtwbrmlabvzttlmuzdxxqmktchwikypzcjquvhxnczetxpgeqnmysayzscoqsmoanefskrrvmwjzrzryvtvsbj','ujalxysqqesfkjxddhjvetutpeqfednapfjdcvawzvzrzset')
+;
+insert into t2(a,b) values ('ypmefojyyowcmjxzpcysozsrufmbbrzcsgqbcseoohvnthnfdlxiphhwatwuxcnjcoqsrsowpploekanvbrdycsjqbxcvxpjmryusefjohusajeuiznrzzfohzzizayeuioqanafpmwmgwvimbubdpj','iqtxllctkxmcmkxastvhsjqxseztubtmxnusnyecagchdkxzjvjlqq')
+;
+insert into t2(a,b) values ('pgmpfohttzkjdqvwtepoqjvnlegppagmapqwrtecvrgdfmmzuxvjcefolhcabpxzptjxrofizbtdkqxxmbapznskignvptqpgsajttismtbkylriccvcolnasrmfjnfsgmcfaovarpprweasjqntzcdocuxyvxabjbzdajhbxspzjsqjithmnkyotrpgvhqq','mqlyutpkkbjbtnrvxyuwvhfmfbtpzdxybbwqsdxatumhsllqa')
+;
+insert into t2(a,b) values ('pshmloncdqqrcoqsftvpskpbjngqqfrqsnpkwhrhlwkjimieiuxjkzuuhkbkiqxvpipfjeemajurmpondnlvhffryumgurqenmmkpdypbxznlgmcastwrpesyiwjcmtrrqzwonofhqokryrcatyyedyikxcrraxyjkkkwwyohxfehrwhrwvwmrbrsclwctlrfhihpymiyxplklhkyooehbdxcfxnapuwkxgsoismeyxsfxheytofikfla','lxohnwolmjulaoagtacemoutgtxnzptuvjgrxigoqerfowuyjhuckmipiqyzbenbuykuoagcvrv')
+;
+insert into t2(a,b) values ('dnmydfkzscvccyyqzkgghyygmoouuziwcihplehkdltofesatevsfrbxqjqovlvxpuftjslnqrbwzrgquvladyzelmvykenfydtpfbvmjzpsujskrihgwjmviebflcpoufvhofcigbnaakzbjqywmwcuvqlmtvkjhdrnygawcomceembkkbtzpzpwzmlaalptduqvygtqqcjmgswthmvzoocucegezcwnjmyqatyvmx','zebfilzswoghnfzuqepizxgfoemgldrzsnsapydvwtcjbmvsbromzudycvppaj')
+;
+insert into t2(a,b) values ('zjduciurgtrcrdhvlexjyrtykhnbscxnmyiokyxzkfcdpwbibcdqxvponhlwuyqquusrohxsopzlhevavprwjzhjswlmmhaltldlbeehosssrinxuscstfzizeoiabwxdonxodqtibbbiyabtseivvlljfkewaihkqbfwowesghphoxzczhltsfecbvqsnpqswqkyufru','tiinqeope')
+;
+insert into t2(a,b) values ('gojktcxnvbyrvqhlknncsaexdzejstwodwazkpllyryxptcgtfaxwzchshbsotbgorxjehubaufmgqcpdvgkzsbbqbkgwjzjzuezgudhtcxdziofgrhamp','iwkcdgudokglfbmzmgnoepjrjcaphgbjshetidrrmkbpyucjoxleifzshygmveshwcenggtqthqsguxkvadjhitrcoxanxitagyleddffojqeyybenocayjckwefisbemastvkdruqpuevmfoftxdglqvvhojqmgrutqsiqbnlywlfynbuapbvzrffklrfwovzzjquzaunajdwy')
+;
+insert into t2(a,b) values ('zijzocxettmnhcsentzzwnnhwkcouoirrhprwvkokijlfbcnbrndsuoyvdvxlngobjjigkcscncqnfhhubwrynisoqumogdsbviwjbddkhtkbxcwuyabwmimrgxbijuayleswymubzgfkguzwuwdqverpgfyzugybvakzrrtjakokavhheqkbadyzsmdllyqeankeemyfzlppbyuadihapdlslylyaryzscdfmsgedjy','byetpdngwowwspngiqwfannsybvlnlvawcbverbcfgpctoaqbqpmditxsljroaehzyaqgvkcamtljssgyydnysdxpsriisphbsyztidbtkheaiuagcvrzbsgswniqdfhqlexjtlstovmbsyosazwmunbszghaunxrcca')
+;
+insert into t2(a,b) values ('mrquaxdulpalhqwdosvfwhfabssprbzkjowkubigxrsebmufdmhgixdscrybzmmrteamdqqbqhhiksyjeuznjamtyxspgxlctrwerxnggdqlhfdgemzaoudvffanxiglpbntfgedrhcxbgwjdldhrptzzhihhqgzykwklsatnblaumrxss','adpgwqwelastvxuuqsqsrbkngmtrsthkjpqhnmeliqxjyjvgpwqehnzopqjotgbzeywvnpkpjmjbjnxuqomeykjwrgzyomjbmxgijjzrrdguhcvtticuiatfydnzkwfcwddymsemzussisxzfxcgzxyozagfbfhmnqwmkijkscfd')
+;
+insert into t2(a,b) values ('bcoqndcjqdlcemfptalkzmidijtrajfkpjtxwxhapotjlyzmpzhlyxa','iwjhzwvawjqtdeksgtjybempvfxuieoytqtmdjebmqfpjouiuvvvcbbvmmyeyklvzbayqvvqaygw')
+;
+insert into t2(a,b) values ('rirlwofbdnvwchazgkzjnhldglwgyrhsrcmqfodfvklawenywpogcopdjglqgyqhodougupgdibgqigndumgaesrrorhgeanhdmjolcdhbpbzthdjzcttxuadjjprnabwmdtwmelafftriaxqiafapvcbeupdueihvsixfsfnsboxsmuagdkdwssfdouxqaibnkrpxzsixgcaxcnnodugnksrezhparqqsvufwnxvlweufv','cnzloeethyuemtfayvoauqvujmbixntheexqynetmxvsuxfxbpzoixv')
+;
+insert into t2(a,b) values ('ykvavfvetuiwtkmvaiyyjvzypkcygbwhkgwqtaxohemwovlakgccknpszlcaynxlylabctxvbjzzrzflyxtreobjznxhuxqgzremirepbvrsotkqcpyfzilewjjqocnjyyppudfilar','fqdahltxwdjoaoqqwvvrffrauamnlgkvnqccrvpmmibysekfkpwvpdgtjhdvipxxvizixubmhxhxpsqacsuhjzsthqkpqnkpsszyzcxocyaunleozyavpsmjedjdtcyrfukzxkwgeaioqwujaoeldjkkcighytecpvqubxilqarnuegkk')
+;
+insert into t2(a,b) values ('lkpsviqssjgiexvlrahvvffxqzrefcbrbjcovbgjhnwl','dctfhkqwwmkeffcrleebgniqnflyqtcblbpbinjvkwivyfconntncomvuuifcyoxtbwqrptdwwbqtbaehhxjletpiueargkjomwmdwemmgwtazwwioraeffpbwmxayxwljmusjpuwkadbhaodymalwulyhypsotsgieciuaomwkbelhgpenbvomwvpdwxol')
+;
+insert into t2(a,b) values ('rbvvrgbdlvdoxlpiekemaeeoxmibhklujhfnfsoteekdpfmpucotqouxcpdbvphatvwdintbhdqjegdmypcznhggsdeilchbvrjlsvsbxokfsarjeyxptnzohgcldjmawluwatcwtkykxdzrczwhxypfxeogl','xfsghigbtvglqjite')
+;
+insert into t2(a,b) values ('oapimkdhmrbmrqprgjtpxizchlwcccgdvbcuzptwrzflgbjdufrmphnwhkrpgkgsduqlhxrupcbtwibvfzlzzjpldievzdfoytcepirlqaahyxxtprpemevbvucoudmqqdutzjjooqaqqekasisxlwsrtrrzkofgfsehgwhzydoqyltqypdlvqwwbngagkfazxwsmfxqxisstskztsmljuechpiurf','ktiiairwukonzrcvzdkqfhhzpqtwodafurvevtoetjtmzourvwzcdjrrcdmfkqhznryoiscxdvfkuellnvzuiqbqvudqkmisfjtaosioeforvpmqnzwuzlollhefphmasyoegrvweictrpfpaffstncwudmijieqifunebakzmamznzpucgbvmwkilqpfecmrsxbbeubbwpsmcdmcizuwazrykrkkxzvmllftwjywybp')
+;
+insert into t2(a,b) values ('blcngdjhladafeofbvlkkyuwdnjrqugttxftemcjgtydesuaixppqiuisodslfdaixtwafxwjvnsnfbsm','lahshkddvvurpfgpeakrczbqtywksqlownmxjokyhduymgzodhkaykvmsonwepajwttilvxgkqgmhfjlehrsugzxyzeqxdsshdftshqyiuwhxcfjprkdkoakdiwwuoqtsayxnkzzn')
+;
+insert into t2(a,b) values ('xrajegkdwpwbtmepkqxcorlyneetefztuwinrxltmfcljitpdsjjhcvyxuta','thmuqcdzotomxrqcminmhfitnsdweenxiifrgbdzszeqxutwpkisjhzoonpvk')
+;
+insert into t2(a,b) values ('awcpttteukqgqgurbuvswqdzoozzozzrtjw','bsrdgjxdfksbjhcxfpljqhaxcyehcfhrptljwxszopvpihnqtqkpjchpnnoknvue')
+;
+insert into t2(a,b) values ('oxhiakfuajyodmkxewgsyyueopltvscvxpjlfmxbwkvayqfdgeqhkbbksnfscpspbqwdsogmxcrrswhezwawmfotrcreqmqvmdvgwxfrkxmsrknbsnrlhzmyjjcddpmpfuzayhczxwwxeeypeuibnvuiofutykkidgbsq','beyracdsgfihekmwzvkivebabkkjqwlkjjiubgrfejlkfnlojqjyvabmfhrhewddwdwarfhamaxumbnkuerrvebamonqbejtjlfpl')
+;
+insert into t2(a,b) values ('xphhojxuiuolwajdijhlbosxpqwnrjuinhcazdwwuujuhdmxlwhbpbapsqmgazhkmighfdzgxvjiufdmscbiynvrilqboifwtafnikd','sqxqfudtvchnzmcvzzldvhhtuelzcbpjoaevudsgndhprmjjagu')
+;
+insert into t2(a,b) values ('xqcujpanptzffahzfyxtyxayhhfogs','ftnkpnscfvfwqyvvcrzvjkxzerleeyevdljdieeghjkduxvfyetlzngvqhmoxlpyjtqcheznxpys')
+;
+insert into t2(a,b) values ('vvfjhxwhlaanvbarrbuhasodunklbyikmrxoyprqhxdjohzad','zmbqupzwurttsxddthunfulgvehqvfchnmgplotvunustkpqhimiccyvjkfjkoogrlkgkzrqxee')
+;
+insert into t2(a,b) values ('wkgmninltclvxazwubchoupgwzxdzagygsoehwrqjjskxjmunajyshqjaxyqwfkqfozpuvhoudgnzykftyjdxhalmhlkcanmcgksahvqubwqeidipygverdmqkqtenncmeyullnullkgskfoydnobbnuvaczajbqxwuenonlkywabchomngenjqxzifkmfrlvavoihvxlyfcmzzirduavaerasrucknr','mifoaeyjnhfcpqigvrluyfnwrgyotxdbjcoemivuosthhsnmejqtbztejtitxgssoszthvyplivsepaefvrelmomlysnhofcnecjhczytinavzrmxcxsemttphkpvsyunhbglpolieuocvefiuutzttonxb')
+;
+insert into t2(a,b) values ('mvfuvlhqnuorzhwbmurwbdewqdtypqekkxsniafvilsyhcylruywysllfezpchtmzkeouohktfrpucbbkjaasqulzqffyoxmynfcodpiuwsxljnwnsuxaysrkhyucwmtjbexagufqugmbgcakvgzqttlhdisxibtuwcjhhrnpvggcyfdhiphcmzyefyznagibuxpkzznjzbvnemiu','awptbihvrianoepzuerwkfoxelhdysxxjxznpcfgoehivnlwxxthgagupwdokpdiembdxkwlpezqbevymktzoxyvfjqpobzyjvrjaohluxasupnhvedqhgproevsjqdsofzrwlmwcvkqaqzgkjizstubzdubwahrayslowedrapgtmzlxzvntg')
+;
+insert into t2(a,b) values ('uqcgadnrshgmyydkofhxnofbimcdxgzepppjaprekdtrtqljuiirthuneocmzqebrqmowgjcxboxsowiegujsirdvwehuisjfpylnvnbywbuohwerpttyiquwushysfyslpnppykoofupcpwnwhiobdwvwqwjdal','bfrgyqxawrcjdayidpkadqzwvrnsaiiicqyaacutrznyhwuvrwvimmosnvxyvonfbzmuufhpaflpacgmzqfefswlqbefnulsiovvtnhmfaezszbppirvxflwqulyluroawpxomapydldowsebmbohilxhllkjmutoqkpiswclojhjxz')
+;
+insert into t2(a,b) values ('fazqqwmgnjdgpwewldppyptmsqqtyeszgpzfvfrvchikfmchibzmzmbhxjorfmeqpnhldsjfpnvqzbfjgrtjrblvglrkvkjsjgsnynfczxwpzuqiznvponauydgyjcyuanerxllsqcqwyqhhsdhcxscelebucbpibestxwtwcvytgpaszzeqkfjorzhfnpuosdtkanrzpdwxgmytxedpygxjswnbbdercwnvidsctjtrkhdlqwnttvejgixx','cdhhhzkvzuyaqomdpcszpjyurlxdguscsdovyifjhrfxqysqohaghxfbgxmmivaywpcntmhilbatrgmawddbxvhzqpcdwyhfawrtcrodtobylkxrbwdhqfsgnwwpdsxgwbjoejyog')
+;
+insert into t2(a,b) values ('orbttblimbnsisvflmjwjfujpcbbbgvljafoldslwbwgrieshocvcsbnduzvzlebqhamunggvlvxcifssdcsirqgsudilcxajrnzwvbxmcxzzsxrnoyxdmphpegviihsdahczeeoqkbexuejitrzisithcasyeyzryawytmlrmrtrccmkhmctyykjkqmlaczhwhclltssjsnkzxeczvrawbgizjxnyoesxr','rvguxoqnkvfnezijfsihaptmipehtezmbofjkqxnpgitymgmqsnfjsgzjwekaytejbzsifeozlsghvykuizovjcodmhbui')
+;
+insert into t2(a,b) values ('xbfslvoeblqbalhmqlxpieloigmqevhhaunpxqqoeuizhyrrucyfzuwlbxuqjajmqkezrewaugzdajhubllxbburjqqqathptbbqcxakiiiasjazvojwwkeeszsilajjvrsmemjvomjsnxniafvhctjhybroiucskaxkyqpakblvsmimsmkumwzvsmxxswoikeeqlaiyz','sexdsiajrhgprqlgsklebbrujgtkiqmaczzntujpgsvvusyyqtfuesrccfwhnhgcpdndtbqttuhnwhfvyvwppccmsanmsgegssswxrewxprvzrhakfohoaohhqjzqkarjcaqqnefamnhwpgexwdaphzcwjmuoqejboxmtogdsubfqitotrvwbrhcjxoyowypmhnedcdwffhifetnidw')
+;
+insert into t2(a,b) values ('yaszuusytvoxudxeadvcncofoeyunlwlwwssxgwtwdlndzttijtnsezaymaxoflsqmvyqighnptneihsiquoyrxlldfkdskuh','zpxpsbvjvlujzdhxiyvsmsztmpgiikfegsvyoicvucemtitaluzirawgpsdlkmcgzazaonyrejvfvwvlfotccdfheluggwsjvrtdgcwouyaiumujmqeeltjazczdiwqjyitadmjdgxqttgilurmn')
+;
+insert into t2(a,b) values ('qjrmdwmfhwqqqtdstmctrdmikhvjkjnicohccdkfstpyjdqtwlwebxrvzigxwfnubtctequyqcdcwwitdqneypddalhxaduhozzyxqpkjzszhumrlxmzogekbgpyrkvurykvndeyidmdxvlwbzdumesfekwtuflvrigsgvhscozdtdkwjkjnbkimgzrhfexwgolhrzlufc','zhgqgxdccfocgilshxyuwjlplbuhdvkllyxnslbqskecysnqtyqbhvrwadygvjarfzfhnvforskyzmqqzgecefqteiaqygktbxnimzgoehpoxdyxljdnevkrexoilgepvjxzgdmgnckuinuktzieocdetpkoxkwjdbuukdozcezzjhojrvrlzziofsqntgluvmpdmkmnjktnkksypqg')
+;
+insert into t2(a,b) values ('cbgwewetditsbzojsnytnjapnrhrumlfbccxyecbaplrfbsdtxdxicakbpwmsbeisayuzhcdrfwuihckcrvizkfifotqggekdubatjkjywabxtfajfxqrmdsxmkqdcxonkuopzbeogsbdiemwamowncyttkanirqlwobxkruebbgmqjdbgk','odglnaaguxsjdkelwfbuiprbuntseynxkqqyeghtplinzfdscxxvyoxiandrcltdidxzpjzpmtboeyquahikyiwjkhzubpkibtxgxggqesxmxgamcfnjgiozyremsdwnmcfmfetkyphgxodrgnbytkxmgtjdamjdrcoipydejciwwwnvbjrngbzsdbswbndkxrtcmnibrmnrdlkoeblczvzilcslgzyrjxjalhhdhafqlm')
+;
+insert into t2(a,b) values ('askobhw','dtdqsmmtngqequxvlzqhultablfxgqalifenjgufmsyyfscfeqdetuyromgabouzbgpespvuotgovrhsiginzlknhdi')
+;
+insert into t2(a,b) values ('lzlnhqdxamrmdsuigrsmcpatyfsjkhgytlmhnihjwiyoanqsjdestzrvcakystokqpbxcrrwchtcahuqsvlkatctidieajayaxafhonkvgkwjsxaacjzxifnxujgujcpmmluqlmkdqycadylkksmvgogpanfutzzjbcrlvhqgxvgchxeuisgecsthhscrizjzfltedjefljnpyyfkfwtaibmszkwpueudcrvxjtl','uhukueeevxcxnvvnrxtddjcvlfwxwmbkhmnsxmcxzshqbpndpbaullvdxwniercimrftvjetfwajlgphfsuclrpsstqhqlaokvgnmxunmxiojktxywzwwbmirlqkedgxfesmfktxwwbmuauflbdpkknwxlqmjcynilzpzjhssoeuzbqvyeesfugkczprqseimrxybiswbkibwzrtpkyvblx')
+;
+insert into t2(a,b) values ('vuhasvxoaaepjgbcudzfkwodbxixpkeuvcsfqpctv','joadboktsbdsixnwfeinnrklqbwybafkojfzpfclpqdgotwegcawpzfpnfqnombaqdxpchajvzqhyrpehbbcypkqyytdefofxbbbsfzqxtjkderkqsaindpizaivscwbhmas')
+;
+insert into t2(a,b) values ('jxjputlhjiostljvefvjxqaehftbxuspzotiugwfdgpntvrqwtgasdynabqmlszojflypozdghydmhengkctsajla','cloaldzftsfmlptuudloriipagjgafwrxtwjgysrdanbpekpcavbvqhzhqxaiszbrrzayooqijuhkljohxlcee')
+;
+insert into t2(a,b) values ('awnnwvkyvtycjvfgrzwegjfkaqwbwqlyyzvbjfkncucgvjwukteosbvjzttvpxtgasrvitnjnulcvwzacsmrdapaqzucdiylwdccwryaybv','eftbucijmsiigwsmq')
+;
+insert into t2(a,b) values ('mcgsobunoyqmuhyewkoritgnspsnmcomdksggexnpzihskidqfvytkxosukjkejsmpuedjjtemqlgfudzijlyngyereluymjnkgdarixejgwvhqwllwkytgtmldmhvrncwavzodkadgjdpmyewbhetjuuujegetbipeexncmnwigfwzshawojigkwolyenffukgbzwgdropaylsnvvlhpdkwlhauhzdnnrxnxux','zxjzittxshaudpycmiqkkeztdrwzaldnpmjcgvoauqyufeinjmsvxofhejvfchzixcfyhiawfkmiktcnwgzqsszyydszyjkmlxpkifqwtmklimqkzvgsiafchkmjtojhbysncafyzlyuofffwxfleij')
+;
+insert into t2(a,b) values ('wczwzkkugrvlzacyvoutshrxfckfpingrszmyluogmewheoliigqvxbyjmblhegspmvvytpsgkttlebwunqdfevjcdjjxubcsmjhvwhjccwvbugynqphzwowsmbetkphehrvhsoiaquctvubpapjkhbsuxjwgakfatnkueoxpavgszgjkwukqvqiexukqzdfclnuwgf','rdqywuyaqiehcftmdlytpfeemosuchoelbcylifigquziuzztzxuurnwjvnuolnjmkrppifxpdgelgqurwroiapjaltwbouvftjxogojxzoigbwfpfmkvqaioeeoloubqzemsdpoznaqcrwcpamhhwdfxnxenbxxyqoxzzlxtipdfwzshwfckbuismmiepkviirjbrwlcvdetmpwzb')
+;
+insert into t2(a,b) values ('obrt','vaimcefqkjjmadzxlmguiqvqyulnvytlesbbgcfogejzyqfypotiiydkkatwpfmtmrgcezedmcmbxloxbnsbiwfipumpkqtaoxkwsexifcsaslgoupwtlavbhxjutlblmifbschbkecqkaioprfe')
+;
+insert into t2(a,b) values ('rtjrduhfdcdnbcqjlivkeudka','bwkzifdcgmbwrdvxpcotaattidnvwzmvwlnfxtloeebkhtwzbukjwuyyuhbcfxcnscoihqeypvymsdjxtyxkbgjoqdhdgwpysctnzraeihpfeoylreqoatwumbruxshctujutxggyydjnkwkfnojaocyevoilmzdlunaonu')
+;
+insert into t2(a,b) values ('rkiarenfhfkyvtcjieqnpphzytqvgqlxgaqctkjskfsqymymwelfqptpsungermkmllvtqtbylgkhyjwzrboaugakszuoafraclpyqvjtoeaidboemukvehwnluqcaanzempkupveueryhetufkmjayuzkdoclkxziqhpvdwqfpswselrtfczzcllpotildwlrmxilvydwbpreuhggzyxfivgxxxunjosrkqltmruuaijlmpqpbydk','laj')
+;
+insert into t2(a,b) values ('rbdxtyoatrtnffofwpxsqfsjxovekauipvliinfkhuiyzhaucns','tbheqeqltbjmzikcozlloybimtwheykjgwmlvfdtglhynacknkncxfqveehuavgiotoriztfsobqasmlllhxwjzyaguavivvbruybwikdnmgjzkdpuqdegejoddlxvovvkhcafkovobbgsysgycclnjksdnasvhelopjzebdrifzlvbdtmatfagmgwaincbdrsqjilnkumbfpgjp')
+;
+insert into t2(a,b) values ('afhmiiogsjphdekhgwpgzpucrimkhcxgacyckerjhrqnbucyljhcvfljvwxzefqmzsvrvpuqsahzokrcztcptknzounrrleltoercbyxfkgnzqoegrhacvjjovwfnwmmgkztgbxrkjnwvptleaqpygeygdinenxjksfhoaieikubxynuduipadhlawyiwfrvp','wfokvronnuonqszbpiesxnkexitduvccrlqsqtjhysllenypfpyefxiuzmgwqdtmsmvgidsrabwpfsmtwdgomroarqnrztfkpfomseqdanbcipaodwzczjnazoknhkncuuvvurisqkoxfwl')
+;
+insert into t2(a,b) values ('lmezwbjtwvjkhhskytdzckckzrhdgllxxueflicdvvpiudtogeyheqrspefebumozfqdnx','lcuevafwonznmuuknymzcnawiochlqcehdevjzyakfwukmnwnsbjscgulmxoigltuo')
+;
+insert into t2(a,b) values ('hr','kpsgabwcbxbakcskeywuyimvqzajbhvurzngzgykzyykzorsespobhbjksnbzcvehpgwkwqzagrrwtntfpuntcthbyagqkvhlxqanfgexjiwqhykdnuct')
+;
+insert into t2(a,b) values ('chaierqaeplqclnwatkbdasjtxemfqiockyphlbtjxlaxrbfixspakjloarftcatonrbkpvpqakvmlfrfsxwoxkuxkxkacegqaxhhkrqudwjuydtrlxdgrazhhjlkqaawhvldzmuxqmtgeeoqcdalydxwofbsqmvuznyoajcndrqcgslpbsmkyqhwwpyxupgmnfzmqfvyllqfqlvrvpkncefdn','grlbykbzvciipbwhrxiyuegifaptvuyavspzfjczjkaimpnifkloowtthgkriekgmvusamasjvtjnabzeuoomzpeveetcvfydkjbkllbypfcqinajzkrrkpypoxabcqokkdhrbsjxnmwhqobmytxkgipfpbidphzpuoiappwrjarxbphxyyhppffrqlfbdzhbrxrcqbptnn')
+;
+insert into t2(a,b) values ('imnvkllg','nhviggghuboatbriqumsryfyclxmmlrnoujhmcfolajbmcbsohfnconytlkrgpyomdtkgziuxriitbzyfticrwifdjfuqqdduryuwcdazskffrwrvinxgqhejlhnxmtaaavxezjgeztaazqcnvugfkcmbnucvgbezpxdynniatpwesqdyuodwlsrkwxilxvwuzrz')
+;
+insert into t2(a,b) values ('kzrmbtrjjhofuhnkkzaircmveekcyfigxeimslavyqiuzizgcrvfiguehuawmirlxnxerdyxdxpktrlfpnhdyrfobbuzt','yqlvperlwgjbtjrtrrsgeekmudxpmnsrwwzsbzzoyopscgjzsktqjiblhrpyyvrkmdrrhnjcmfv')
+;
+insert into t2(a,b) values ('agbgwhyflyjmpiaepyeeadtywpahbxwlffracdpsbeppszowulzfcftvksxsyzdqevcixufydtlmodzfzjttevimsfwbvtwbxfbaeemlodgchbgaanlziavdqdujkvsmknjerqndfmhuxnirvzbyirnklcqihhdbedmvwrvsqxehircuzfjmvumuhqweyrmahebwngflvmdkqzdgmofqeytbezcbqzxxzdjrwvswxuaezoq','qovgbignlskhbaowimcobwzsogoxddemipqhgygwghdqqlfsfbisthnhcbdnddrqfasphrceoonwahmczxxqvvezmuqdlngnhnfizxywopumwfeppmdvxblhwzjjaiwlwunbvvdwiaixtojfskedkhnlonseozmjatrhpezusdxrqmaluonjuthtflnfyrpfa')
+;
+insert into t2(a,b) values ('ndxqnusrwsslccsussweclhiisovoihukvxbqtcjkckvszvjtrzfqewheisjkcsaetrpmwbyzvqpjfxhohkhi','twzevpshonwkoitzboruujmrwgypxghzqrekht')
+;
+insert into t2(a,b) values ('wygafzltkwrmrmiszdacwsjkrmzvqwofayjtotsakojlczzxjaulsoqizbolnjaacilreyhtpmtizzibxycvfzgsvrejnpawaxcxlkvlcidskuysjigzqxzcxiwtkrzcirmvabhajogdcrajatqwfggaijowtwoqwcyixnmqenaxpljusgaefqacpqtetwnawwpnveyqqgbdfycnvqrukngseqdwqdrkmsdunhos','cluhqujnonhskgwmlecmmbpwxefhiaoqwnqchoblooswxovcghxubppsqxrzlltpsqyadsnqvefrrnlsknhtleugfjyhmrtwsoqxhuxzcyddrtrjwwsvpedsdly')
+;
+insert into t2(a,b) values ('gauzckyagnxaurrxrylpfucctfhftqrstmzychygflgvpqxivpkxloopiflrbtlsvagyspydjjzhelrqdexdvotdtizcthtvwyvbkbzzjkunnxssjmsjwaepjwudxkdokhqkifwcqfuewmxvolwoatijakqtebiclxzvowrwatbypjxbnxxalvqoqiluecchkeaugmvselvpntxcqjtvaqdnwdbnnlodxjrotj','kzdmvsykmkutirqmazwzozlaokzwliqxmyfmirukqupiypmuwezroyyosepzjezgjnqwaioksgxqsrtsmehqquiqqjgxmlrzfvhuolwfndsxowtfudmrthgjofvkbqscopyjbucpagwyzxmsoazqjpmfrykbbfipanyieirlnnpiwldqwqtonnwmyzshrfsot')
+;
+insert into t2(a,b) values ('xcmllmjukplagvussquvdeligoduhnkkpljedqstsbwoxjgidydzfiqnjcbdtnbpzuatofzvghdkfrokdtacrprlmwdenkjbvdofbpxepidymxjvfxyckhtxicipjuiumldqgtuohlzqevwqscjccutkbxnhjfrnhqimvpcabmlzxrabcpgohdlkyseoguxpnjcizcwcscsagcntmmlxmgqkasujhmfyzrgssudnqxudiiynvtya','ioqmcgcycjmxbmolnhmjjwbhaifcilzprtskavhmvnyshsulrgvujsdhboiamzbzfvlppwilurdtuanpeitsmwakbylskheykwvpptkenjnrdzllgdumizkhiieszhzseiewgajjkdozhqbretifhuhkcldskyjqlpfneyienwyqegplpnwrhkxtwbqpvpvvaiwfkbvdwsjagmbytpaxcpxptsbgctedtcmgzxjwhqv')
+;
+insert into t2(a,b) values ('ieumvojayvfibemdgmxrleuequwsgihgoblvjtyaddsdnfyyxznzmdmjitjybesucqrzgkznhkzzreonxhgfjvagbkhvypibewmiexxqywjcga','gjznmimcplpevyudssnipjvnpgtnqelffkfswhhgfgooxaiecwwryljfxfrscmplnplrynygrdcsemytmdlyxrbyrjoodknslwktphsrxpdeyijvamsnqhuwjevgsxtyamlgkrlqrxoeysivitmrymzymdwqzquuwpkawpcgfwxojsnaawhcr')
+;
+insert into t2(a,b) values ('scsgulxvcdogrkkiufgrthfiurwbhhmbrpcgmoimzsyuninbrldnvrerkmfplztobfqloaewleqxshksogmxskpfsdpitblfysqvdkvlqpzrrumknavbsllttejkseoghskuhxjwuayodpickqtngvhuyauxvpdmlowyprsddzhzhajjzhwhlsthsyavxsz','citzcwfxygdrouvtxpqsfjswuyesdryioixsvwteexafzuuevlzjuwfmswoqvlyyvgdkhfjpscwfxxofqvldghqlzbiytqmnzqpfaacgbaimjhfnxnonftghscanuyebpqtmyyyxiqqtlkiikbzwhnqewcvnpqlsuveqsayrqbrtqlgmrmlczenormcrepxawfggysueogenzfoqvmasodicjofimnzmbuihxmznt')
+;
+insert into t2(a,b) values ('cwkjuddvvqsiomsiuaabvbioisnloiklcsdukjohifomejolaqahkmoplgkxyrtpokkjgsipuktstidrrhokcmmlvhfeemjanbvsrosjeldepgxsfpvzlrgelydtntdaoqeilbsldjewgrnxngtyy','luvsqpxbgwxhyzwrcmexptlpnrxnrjvueooxabtkofcvxbzjkyuzupiquontdakcxymkbxrbodwfaphcvkzwodwdjpqqwcmpobrqhkuwarkqeiytvfmbabypzpygjrvsjykwxhztq')
+;
+insert into t2(a,b) values ('clyfhemshiwwkwmzuejifbznnsisnkrqjuimkkbinwqzewzpwcytotuychkjopanopirilcgzdzfncsvvibbdzaddsvojfbsietphgtemugdkeltlvkebmpumkwhwisiazuduqqmhlamgoalbmgjmfvjcpgkfaetvwtvvtbwucrdrsmdjfygtsjuiyewgqrdntbtwfzkeywosijlvuqqnjbudsosgpdodtfkhbiayekujserfrtzr','tiavphzjqbmgracyuxaadzckwifgvxcihimjntc')
+;
+insert into t2(a,b) values ('ufekjksqtocaeggillffejeeelkdxpwdqizwijdsnfujsxkxkthbmyzxiahbvwcfwvpcjkqngguhwimnobtaogqrmmxclrkvkwrgmmpngfm','emcnyrzpjcyhrkpfjnwswocqkpoyofqljrewoomdqbeaglnamkabbeblylkrzqpjcrtxvfvputuvglvwozhsheqatsphdwbiffjkosrkdjkwnavvltucfvbvdtiyttfgemhlqorkdknbeozvdksetjykwucarvwefsuti')
+;
+insert into t2(a,b) values ('owckpzmfaucqswnjcnghvrfxrbicvwwopcqjypkeebydkrypnvbazlledsskxizxwrcmyisbkitwnhmqulfikcozubnussyroiypoqzgzylziljnmyiekjjnfsdfuganpaxiavtsibfvxavmkcyqpxkdxzdqjwyqwvmsksisnqcufvsfjzhdrfzzthcktzmcovfgedl','hsaakcabhhmficlghezeywbcuvzlidqgnfrqdbfvgwtzlrdujxemehkuptdusyesbxdnjblahsqm')
+;
+insert into t2(a,b) values ('rdanltxkamdjfregniuleskftzzmpknygavibtipzbdmtbmmqbtigtqjxrddrarzrdzbmdtzcqxmwucye','hlqjgkaswtyfdbxjsakujcskndzgkvelkimyfrdygfblsqzerefchcqthzvrrlxrypdaqzqhqotpigytrkqkleibeyvewsunvxdijiogncdwthetxmevggtytbrjasxquzbccuzensjqhsrmqquxxcjkkbnfseqaaldqooxjivkrynzwwtgakxdj')
+;
+insert into t2(a,b) values ('svmxreupemnxhiolejuexepillvhdssxxqompigdzfrffcrvrzjnvudiewncwokhwvogdajabagnznnxckasrvvhzrhgpkfebxologcdvhdnsypvwcjvpgalnoelhditzygrpfdhwbpqfqntfxlmwvynocsnridrcjadsxenmgjxgazmvcwhjdrrybnmmaccuqewiaoglfdxwgfzechhwpwqtbldaizhon','sdctvxgnwnagsqgeywfikyutugizlmpujxyftomyxamf')
+;
+insert into t2(a,b) values ('jiomwchjlzdninbupjgshqpuxsizazjbevpogndhpktcjyiehyvtcigmaxqhezshzipecqckkzkwqsdxlyzanckevbf','axmqktuwbqizrhxjxwanpbheayxxmrj')
+;
+insert into t2(a,b) values ('scfzsqvyydoistunsnlzmycsuarqgzduodovlycfacyvbqkoqrlzvcmloltyasqioriijeeubfudojdchzmxna','aqtelspcmpidlegxeluofpiwwmkmgpvnvrigrzrnasihdbowihplrlzajpfamspyqvozvpxgybkeaxibwufepeswdzjbmqbko')
+;
+insert into t2(a,b) values ('quhogysrjxfnrmgwwvjtchbpqxnojjfthjilztrlvuylwakakafvcushzanqlcarkvyrobaseflzdigxjzfeaqhydnawfnubxcmhepccbkmtrkwaqbx','atzxatcnkpqalkwghubzwmfyherzejcfyblxdjscmjkltnvgryryctrgzlgxqqeixwgzcmuorirlhphmtyhbxjrrvtdfnerrjxhqqpiouvvjqocmmzyodlhvuygappicodtzqcrg')
+;
+insert into t2(a,b) values ('rseplqvzgufrkaxfbnmsoslmfhivdzijkhpnzfyqkjuvdtmljzlwdpfjuhaziceqknryxkoxxdoiwsokcnhdlya','eqfynxgzilkwsoecl')
+;
+insert into t2(a,b) values ('srrxfzaewgtiovqcbqxgkcqinbbunymeltqlplypgazqtuquoxsxhadmqlhpcyenixotvhzhhiqairrquelwuweulhmneqyrxnycdbtlwreqptogjryceuqijttljbjiyblmqkqirtuuhowlegzylaremfkvfmcaj','kjrbafhlsvznxnbdwmnrsumaczifbyzxjgxgbqipobqqoouwlxolktonwgoosqxjjleknlxxrbldbhkqtjwqjeomcrwdfzziqqgnmvcivqyslbmwqfpmssvumonyqgwcnafcxcmwmobmpovfuuejaqrwubiiyciaxvmsuzsexdrkreymtgpfk')
+;
+insert into t2(a,b) values ('eztkcjrmqvzysldyskgpiypsvlmjwz','hqyepdmqxrebhelwtosqakvaduworhcmhicqdfgvlxdyolkwkdgxrmtmuncozoxffwnmukjgvehfxzguwphtqiyuopxhhortyaattoheompitykugdkazadyfweosbpkkckcficbvbihsbyeeexlgtxpikkagqzmbrmkyytufhyjscmqzqoypwnbvqmdtfjfageickjndiyyxdpqlmgkihgflbhrbyuuxtwvonvzdjtctxxboncaoyrl')
+;
+insert into t2(a,b) values ('mmkkyazezkiofnlqrdfvuwditihtxckwsldoptzsrkvirndhvtwemrjrjlplkveoetitwocbitkchexmcfkiitckapptsobhbrcduwkdquohzcpchufaar','sggospaaliwcxnxdkzkzmacztxtmpmcxelcwgpserbegybxpkenqewipishiszhtjgocmidbbloavyfcoczxcsaodorwjfiegtywjrmnyekwthobftjqibukigzpwfpdmqsyjhmmpzvcpmfrmtnughlpkejzantlqmixcl')
+;
+insert into t2(a,b) values ('fgymxundlimygstxcgljgquzrmzgrjfolkzixazqxxaeejmntmeyrmszpifrjsmpbkjmmxrgwhqvdgmyklsrxgmwstknzstnzmfbplcclolhkobhzlfxaqalyngebdxzicaecprdkydhmvkfmzzlhnrgsbjrjpazwxuhabzusexdsiajrhgprqlgsklebbrujgtkiqmaczzntujpg','adwrwkpkvaklvvczduighqhulmnlstbcqpzufchvytqqvksgdcmpgjhcidkxlbgciqnaiotsoihmrsgjcfwsqviwbbjfdbdbiptwciaqpibhdmbvimcudwjvwbmzxtixqebghqcpmjvyakdqmgekvqjzqiilsbaoklrflybnznjccyqxbabphaigxhgjpjyflhcq')
+;
+insert into t2(a,b) values ('omfamrpyquioaoujbyjiqozywjdhrrbhxpxgydlvbrmwxbtjnllybvllegrqpwpszyjhmoeljfqkvoztkufpuoflxkiaoppcrefdayumncjkkjxlxtxtmvpozascoyehkkcoryydbcxmwmyhmvdblqonuaworalirxarbxsqoglxgtasxaobtprryftmastsucbjyvtktlzehimfqbutwosgtfwzvqflqydqxiriyaszekummulaljjffbsl','psuumlqpssgxuroiyxrgeobqoeytjmsqjbulbpowwpxjtrgdwpypeczrqctzmtzixpibhhjiebcayfxrylpyfgbwbltcwbqohtsqcrsuehmcitcrgfofcfielloqsyyhtthihaiqfvoxrpyusdmykrtubshgjsxavjvxquujzsgwgaxiysnfiqtfllbusntewgjbde')
+;
+insert into t2(a,b) values ('aqvogcwwktwqyhreacmaiylkknjctmsmwsnohjrbejsrsaifwhlqigkfrvsjimmnbqmjqwnfmcdrfnuyfzyhzlqmjvkdkzayvvpamneojgxxcwgewgxurdjpfggmytfrbrlmapjlnsuuvtzo','bekwhfgjwrqeqxnuzvipehvdazrwrfbjdeuhmywimlrtonkarsazsfvocen')
+;
+insert into t2(a,b) values ('pwybfdysjmhlzghzvsactcznnnuhwmhkgxshsgqcssqzjnmhawdcxoolhdvjpmterjhrhcicmcnhdvnwixsaxymkqgyvsnmvzuilnemafcntsywfippxuusqbrzmymaafiepwhevswjtpsgnfmvfmluhrxbbshwkpnbyhcqwrbxmehzqyqoiusmjnmbuyphvkcfqmalijnao','fbrjcotkqvqaqdokeuxbwxdgkowuiqazmuvxaeeahqrilirouahaqkvfxiyusckbwrsgvsdjebwvvnzxpjuxbxigitxjdayyrkvzrzadqotaypmpupfpd')
+;
+insert into t2(a,b) values ('tjbzhsumnrczdjbqeexoobbwkhbsvspbtnfpjgumpqdehmprsucrhjmdcazxfatrhvmgymhnlstocaxrrgsefmqshtjwpedevvtraucxjdbahwikatkidculwguqitcikewcgywrsxvqajyigdejlaudlpjwkrltcagwttodxzotbtkpywqmkfjshniymupyjvlzpgppkvrkxjyusclptmneutntplnzysyzbem','')
+;
+insert into t2(a,b) values ('hnsuvrjmebhrahsfokhhfwfrifhaxsnmnmtzutuquzauxjobyuwwctzrcdipbe','hoqbeuhiyohyzummtgrqqwfbvevykfjicklgpgjcvwqdrbdckfwwkqzbwehdlybbookacvztocuvjcmdaaamf')
+;
+insert into t2(a,b) values ('jkrlyqpcwbugttkdaeaogmujswxizwqgdqeojzdmhjrvzhcefbooqpmhvxvdvnctqdkxfnizknvwduoqlrhrfgnbhvjnlfpprzzvrdlijbcaesghcbtkkteewntcawmmjtswfssxzeptcfwyxkdzsdubueughafcchsynuugtcuyftqzslirkkwnfrroulggarvfeofez','ilobvfoqifugwqsfuecuiweyjetagllrsqnfxjxqhrpepnxbbvkxvetdeeumnmanjkxffqgjwpctwpvtvbiusvhuyassjosflabrvsq')
+;
+insert into t2(a,b) values ('azzyveoeefkzbvzeeryewufktsvnsvbneweufzwvqktwmtzzttqbhmkszywynhedjujrjozcsbefuhwmgmxzyhlibxmutcdsbmggipuwescwtchvbtvtshxmnxmqyaehfkcowfzsugmkrqserxsnhgeqosmmgrxhkzkzcqgsgwzcxerjkoofu','uggsexsxrxmzmzihnztcjvmymjajgvhczctaryowtcbbipkfefoxeppqegfviiuwwtdomxulrlnusurhsppbxtwnbohqeliysldtj')
+;
+insert into t2(a,b) values ('sjeurygnhqwcshvfqpklgmfkjaucmqotxgmwybfbytontlpiulqldcwgcbwhacelxbqppldzehzbrp','kflvwuxadxvuvmsixyyfwwjhquudutpbdafjuybtmwxwzvtkoziqxxqnwfcgqzddieqltugoorgcitzwtraivcrrebbiekzqivduomtttmkrmrmmzijxnswizgyrlxxqbhbmyuatgzycsmlcimfhssquyie')
+;
+insert into t2(a,b) values ('sufamjkocnkluubosrwtqkbituaqzxctlipokfyzywonsyvdmftuovshbdnkkhszyynmnwbzlttkgjwnfkzjutjizvwbsovtdwtkzhuruwwxnvgejbrlobpmaywreupplycygpolvflivnbpkyfcyemitlirktnmqmjsyouabyxxkvvmvrpievojxcokhpcdhkhejlanaezimcztppohpvmucrsphqucmtlpehsfvxktmtzsnolqloxr','qwgcprqjwyalqwburduzjclosthrkzsphtovfoqlgaktxfueffaxnhfoxqmqeihoyatjbalbctmztvnpkqyzxggwvfbyubyxjmeybxvvvgbtcymrjzhvbpdboiozxccrtlcicckgifibpjtaocwgczcejoroqayqzdsjonirpvqbrqc')
+;
+insert into t2(a,b) values ('hcencuhbysdkqrwnfilovotptrxxiebwanndtgetbjouxsdzftliylyxcpevfyffpasjendpbzukuvykolpiycuifkcnqornptfaplkdrnhqzzpsdviljrcnefbhjmorjvjfudjipofxuqbqjyqzfrisrpjflzpbdgmerdpaspvxutvvqncanrxnmstxyfgkknjqdjwonbbkfycxrxoh','aewowdbdonozshlhlpsimxhjdjpeveiahlsgjneulgqslqmennxdxrjyuvtxfkekigvmmpaob')
+;
+insert into t2(a,b) values ('tksiduwbwoaotzmgmxfuvszfxsvrvywwgoryeyfislexknubejxwchhifbkdixofqrbxbxvrbhdtaxkqsbcuxqgr','ykaxtpixaueeekmuzsgqtnwvgnbojtxgeniayhygddgvbtwohcrqnqljlfvmhoppnciadhoeumefpbushrjwoizlsmkhydmvmgmievwnsjudlfpatwnpytigzmuggz')
+;
+insert into t2(a,b) values ('pvyeodjymqer','rprzvzucyzheyexigo')
+;
+insert into t2(a,b) values ('tlzgtkizrfkfdawufltverwgtlop','wlymlhtwurxgrpdtqribadgyccbbxgwuoryrphmtpnjorzgilhdzrjcntwvpfbvngqvrqgigrkypeggagzqdeqoxorlgjhwsjambilguqgqkwqtzfgycrhafujfpjwyppkwwybxayznof')
+;
+insert into t2(a,b) values ('apuvkgarhuxgpcqxdudlzyynvironpgryzdvkpkupgdzabgmkktrdxxrwrxehkoaedgrqaxrgzkkpycpnlkwussgumwfwwttdbbimblyrdpkkdtfrmhatmppgtomwucbpomxlnmfnjmyrbpwvpjwevsptqradkouqyxlqmoxoiiskvgmlaosvttgcsvlxpgiunafiqledoaeydacuckhslljgnyisodldfpekwwbfhqs','votvmbjzqjqnykjkdnxifhapdpiuainvbywqiomlmdxrstprcsrczynxcinmnfxe')
+;
+insert into t2(a,b) values ('scvsvavpsmirheegzzdajtcwhqcpkssicvsyoyyxjnwefihgpnhssplseaibdzlpbdcaphmrdervckwpchmxlxjxdrnwodrugbwlvpfpaoecnmtkrqkjsoqoobwuskktjhmcfwvemkjgxduueptrkfynjpchjbljlemfrealdziqdxieazzkqookimdrugyntzwdwhhjmabqaxzbyaomrojqrzxcsrxnfb','lcqfeszsajuulnyhjxzzkihielitogjmxgxoofatrhmzuulxzqzkcaefyfdhebhutgydmlaqgazjjumflxahplsjeahbryhfkmnrhfhviazrwsohikljmbvvacsgnvglzdlzqobcuvnqfkxopqwztrjmzgbbygiiujpsphljzxywcqjtkhmljyadjcngeuaczufpxygitrqpbwzojjvjocbtzbanrvihncfdaqnxwzbttgcircrdvnbqmkgakb')
+;
+insert into t2(a,b) values ('fjyjuxrncuwekwvcegkxndlgmzppzvossuvatoqjamsgllvevovukxhkjdllcxjcjpozijjezfpfyzrqktgllusnrqnlqucdtjjcwstqkorcjohamvjnlayqdjhnymvnexmnbpagyftllr','zogdubzlvauicgaropqezbdbcllywmyplldewxcbbgyfjwbqopavpkimkpgiqhhaxoxvlogqlxahyntbzfrojostskqcuohabggjhspvkzfkdpptbcrzezzzjevmdvffovelpqcobdjrotttvzyoositimzcgegx')
+;
+insert into t2(a,b) values ('cwrpsnjwrqznyhslleccvgdpgskdsfhfiifrdayqnvvvrvtonenqsxkieqmrfntnddrbpjqvfooskycvqtojjiewqpnmlhwtpxgjplbaaxeedjtxrpdtodbgcdzlhknenqhsbljglbdecslflv','ynlhwnhlrepkvrutlbjzbhbjwvcvijgvdqfkgrovgdozjftwmmadgferagwalamknwgwnotqhmqusqscgxkbzyxocnhxgwcrntubbaokuhkprvgsqmatskmmswhgharegykvqmrycbjpa')
+;
+insert into t2(a,b) values ('yfrbttiaineggabqlbxdcimbaeippvhspjffpuicwaqbxhkgnowrxurlsvwr','ycidxzfphycfpoijtfxgyhxhtwbbpsdziojwsdotelugilfdekfwldnxixszlgmqgopzhvmlmxbypndxxqgkltgmndgolpzyzqmdgbukzrjmtookyaxlpopyiaztnyndfzahkhifwakotdabfmteavpysjisoduiouzpaevevndqsnhtmfqfvagkabxgcwcelpwlrjssabajqm')
+;
+insert into t2(a,b) values ('hdaihfpnjsgoyzdwqbccpyxrmghggqgzkwupddayxxmkjjdadgtt','kpyizcimldfibgnmilobiyayyalmjsccapmngkpawhbyjpsfglttgrbdscukykfnizgrocsbtfqxpygppiegcrippsxltagyslasiucazehiobhxrvejywvpgjcegwuizihuecjgvibvyysjuxayfqcfamtecyqvycfcmqcrjicyygkhhbepshxeoggwqacbaihrsqqtukuaagfmrqhfvvljachifjjovqezjctudxfolynxybyc')
+;
+insert into t2(a,b) values ('pgfnshmnsuugblmpatuhhyyrsoeinsdihnqxsqjtxvdyttvytpfahcarxayzgecttkyedskfqzedpmirhgbvzksnxqqxadclgngveelhukklpacqgsxuwxqwojhuqirxyrtiwwkrbhbgyonwtdzwkgldatkzdighxirzupafgrizvxasxeysexufbxoyvebpjkcxvebrhmgytoyewpvbhlxbsfdljdkakurvxisjoumqzdbeprzvxmt','fhledoqvkwvzamefhjpuyczuqvodhzdrgdweewrcyrspkbfvmjw')
+;
+insert into t2(a,b) values ('oaatlgnqpbbskhqiwxryydumjckyproskgvrgyzjimodslwqqfjupjswhwmpofhqesqqmtbazvwcywirqdzutjsjvndnncrsgiskbchtgipayncljzdhtlmnlhiwtrbkkomecvsgutikvbdpqrgeqbliknadkpncecjtqthhzsyqssxtqzhrxadsckzfafdhbwiakuusxlcwldal','oaweyvektylaaymjjgknmrisporagjtzsltzyaredyngyebmuqlidgohajzqerlrztcidukqexanbeqwwbdtyrksmlgmlgzowwwiwiizggyuqpbnicozfnzejwejnoeoaypnowpdrmlxqchxpxtvuchjxvheaskguybangkdlndlzwxtfywlljojusjvavioffogknhz')
+;
+insert into t2(a,b) values ('qtqyrisjealdbhhicxl','giktiiqzyxwrilatqcxfexdublkesmibgcxtqsnxzbocauglsomlnjgxdsknpmgdmsujpuqhulwtccsraisruvfsfuvoawrgnuwshvpwbjnohwwtmpuwryuzgufumoyzqdsksankisdwvvkddffvcbtpnaatfs')
+;
+insert into t2(a,b) values ('clvryzoobbvgqujeseldrfrvolholaxpbrnsiduxagqhtklhnaafdqhpulljwqjvvlsmvduwhzxytirnvcgrwsxhqrvgjisvzzhbjqspekjjhvzgnwefguzsoikqufirvfrhyxeonxijvctiggckwixkien','pnjzqwrdvgkxorefhdwqwlvieadtspchyqfvuxhyyyrcpiftubcnlaxfyautcrpqtxhlupwgwhicitlhfstkgwzcjabighvwqpvrlquhwxitsyqfpyghqqfzjzjbksmwrrilrspiidjohbfqlenbhlrvncukknomjrlscodsqkcifwkdatlqbgc')
+;
+insert into t2(a,b) values ('ijuagljrqaludiyashkmsymkpourqkzyuoklgtjzzedlpckotogyygzpvuqkznlitijnjvpnsobigujubmummqqsgeilaomktnqwazacpedazpqbjfiqbvtuqensmtjdpvqguvnlhvfgxyapfwgwzlnwmkbekarhplkaxquxaspwdhjwgprzxchoumeupypiqmutudemwhkrnmkpbenrorvmklbcomkvhyyxdjqdzochgmmakou','yfqjbddtyxjillitzkmyufljwdggxvbjhhjqoyrfwudzjuqnqtxeovveldl')
+;
+insert into t2(a,b) values ('xzrzgudurpwrhojxjjhhhwtrunuozlkcrgmqlymtxvxaikonxrmdcwczegdwdacdtqmkztsjdezfbeltnnurgzdgtgkqjunlufxdcflyoyoydxjzvyhrngdvnzvqelpfbwgyttwltrjrvlkuzfejcoofwzdaxjspcqqmhmsujkyemqgkvjmejndnzeqsagbwhnsjlsffghplvtglpcwqftlierweqithnjgnqoltlxmimfkiwn','iyatnfmgcrabjdtrmvgzxtewqcjvrtclrspobphjvxefcjxuddbrtvsirmfvyctceghfxjbkqkkpdirkplmfvnmibseeoaraajzoplbftbojiarzsgmwnqirzbkmjbudmrhyknhdxuyblcmindlcmeyblifutjartgnciijzrruuzmxmxhvoemtnuzouboerdpxmikbedtrcegsbmjolifbwpa')
+;
+insert into t2(a,b) values ('ffazmguuwcymhyjosqoqcyyccpjxmivtwfpfnwcztjmqdokjwo','pbxehsnljqxuytexbuhscrypiktxxakggodggbssfbzfauybvccouzvgagllwrxzjtlbrrptsmfviyfmkisdbrehskjauvghglscrcggzkacgcdackvomersek')
+;
+insert into t2(a,b) values ('hbuljbuwyusbzdpillwkkwx','aamzqkwhqryyjgwschizfiiltzvorlychkwyqmavkxmlehrxbkocapibiiniinxtzjxeickxijf')
+;
+insert into t2(a,b) values ('cmrvcheleyusalacamqnpdboshckpooeaqiexoranqimdivgabronjjjlnrsgekfcfjmiuyyezxuoifccgtxddvccyfsosobwldfvoqcyyruqsbyjqarvmlqisadzjlxgrqjppznwfzjtncxmrabilgtpnlodbdntesmorufhxslailipaxlxrqxxwpxghzgqwwtxdanidwgrymbsdxxcjodpdqurhkpehkt','zroavmqrmaebjnhoujqimmxkqltixnfpuhppeybvvvcfjgipmzsiusyiqgfqnyhxewiuxvodatznrsgfchuqxvncxmbmxxyfmfuipcohrnstkuzhsitfydexersekngtwrexcanjrdyqaxshoycxyjhsjmbszfllywpizypddiitoygznggfwrhhcfnakwxuddvdjhfcgjsexnabfqawanemuznvufwo')
+;
+insert into t2(a,b) values ('tkqykvizclybrisnfizbkazdsbduqwrbxflvfmhhzdn','qwuixloeuzqtvyzevcpkedmknerlzhunwmjrggwmziwbltuoevgwnxtspusmcbqdqbzbwtsrgwnwsldultpgupzaydzaprksukicxjuwurtydxhqhslrropyegsrqdinscttwgnkj')
+;
+insert into t2(a,b) values ('bzqmavtqrozxbbdldrafztpeubcfwdpaajxnwmzmijmejletpltbfmbvkztaihzasplbaqeurfpmutkvitfeluipwvyqszhmtekadnlunawpqnvxqp','mlvzdpmqcbnxmxraiifawocuoemugwlwrzmkxjeonietcynpioirijhjuukltjzrlzrhdzcleunzlnndzopvsmhc')
+;
+insert into t2(a,b) values ('ztuukouctxzmdvfvvqgnyxczlndqqhkubbcvjzulxquwwpzssxjapjtitrhntnjgjfxzdijefieohipjqvyabzosuekbsxgjbjsgaynhfvxqtxodekyzwpdvwxvs','ovkzkslrzndqajwfgmqytxnwcwwlocscctdaocsuilcctigvfneaajekzsjidddqvnophdzxxmjefaudb')
+;
+insert into t2(a,b) values ('yqsuwyrxekkielkcugsnlqjjjahfnfdrspqgujrozljnamkcdmfcgdoofrapwbywdxvjnmwqjacvaidnkfdtdaz','oaaxqekxbqyqsmbuwfactxhfjqtvmfdvfubjjcdpixblozsvtrlcozrrvhypncfkrvkkpyfgurvdkezdbblbvtloggzhnccvpdedxtazoglnxreavturyykhjgtlewtzxsjmovpjkxhdcjntffovvrjydxbfvhqrifeshhrtgagxbfuoirqcaiaabvpjonoyzwxdvkbwkyedltjbngpoysdnqfjtobqbsfcgamt')
+;
+insert into t2(a,b) values ('sfmbnpebmqmwlmzaguzlfdwbsglivmivjncpxbyvstezmhsrwurikcofmpvlkertwtopsvkifylbfwgeoxxxxowmcowmoxcflglplhnqjrlvjvscystqdneqyiywphqbohzjdajlevutfwggkgzwnzruydqpurqva','prfpvsciaokspojrdtmaebytwlbybjeurbdolxdkjgvoizkwcgbbuztjiapmufyuvmzffmz')
+;
+insert into t2(a,b) values ('amwdrsbnjzixrgrdzbrgylgmcwehntbjpqpprtpcwwplhnauezfesuldofzwcmqimxjqqxsmmnndxutyjowspdesrwuhzknmmtrjxlajbtxntfrvmerouozrxnmyfunelktraogymwosvlehidropcsidkmsqcqkzwqbcqpyobfujvuzkjefflfx','cjztigeovgnogbsxyzbdxxgipysnsiiuaeorezkhgkmdkkbxmhmnupzydrezcgwvgdwqjizwhbwsooozuxinerebijhmxmvghsufqocfbouxwkhjtoineerkcthwpkgqvuutbxckxthntqbpwngskalqriziteausfcmwwhyxktwxaivftgcqal')
+;
+insert into t2(a,b) values ('isgvsellpbkddywawjnjfkmmmewapbnofncdtkzlcxopzmwrbgjxvkehbgbogxhwpmbcbhdqxbwgdiraaoeeu','jmiigpyjovginwlenxgbusizbblpenyerotpxxmpbjjzauqhcpwhgykvfkgihsznfmkkstaralglxzbvsxakduygpogoqdstxxftuxvhyawcgginujdmaqauazikrewsuccodwuhjdbvwerimsdzsrtfmcyrvquedbttrqwabacrhlnbbnufdbtxanlfmtys')
+;
+insert into t2(a,b) values ('xfgrjnnltxxslwnbbiznfwvyfcpsvsxbdkpgtofaupmfnwcxvrhxatviaeumocwpflgkcbjrqznrxhypbvhgercddkjekfockfxzhjduvccwbhlsyyqk','zwczcktqihhkfegeludussaciikvovwvdtqzblayskeqoifnsvmjmemmtksjwdqcuvuusupkezmfecllnyfeibbshydvxiohnfvqyhzisyfnhceroycdiltcreeroaarkrfsoathyedqmylkoblxnbbrppdlksxbzdeanalubljgkefdfrpiobipiulzpzkmogfplogsrwfprlikffkvdscswnfuoosubkubjovw')
+;
+insert into t2(a,b) values ('mretmdcsoxnkztbdkmbvarcaukknxryhtzgwwvvhsqmqvixprqlfxexoxihutwkqdjywlgancdbqtbgnuvfnmvdnjjaclfdrlkfkcvsdkjtsqtxcnhefxnkahhpltnyfsbbbiiqozhccscnzpoxz','je')
+;
+insert into t2(a,b) values ('ayierhfmxnkxrhlureilvaunziicqeagjlaepkwdwjzwgussmxlgychmxrebflaltxgyeolzqkximbsjsevaaomdjbexcuesfppmkyfgfvjlsuvswcicqohenwnugjunawvtafurrhlcnkwfibphjjcsincjrpmoevryobmoqxqswagkwazryfuxivl','fxogtwhakkwderpblxqljiliuefphyskzitykbphaucpprmsvfblsnsippnqdfzkvjpdoixoejqzyhpghfzdrwciucncmmdggmpyhkduvuponukqgthpcwsacmfiyhvscnrgmqvevpekphstxvkvyajnmfuxfvttivdyphjufinpccchdmuufllwzvvchjhawifczvbbwxktiuwpnyjmaemyzqudgjgwzavxwvzax')
+;
+insert into t2(a,b) values ('hihjexjxatftovvkpeoffadxnaxhukwztvtefhunpzfrxixdlccxpepyapypoovrlzryiwwhstblaiynkumjhecutsfitkzilrofajyryejyhscrsslntqcyqrvlblkwgqjfnaocorwqkmtnrlymggfzfjsewjzrlmhbhdkielphfyjyhivpdbfqgpzvjwcteadbhbswkanzhuwsilvmkd','ncxcpowjuyrujpnqzmnvcdmxgynffzrajsjevuhkjcupevwdshtybtnwcplornywuvfefzobbsanwhvnwnhswaphcaowaraqxghjrxkzqjarsldvxivfxfwbsdkronlicujvtdsaqsvmhfnfiawblybxgholbdurlxoeukgvuybabhtobupokpwrvypfqtddchsrkcihtmdtnzqsgiapaanjpdpuvksmex')
+;
+insert into t2(a,b) values ('dibxthdxtspojjeaqomsuutautbbmdvgpfuslginmimffobkbxsllmxtxfssbvyjkhnejizo','ctwkfmhzjompmenuzjnggxxlmbkvkdcwaaidquxsxermxqeyxlnadjqmyryxgqohjxdafoyxjsskagkfbquxpbteeysiizhmrmyfyurkrazhjkulgmxqfhbspg')
+;
+insert into t2(a,b) values ('arazfabsomnztllwgxrafdyvomkpwsqwvyxaibofxwjhfcvujlcuyniflyumfqpmkhqmmpuaxwsmcoddgncxjoszjauclodmgjfafdeeibzijroubevvrkhzzhgfuctstxyyppghfgelmhiuszftchyjdvddnkfduknzkwdvfcqvpwxfyqwtfghuaoplevenaseetoee','wraztvcywgueqlxqotyajxzlrwmfbqbxzsazfaaxopobuutchyjgrykgeoiamtjeddiiesipbqsxuqehjqortoyylfqxymxypsgldizatuq')
+;
+insert into t2(a,b) values ('cswvwmwykyrkldmwyomqhckrusnyweqeqdquumpzzabhgqcoruiftqhzhkyrtglhqhbfyljcgsfvtdnldkqpwfcslmefcuealnhn','fgxausjlglhldbpilbvoepuitklqsxmdkmrrbwzkexzxytmyuxdqkstlrgmqkwugtmpuvpyxjvlnuuqceukomokziwzhvbzlmdivqixrdhmshmitokcngoo')
+;
+insert into t2(a,b) values ('wxlixordiwczy','jwsyqryjvlrbbjsmqbkbztlbkamveuctwmdqnwojlbtpxfixrxiktpjbzigxvhruozibyflhgjemu')
+;
+insert into t2(a,b) values ('ektmfdvjjycoxyxbtqeumzqkfdjdcrzbyxkkkuiiubijjcbzqhukxkviomeviszxnskmkipyogamvyukqficqoeayvugbshgrgfbqvmejsahkuhxfukeyvknbbqtnszv','xltdddrgshpwwpdlocxabmyiuqmvnnevygrwvebggcxckvljwdykvjjqvrlfiexbdrvsddqqmvwkdlfskewcrtnzlrlsliiastyylwvumamworbnpwac')
+;
+insert into t2(a,b) values ('vohyraxrvvfqmoiggjfvqvpgrcrevwgshniigsnugmhplgwsbenqynqrknfpebvictundnfyhftsjbspqnarwnppcivgyiooxodqygsbruckhmisggqtukicetjjvohrljqztgruphoufntpfrnzqakdjwoipesqvnrgidkzzbbdvpctyjqemourylzkixhpkgxftpinmuzrfqxdzotomiuu','xnuhauwhlaxsorvoqhkigumcakfcgvzssvovxxolspbikyhvxncfnyuveaaihqdcpmqcljswgoucecekdzenhdbnnedbxaumgoexqfhnztcruyymqjgcscrelmagzeqgrluqseadhdezgrjudthjgbdadfelarfqstwejfrokvfkunyel')
+;
+insert into t2(a,b) values ('itijrrssvsvuhtkflxmcurqukoinkjsirhpfwjrlkpiqzkcjzfvyzcnbhpejmnfriquajeviykrmauznjqhkgqtmdufvnwotigwafekkqbeofhhklykdmajulxzmexmuhcoemzvckiqxauulhzhhxqehjfosv','buchrftyyqgseovmpktfkcfhisbwnoofoxmvycunyebujnyfduwlsnruajvcfpjnidknxcocnieogcglrkmpmwgazavawnkxlgycupan')
+;
+insert into t2(a,b) values ('uikmwkllapglpyrzxjyqwlajtlfbryzrzwmojgnejcfsol','oxvxbathmjinzsygpoxglthkkswmdnhjvibznsutlxqrmbjyplkhymclsuluwbciabvealjpftfzfylgmlsxewytwujkrliwepznrzoylfnjnyndrdvyrewgtwuiunohuofoi')
+;
+insert into t2(a,b) values ('bomxjrhsxhetzyomrcfjjdiqysxqbrpsrdssqxwdybzyjcnqgmzadbtzvhnsqhwovhafixcxcimgxhfqhexadollqilzgpoxcdlkbfscikiybkwsflvbxcemqybxpbppoi','pwcispaxdhfbqizlnhkacuzwvqbkhvpkqospabiotpcyzlorwxyjjdqqsctctzwlgcdhinbdgxvsnxddbvhifutwnrtyzgojebtgrcarpzfywwmookvdmlblchjcjotssskvqyitldherjpdpxazlmdcjxbhuqrzapzjcvfcgkxtngaxyctifpzavfapuqtepwiiqqxspprjqmvpclfnvuooemyyvokgxgnzjuskmal')
+;
+insert into t2(a,b) values ('nkgzqpvpemwyihsqwbvnjzdjsbgffjpetzvgvptotwylyutlgjqneqkadkrcutpgufaxhcykpnaxmalhgxdvsriaejjbzvkilswdgbuehpbwj','oknytdjmwmihgnowecifoxitiejgjnovwuiskvinftyeahomoycbifcbpmkhkfhkynvslhplvaqliddvyticftouqdifvwtsbbmwdlonqoyxzqinqoqoooudbodcwuraajumjzkinbqiaanloxwjiwqgnacoenuvsnnukeaqzvvcg')
+;
+insert into t2(a,b) values ('tspaclaaxzlwcoaemmisjmyjtbxtkmrzqjtfkkblvvorqlqbzkfmuwecvjicxvdaxbvuerdrijxjkurwltqlyrmaeekflcsihewiewracpkyivbdyyypzpzqmmxwjwsxwjcqkoramyosvojrdypiueobrfxboyiqbhbckjpcmjusddydayuctjmlaouipelkkdinmcifvtobbxvqe','lertetncgiduugidlnpdsuibymzhyjwchqvsyaujtvfzwayiakyjkwjaexuqgaoybxadlgmkfuyvruemzecbxgevmbmiapkcvsagfrcqduyjtsuelelajqeqkkfnmkuxgitqmvnufqnnjxbfccrszmndfrxpeoratzpfdikxwfcsjscbsjmdzsugftlxxsdtozwyduertmpchnsoyxlmjovkuphnnwjlixzdpdjeikxxvjuvcqefwukqap')
+;
+insert into t2(a,b) values ('wnqcvoo','wcwqjaqvkdndabqnjumfcrr')
+;
+insert into t2(a,b) values ('fljdirrfjclstqabkhcxnxhsuqpyxlwjwtlhgynsknoxbyomptzazrqhjzjlrlmqpsezbudoptyefpwfrgdvpcxcomuksobahssvyiblnglavjfmiuxavraobxebflaknfqhkqxalurn','kvbamztseudjukbfzt')
+;
+insert into t2(a,b) values ('hszrnyafhokdpmiayrbaxldrwlnunwxnluzryd','qjnoyrmdmbqtryhnsvqqbqaplldfhdullmalmmqofpwytqvrnqubzsobypdaqjipuekmxbcqpiwcsbloztpizwfmzdpkvvrxgdyxwlgyjxnexyplkwkhozxkcfladmcbrbxymuluoiwpzkhfcfyrrkrdswoomccffefvijztrmbuskpkjwbdhtvwlivqyhuekofwwjvxxhphjwwerhumlwkwvrwhgygiowwfmheufjtgxbcxhkj')
+;
+insert into t2(a,b) values ('ohgcwfjjggvbfrloqaphgayzpzsevhpsvixoljntnybgrgfmgosfonwqhibdclfxfagvydujskfxwapdaydbtekfxxoquspzvidhbmygqegmyyvugbtluphtcnghcwypkjqzyrttg','egniyowhtojtnrplbicuoxbtztcaeqlvdqdzjabzlndnnwmqtmykisfytqlyntbsqajgimvsrqizdydcrqrxiwkgoozed')
+;
+insert into t2(a,b) values ('nygkrmvvlnbhdnsfulomlnbzqcjcchtptdywpqmmzzleaqqsproieekistympdkftonactiijjiobavatghamwzqrubcfgnoqfrqphqioedlxizdiqwostscmwx','fjshhgxtykqbbzuizeklgleadlyaejvqjhsfhswiaeajoymhgbouqrylacnfoisxdpu')
+;
+insert into t2(a,b) values ('eiwsfylcgsgnetlmzwykohaoehotiyxjmuojdpelldtbxwkfsvpws','czuwpuhdxpcwutelcptkovysxqtqmlaayeguybspcovhkxqjcazcjsntafbreiheiejmswsshzpyzmxdvszmjeppqudxsuybtqsrthdflezrrfcylzyrabxhqomoamkyckjlnnquhrxesuhwrosppfahjqkdqecbernofqjinzbvcmlhwjrlcnfsfntwdnhfdpixarnjjbjjithzdonmfclnhcpvqhn')
+;
+insert into t2(a,b) values ('anablguufuhfjacrzjfmxwyrpypusadagtugfgtbnansodsbknljdxuudcuvjjlqljivfdutkkcpjtvnqhfkymfrgwalydqfznjanqnkskacbsiseshxaydchenvdholzponifwcuxncbjjktdujizgklsaubjshvhjqmemiucedrygyxelsgdlhvnihslxbftlpnwvodtgoijxstzfbuzzxnwzvjanubsbfxjflo','bernremfsvadlvysjoctklqywbokncgmyarxsbndbpkmwbinpatfozykprdmispskzmvdvjfpczznyazhdtlxbclnvajdorrglaxmpzvwrinpcmdkxfuoybpvwyqttrogsxgjmaohwddfafehtjdyrhswqrejuxdxnitxjpfznqolhtpxrfafejqkpyvrjngcwelqboozmeiez')
+;
+insert into t2(a,b) values ('abzihkmtvtmxbdd','fothwhftrknulmlfgdwehxclaqjlvnmzqhmjsutugsbpynhvrtmpkkqrhhzineitwuvrbwvscpxslxgokdugvhtevyjrpdedugvarjxnammkidmowrdzmzuebvnxxohjhhbzqdcftjwnrsdlldbxqszmxtwgmofrqdafvlukfyvwzgrxwrtyligmwttoptlxufhiufzde')
+;
+insert into t2(a,b) values ('hkmfhkqsvqumwfcihhfzchezzwixozqwxbdmfzunypuzlsztppwvqzqhswtliydmixvtdylnohlfdtgfntjbpcdspxwxhtxwqnravfnuduyfkcnqpvpbkzbrgngawlzc','ibyohevqjygtmtnokqpvvkbdzzaswhpzqroypturytkhwamjedhblqilzmilnbfjcptxiousxhuvajgrsxgsifqbxuwwcunozptbvatwxjfwoggbdfyp')
+;
+insert into t2(a,b) values ('xeqgbxbwtwlifqnznawqwbadoetzbbfczbdxtnjgelrubsluumvgstjrurjyplndzinzukmvxjkapjjpyjaaxhpfbqedgo','pwqfzgqspeuvemvtgzkiftcucewenfrrtftuvoepqfhiirxaarbneejodhuctpjghbivzqcjb')
+;
+insert into t2(a,b) values ('royslmhrmqkchnjqwivrrxijpjdkxjoyzhmsmfvchimyuzffqcmzwlnorntijtlfptkdqghfteernkamngzgswwiwwrmiieyvujmrjqasfrosuitwinjyfmhmctxcmnlwjxrvkerjqswnhcbunxhextaqkebheojzjvmlqvqdtpkszosigptqqbmvlpxzqwqzucqvvrkkwfxlvodgqmpu','ylpngulycxgujirmcgmajwnqfgqclqhktcjaafnocvtwhixwzllpxsqbtxxqgyxgsvrpocwfealortukwqfaidalrxxiypmuezltqhefasnmrmsfnbkrjddivql')
+;
+insert into t2(a,b) values ('aaewkipxowqttyvdkksipwyopxbaideqqpzgcagohjgiwtz','euxnjnojvjlsjearksplkyuwzjxkfklvlzgpaovytouslmqyxkzaegmvrpibtnvhkjzllfeuxkochtbiramugtapuhvnaxqgxeghlrldlakhdev')
+;
+insert into t2(a,b) values ('arzfqhpewjtbyahebmheapmfmanbnypbwoytynkgizgpiijicbalkljwulgxithkqzwlkewrlwlrtiynsnrrmuihriumjrryscdsyfeikayvzfoxewelwhxdgcexlltxfepeesqkgfgagvcinurahesohipxggqrwqjsltunmwgsdgusmtedxlpzkjxpdksnwgoqifvypqoao','oxyluwcrxwawvpdbcmpcckakhyflsiqriffdjykmhsmfzmlulupdnicpbhdbnngndvqekqxcdgasiboqdvslujfpxzwfzvgxfsdcacvmtsyxfqpmchllthibaslyinxmgslenmnlkdwfpsuerppzoojgcxfeprutegfwiqjbpzdiwyxxahbsmewj')
+;
+insert into t2(a,b) values ('froxiballehpcecguazschosriiygrskigwhyocrcowerehedanathkehlgmtcovcnitttfdjmoqjtgllhseaviecseoqzzcmwiwafluywhadcheifrhihyqofltelkvspemvzdpqtvsatzqoeahdxlnexbnpngwkiiqciaerpwehjpdtcuxegxbpuisskxqqjnysvshnyehjpdvhcpcwoiyt','')
+;
+insert into t2(a,b) values ('tfmhcpfsjhpebdnwwxzmklzvixsgkcxcmabtdvqzhmgk','ojiklqmrhtofzrsruuyqikukfkbixdcwmqpnudxioqecfduxdlecytlrnnyetjpjjblcdrcwda')
+;
+insert into t2(a,b) values ('xwmakbqivuowatscockqbkvgssyruiphzhyaxkwxytjqmspbsimixvboopwacruslydmvmghwogeyccogkygjwxfsxwrztggovrpqzalwrrniwbaqhqdpgbnkcuvjpgnfaorobzjkzdxgtkzpdgqwowtyaspubkjiofypunxofzxqtcfciuwmxaixgdavnoiqeltjtgbkcpmeeqscugaaymuhvqkzpemixtasnxjeckvzngowqd','vvzfxfbjuyjhhumrcjkciatjxhsfiatyqbsbvxuxpwykyecduahwjuidzwbaqczimesvshlebcpjd')
+;
+insert into t2(a,b) values ('sqyuyvuxvurskxthgmenjrmdlmcysbkjndcewughawsyiyrcxmpeyesrgedkeljtyklipepbgahgerldichuoc','wleakhjgqpuwnozdgbdwxujhfsndnbrosprtdxsjeobqvkbrmulfkhludzhwmnznbztenifxpkuwujhaokidfvgdduknonjsvryllitsvhwngacwjrspvploluletanhung')
+;
+insert into t2(a,b) values ('tbsikdbdsgeglzmzelvzpdtfbakqcrrxfjivpysczafxfgsenhjorcegfjblvaudewdkgydjzpukloxnricunpzvvcogiebzkxfbrqvnuwhedxil','pwarznisnxpftqftftvqysaqggkzrmmjoqjvwcauefltkroccgdwafzebizorxrujkihtgosslijssvwvhvousixtzrnhubcxq')
+;
+insert into t2(a,b) values ('lqoefybbhjpllizokygalgvvuex','trruxbyfcfvbeezkmwdxekdelavmnynhmztpycbdkvqfnouuuvngffcdlvouvjvidjqzvcflwye')
+;
+insert into t2(a,b) values ('xdtyonzlj','ivikbpaiozwiuvddrqrfmejvydcrfcizpjuquwsabxzbuuifjozbhlgfizxluurtmwsi')
+;
+insert into t2(a,b) values ('bjtidazvhnoktrufkhfdgumgnxjbqbwgibbdskklbwkfrysetueptoojwnfbpmmomjsajmhtfbeoomfihvfgtmcovgrfozhflvyzlnbgxpnsodizbmnyucztzglpwkjuibteyndsjpkyidyhmuwjincgtqhuvghoaqbfczicekacksxlgsmapzixrrxnrvabhokepyknhujfqw','vjsjivrfgmuafkygcwhhrlmozaiypllscnwcebyekzncypjgstxxrkxgsoimplucojkgcpvgbofbobqpaschphaals')
+;
+insert into t2(a,b) values ('ajagopebaxdvykviqeqtumyclaijxbebkihugnirtruwjgkriaymxtaeiypaqartltjvgelrtasbvmbpxzqatpvenkvzsjebdontmmvhkmsukyohwchfrwmigozrxabbnotlnnfvjibzulcnqihfdxamfmzuudiowdgjssbfzqr','uyzfwxousatyrjjbxixoijxomdvrnqlhcnifzvnxczviwpryzkuoosqanlscoqihpzgcirzomxwfthojetrrzclmzardunpamzoarkzwvcuqaahattdctvbucwmyhdqgujljqcyjojourpkqoupjkieijkiezwkmqgjclsdaelepjufzkxiuqykvsiavfakm')
+;
+insert into t2(a,b) values ('ldrlfxlacfyvzoauhghshxvmlhuzlslvvjqipoyorgztronwhjpcmoetptpnbiyqteebwdelafnvfqtmqxgtyhfivscpbrgwtgzixenhvmoviuoaujoqingzlpzjratfpabokksmqgysscampeerfkghdgtgepaxlgpknnpctasnlbizacrbgraqpwfhchlmfcioxteeczxuor','drtlpqaxwzpnhicqnphkjveryscnjigzyuzreavtbhdafyovmfnvuzwokvgcpefrztgohtseorugvrovpfxzfwduxxboudveykkmukfrepzotgbbcfctnisyo')
+;
+insert into t2(a,b) values ('humbisuxxkzgzzsiesbdwzzqoeloywajbfllrmuhqnrqtccnxkznpfmheacaasmoozadsiiixfjuknzrpuwifjaxaeyaluxxgtdvygslhrtgzbyhynwjexhstrujwiolhdqmjrrecxtqwesuebnuhxblgxhrjozwcnyznydirkxptpimxxcrsngegooimwjeyyjbuwhadbvkddboyy','vwousbzyiscobsexxydwszrayynhzckktpalxgmiefyuwrdfkbkzwgegzcfdmyvaiwnknqecgsekjcfbylsyjowxjxipcnxsxqxkqzvyjibvfkqrbvsogejwmldhkuiqqdftvavdl')
+;
+insert into t2(a,b) values ('qyssqhhrnzgnetmzvtdrpkikextmylkislboqxlzfvisallhpizpnpivmevketxaiisfbforol','zngoobwlbkzzesagjlqcpuqvapudymelxsgl')
+;
+insert into t2(a,b) values ('uzksvpjivyrsetglqafhdgzybrwhaohnpiqotqgrwagqaoiberrifvwjsmoyqaoag','erzd')
+;
+insert into t2(a,b) values ('mvvrlnsjwazwwcndrfvadsyykzcewvwkqzprjegmrlulaconvddbnvzoidhobbnlygwptxbwljzdajrawmolpqopchfdozb','fdesxbiyilaitlegputqdzvtyeufzvliffntwgvmxnhtggnpqesbavmsvrioujbwb')
+;
+insert into t2(a,b) values ('dhvwfkkegrehyivgixndpxrzgofeflnbmgkyqgwsgpkwjzzvpofqhivalwbmoedlgunzvjenebrlaejlvdxxpglobglopfcqmgbjramqcrppaqfnwjlzaolucnnyudkyxunrmmthzdzuqvbolxkxjnencfgusbffxjxcjhquxnclykvpavrjwephnnqycedxazkah','zullhytvscfctzwvtmwkisaaorqglkdpiggeepefmwikwfgzbpgdsvedkqsyvaxnkqdnqbm')
+;
+insert into t2(a,b) values ('ehpqvrrzgdekcsfesgrdxcxtrbbewelhbiqedobaywogahrshdlubsvvxvvrpbrpyvtjpconvbedrulutaeb','dnbwnfszlbrnfzahieaxipqttmbhohhgojkeboqspdznvxikqfgruzrncfumwzghqhgptrylpbb')
+;
+insert into t2(a,b) values ('hmxcthbdowmsqkyoknsmpusgtutnzeshzlexsdrkyzvzplxgsbgmgdadczlmppoavnuwfcehbizkrbpogevvxqnoqsozkakijghkpuvlbbdvlldoysvbkbyxvgonnhvyqhzfnyljdmsiqjczrwjhmkzxxugpurhsldhcbzfiwremitkzadvyfiroveync','tcmbfdwoevenvlvzepmlvlwiafezrdpkcjwvhxrycftjrrqbbqoycqysyztpuaemvupxzgtxojzlwlteuykgndvdzsnnvdwckzgdgasxatqixamszwrezbdaabgsxqgscpnugpstqnropcdvwcnqrtmvgjzrhxxohfxbampcsxjmjefcvfywiiyixkgyozbzfdgqdxlkoyulbwwtqsgladxctpeztlfalwcnvrulootnhbdjijhibh')
+;
+insert into t2(a,b) values ('bddcnjhuaeurdifqizydkfyigsmrqtpybjhzhtettxaktznjbvlmnhowfotzfpvujikwixaryddbcrimntdrgesnwtlrqqfdqhpcihnmiyihpgkjykaflgkrcduzfskcznuvvajasdhzzlvurisoccpvxtuyeawslpaswubfjkqmjaukakhiubhdgfyypfindlodrpvawgkxhvctzogvlvyewvasrxbyytdnwcxxlaqzevusecpnxu','vxbnewrkvjuqwthdxuipkhgubssdfytzgynacxfvhcjjddhrveorqczhuaqfesgyalypjahrgzccysxhkxwictrcuubdrbmnfuurmotduumrkxcmenbyppxqrywyxctmuufdvjtzdhnmulncaqlmaumqlhhgqgrztwwhvjzscmhsictanmvu')
+;
+insert into t2(a,b) values ('tcdfkplysqlgwymeisqgcipatpfkvhflijupavhoaczkfxxkmbbxevumelnflnglosayzkazpjwaudibjfrwudauznmzyrmjeplrgixjkoviyefjjtvquitqpdtjvnlfezuuxpkemmvkpmiyuosqxossuqewqqsqvbcwnhtfzz','ygwkmfhfqyqrbmrsnqiqhxdhbwjwbxxiqazjqyuuduzpzbfiktzxhywqglszmratpboicmjkhywxfwyhnwlaruvntmoigruxzsruelxqfxnwdjeprjhxbdkxmrkpdpkpyydkjhizgeljfrsgequuqjzyfjtyzrcripwgkazkskvxnxyhnjlvjitjuvyvhtnmknvmzrfevnwwydhtoubswvcrdrmvraxymrwnweqgqlg')
+;
+insert into t2(a,b) values ('wvjsqhzcu','amucnhxqgacvanvfbwyuhutsvcbndwqw')
+;
+insert into t2(a,b) values ('mslbcqgsrjoedlfyltubekodtsluxuliplzblvijbbouaijdugyoolgzxelenqqadcmswrcbcstnvrnwyyqwfmgabmujviklxkqtfzqorwbzcdicyayiwpeqadfotnkewnqskxtdiomiosznnzznpnuovycfamqmbieqybkpsurtdtyamyaaisbrtfhqapgbxkfvyufsjcvaovfmhkdnlccelavns','tnjhfvozqtivljmjxietyvwpsqhespkdhvmzelxuzqpgydphphodahytiraxucrmnqzgbjsjbtqqrrqtvewsbjsdlyprqmbmvvtcnvqamtvoeyuilcgnyfxtjgzufalaflvnqfvtzgjmlelmnlosstrxtmiiytcjpfzauqxtejxopolvjetzjusoiaxcspcbrxelqncal')
+;
+insert into t2(a,b) values ('aiubxeednaljwgdxnpenvvpfrsrqovlzgcwubsezkyzxhkhhepmmodvzuvdrlad','dnlzqnjsunnwlbeuejtmxsblejpwoiosdmqecfmuuylqjzbqnnbigciaiyeuhcybcqexmsnzzjtmqw')
+;
+insert into t2(a,b) values ('qvfelnfelhtkxhdnrmmrhyjgyukyelhjnjailllsdaodxbmvmjmipozzj','jkqwzmdoydyjffgewewngmiywuemuyacmumqgxwejnpfxelmezbezbxg')
+;
+insert into t2(a,b) values ('tubrggkljivmgqwujaqqxrxirohnwagyddbyxflcxllwswfnuiygnfopyyrrogkem','nboyidqihqwkfjdbwbbvdhcrzgwghkjjtycwrocpwrdfruzabyrsonyfxkinggoeobzhmjtlabwbowalpfrtfqejhbsrmljrfjsqvoomhfozhwbw')
+;
+insert into t2(a,b) values ('etmobrqlvrbtbhuhyjvhjsxtxyrqrrwaczifbgpppmexycwjengjnycnhcwedccxcktkboghdazyoxigijnrwycovpcmpndxpjyojlxlajufoavwrqcnhuntbakysqbxxttwutaggdktrhljdvkkrauq','tmzvksavpqybffnfoghhfsmtrlusrzvzdyjxljvwgiacuiqlfyojaejziacoqptjchyykohugvzuhqpsvrluvkcrxmooojedcojwjnjccy')
+;
+insert into t2(a,b) values ('','lppnnrkypilxmfnqzizkssdjafvwtswqbqzbibsrisd')
+;
+insert into t2(a,b) values ('nvvbadcqueevconzeulrnqmvvfjfszqvbgdryqblggykctklrokvwxrjofshfhawoumleoagfpeslqttfbppfpuvoaodbktnkzhyffhicrpaopytwwodvkfhgixkuxvsdbzhsdfnnfvjrfxtkgwydrrpfwptzuhfcbizfrorigiwahlhggegvswxorchhddlcsjjnrskuwycbccvgiicebbbqriudhhdnetsqvygbxzeafoslogikjcnh','ooytoharovtyjaigcaczkeoepthmpunccapplwzhmidjthgeqkzt')
+;
+insert into t2(a,b) values ('umpehmudxixohhthqgijbxrztsobcdfdpzohjxwjbutngtjg','lfallzjszqlpnqzutrniwbnfgjffdywzlrcgbueqplhqkkycnoxgzehfmarpwyboyfmwpokogtxopbdisapssvufehmgqbhmppekfbzyfrfwthjihwdgzqhspnyyfhdbfmkyyrutnvysvueitbdozfbsgvihajgnizcgmcvzfoapdvxlgfxbaizxikeewrhiuhvdcsmx')
+;
+insert into t2(a,b) values ('szsicntwnbyxqxhqzhxjmrgvbqsquqxxnmgrhhwdxdfidftarfwpfxufsdpucwuzeyjdrvqxuthyabpbpzhttjdfyahdbzokvwgrsndwamdufxjbvrqwozlhmaemjicazatzx','zpakwjcffcvuhjcdvfcxraetizdmfzgkqoqumoheutulzgosccfgfqgsmopgnjnktefajecgerubdiedvufetibnmnaaopfnuhescyyvnuszzkkxwwzblktacmtpfrfgjtmodenhflopqizzhklsnlfjyekgabvvbvnbcjtqrqigdwxztwdtgjdddl')
+;
+insert into t2(a,b) values ('ygpqoxikldlnomuuxrfecmjbovoatotjolkqjgyaafd','xwwdngyroobyfmetbaebbftdmmghbtcxcwlggcvpmnpikewaydtzcuoslgiajzppkecyexuebyqnyiryfywruzrvfeijkhzfrhrwcnjryyetwpxdfslzccxsudmholhjxekjyhprefvrqyqbfbaqjyoyxbhubdjuhizlccnmqcrf')
+;
+insert into t2(a,b) values ('aymykhaxjpuxqoxfxikfudtmtmbneijozwnyigexwayswyzukdmigbpoehognsbvmdqjlmqmsclkyspefksaikgqppbrswfddtkcmeuqpzlmbftfitwqdvqnkixrzqkmhoaufoqkhjcsoibhlesmqlrrymxfnvnxfy','cafypvzadurgtvkfgojptusm')
+;
+insert into t2(a,b) values ('fahsgcsxmfettdspuebgedrxfhdicntsjlqllqoidbbbkyfdgvkxecpjcssijziwrjzfjqwyoxmhataiitiqjdglidlxnnzzhdaylzmqzhbuuxmnhqxwxawasmdzxmtmnpzybgevfsbqjiyzjoxnmivncdqfbiqqzxdfyxokuzaswwrzoerluikxzmqplgowhcwnnq','muqwkjxourygpmortjmjylsqokucyivrqcvbojyswqmfdjjmjodenbitjnjfqppzhdmwonxcluffnijoadxtycylizawkbigmygsjnmmrvsuotngkhfhektprlztpaybdxcoczsfeeidnmvfuwofvrjsvubom')
+;
+insert into t2(a,b) values ('roblpppvnwcwzwxiwwxyhszklltpaxtsmeekbloafpjxiomcvzpwwpnpfjimtpudvozbuvubomworkmiczvtetgjrwwwhvbufcpoldxeknxtvhxtuxedvmmhcvvxglbswdkrdthgqvajkxojjcvoqrxi','egvjdkhbynexlivdnntwywpungijpdzxgseeejkavowiylyrmpalufplhuqoragjvzlvnixevfscwnsfobjorjimdgcgjvekerhxtcombkweshxgchpvxwmobxbtjpnuvwenykramnpiyfbgrdyscbiaksnovytbeehpaphmatwlkkyjwlhzwjgwezrf')
+;
+insert into t2(a,b) values ('tuewrblstwmijsj','turmtoadvxprygygnmcrfgpgzihhckvscckresmofheqjpnmbzhneyxvpgkrtzatfipaqzbivnrgezxlolrzyebjrbuhuqttpzmzdjruobugtoswpafscalhciqnzzjhueckfblbogugrdiixrwr')
+;
+insert into t2(a,b) values ('skjmbxjznamimdwzdvphyjstpmpppjvsnxkfcuyweecqfcxtdlfttrhyxeynokhgtdlvcuirizkifzfwbiddjlvlqcibeerhzexqziwuxxvsjkmefujlxsmwfexrpvouystqaxycyuubwghrdleeibcrcawlaxsjenxhuubvecqgibazwxbncfkadozjdnffkggtsjkxijqlcshkdkyovribrgorhkfcltnerjplehqpjftcfsayeioqo','obugfgupfopabmkmohruwlsrtpylocbolafwufotviqvqmkzgsvdsqwfvttphfzdohjsjucvgluqdolvxcororleusbhlafarpypbyvsicoyklqzkbxrzsobwjigzyvkdrfxgxzceqmvwzoajkrrrjnfjgoeyplqi')
+;
+insert into t2(a,b) values ('bsysboyxjldxxzjnzistnhxpwgbfhxfjrsfztzcyhupevknavjqggpvfuudqtrgcppgabxhskcezpadepboyiqzwfishnjnxnrovxkzumqoikdcquujwupfuleuselwfzlfmupseoolqnofzulzpimkwnpufosdqqvlxpvgrhyyitqsstvmzradzzolworsnexukyatpqvrmvveunmhkhemqmzcyuwyudqv','lqfakxdhhozcicmdlofcfoaiyrgfqzqfsxwslyplabhvvvikwyvoiydtzgkzmbvnzbpkygemqkppbozfcizbvrqoisasscluflzaobvvoziatgublptjrfouicxaalrmdyecnhygnheyvtixgnnmcogkvhgduceaozgoeeykremzttbfflzdwisykgpvnhjflhpxi')
+;
+insert into t2(a,b) values ('zzgjnbdjxcmeqtztcxwfqhhnkkrzzkugpsslmbbwqjovcxvaobgzwetyutbniyzbdmyadkmvpwxhdhyvtrnumgganfspqeaeveymzcjvbzflbknwkidlcnuktiehsgqpxqexjbrrktapsujpttstcjojkagbqohrwgdgmjfzjquhrrptwpnwwitrjgamqmoyvzhbeefljrgekvytymgonkigsbdqicqlpecxzwuhwwiztebgkhhhegsv','qjhvwxnrx')
+;
+insert into t2(a,b) values ('eyinnbsmuzhkpqbnbhearhuzwabzcgguboseboliauatcxjxzhajnwelhiouxzeqimgtapsijcmjxuetzjvdabochhcpoeexezkckfljzbwnttjqsrxwhkaweauoctonjvukzggzwajokivfmetbingpfxwmjggnloxfgabkaiodoiwmmesoqwinfxnsyecwpuairiydahmosjqdjhvlogitrfbadhazgfww','aoohvhnjvfnhqdpyakcspmvctotadsftfeuxvggmybolgsofpsiqkkwihmlunwtiedhxfomcbfjhiegxlgeboqwzrmxhuqftwnjsdawxlywakotvuadqwvaeonsfajdroqoekivcubnmcjgvfewteokxrwmoipjpxgkxihfgawcosxispcgk')
+;
+insert into t2(a,b) values ('uvlmyvkwwmjupqoajijmwbgpmscmvxdqerqmfnvwityleqownhygnrrxggnranpcgnekqzpzpvjvlpaeylbsleilikbajxnvkmizrqgpucezeelxxaqmecfxhfpeiexzzcqymvkgsnouciuv','etagihaclceswhzeuopvkytvomwtumtlclptyxzooeevmhouhrmgmlohfblympatcxrkkifppwukwmmlovdaanhexbdzwcwfsnqvgmhidmyhdueysaptevbxoktynxg')
+;
+insert into t2(a,b) values ('gkjlhijnbapxqmeuouyroaklbmgkippizbxgzlaoiokkhoxujayrguipbujttcodgef','qbbzrjtobpkivnytsgbzxivhebxkfkqfbzpybfzapnziazwpsvewmifhnjvgvfrhnsgizwgjbkyqodzltoyofcolmibuxlrmkjynzgzwkcauypowcdzrygvavwygcrx')
+;
+insert into t2(a,b) values ('qagpdqgpzeivkmddluwnrirwgobjhhypopwgwbcaibxacclhjzvvowvvswavbdghanjibdufhxifpharyvjypklomnkmuzgstgupvlszfvbcbyruietkizzjbkudaszgcypqumsxwzalgrfzbwttjkmtdxyzproenzglzlgkjiyzqz','eqisrzfoamynoxzbmhbbrfwskfwzeyppniqlxxutrywxqjsffddctequzoqcmnmezqkbntxdytkuwtufognnlbxsidzluprfyirdepkngkthmviervadwasynpypxhrmdzhavwsfxhfoilxlcgeqfhmjwojjgcsadqpxazlqhymovlqgbpcdxlgfekbcvstwyqxhtqyjndczzlqmybdnmb')
+;
+insert into t2(a,b) values ('vhbvblzefrvcjukzhmmsmbovyetkqcmzsbdgwjdvlxjtwoohvagfbxznuvkofotenmyllzrewjlhltrkvkzavyjzqhtsbnidmxtzvoijdofwtkhdstting','jyanagxpmtylpduubjdwholrmmkhtdnwdzcjibnljzauzvtgazmcsfddkdlfpkjgzsgbzpjulkpnzewhniecvnwkhibvsaaaxladguiiylrtkiclbmjmnlw')
+;
+insert into t2(a,b) values ('wbnlgbddcilytgjxufmhhgeaeclxfigoakuocylhreemjjpmnlhvtybkgvcarmpqpzhnwnpeuwludsxthdwkzmgecerniyputnpvozzzipnvvnie','dlqyenpiwsqfjfqlabhpkzmvmfeyhowhetdfszkouzqrxcrllxahbnzgayggipzrwvvkgaddgczgmclfrhgjwklvoubpppkcdmfzqnuktqmoeldittrumbmiok')
+;
+insert into t2(a,b) values ('fxcbxjtkeokbxriufzyzyybvykwafmzncdxzicjkmarmdayydzrhrtfsgjgmnxfxdlwepjfkjhvpoeyupofnqgucymvjpkjrtgvylibshekdeoqssaaqt','gzpdnlasremqzyifjbxeqrhmegoxkdarppmqlyutpkkbjbtnrvxyuwvhfmfbtpzdxybbwqsdxatumhsllqalnlzrpmczvnugbaqzfvjnozghfgdxuhdxvmdwugswlacmmhiguxfvpefjcicpwqzxcynkxlpuxlmxxqktvwcguvajfsydqtauqhvnaiacvuwdmufiogtuqkpxae')
+;
+insert into t2(a,b) values ('xqzxnbhdiytmnwe','eofqaclonfvbrgaotktfeppwuziptdlywmtlqpinvzlvxnytvqgsnihljjjexdyrzdvyfzfoeycvnajwcdwxwloeweghcdfqbhpbfnmfxjgmftdjlnfuhrwezcfxxpbgrymwifezernjgvwedvnbssijqvvfeahbujngcnjkysarxuozkkgpjkajmhsfngcclzqfxkxygbzvjxhapeiwswprfdyegamexjscuqvdvgwqrugicqnyqpxnqbgknt')
+;
+insert into t2(a,b) values ('gwykatatktscpqbgdzewuqfapiybnaztggnozrrqsbdppazuadyuqshxdetwblcucjjqthbdjtfeybupsqljtmgephddqbbkwhwauuyqkhkkzeumugvpsooglztaibitxcwnlnpftzlcwqbjiligmnshvhopqznhjilqozckwvvshyrfmlwcwlwjcwliukymkjdfpz','mvywoisejrxhrsoobdzeprgvawtbomnrffeajjyjhkscrdtotgtwhorvrpztjhkuitpijloctdibdsxrdzexyuheozyjnqpbucsiqasesuxaynmzbkvxiegkipsjjxgewjacmjkqyygnycpjspsc')
+;
+insert into t2(a,b) values ('lhtlqvbdowbddwatifbywjkdocvcwuwwbgrcfeglmaxomvwdkrfkgcusyqyztnyikjsvvujqeelbjnmmmcnapblvftvfeizrreieyvvqxyvmpiuvgkppwwdcdoababvqfzrktltazydrofnggqhqkejkemswjqmwoheeoxdsfvuvmfetqixtxdckezfemiqyzuboqqtzhbccqamzppabr','echedddebqanzglbuhuvkcyxknvucxvxzyjqrfgpkoscvwolvwclhpiuqyhrktsyjwokfpimousyocdxmkvlalirshtmrykvxqcesvgajqkammigxzitvfdmtwzqnuyffkyxdhoyleiepgvmpcknnqlkiucbxwlhidxwoutymetpmkosswfxifdgvipffblfbekuxlqneqt')
+;
+insert into t2(a,b) values ('vkjyademayeozxspqtcnwlmixqqnxsyonaiexpjmvrhnlxfvaoavtvnroauduzlzacxjchlipzgaenyisnsxjdbpnfrmdmbeyfnthmmdskblfzdoybiykdzlwsmyknfwwekuuipwoxbennibaszgcxligzmxupuxyeelobshgvwzwohjapzeeacnxxmnfggqmkfqqoqrjinlgipt','evvnrntrmhclgsxkossyvxhzjbxbpvzuvbqyagkgpwxcrbekqijtgvxazrpuhbtdayliytxjznznjmrjokjrtpevolsjaxhxqhzzykulrjrdbqbmndenokfehmckqcmedsagrrrqkwoh')
+;
+insert into t2(a,b) values ('henslqxsdwfawafxrbmfuwctdkziwkt','tupvwopvsjgzsomotdzksictcuuirxgzwueivfagtbxgpkdhyszvnekrmknvhpvpgvltkymcvgbdnxszzurnrnsjkrfjqxetxlqijtjgltrzsajldsarecylrnokueczyvkjqzbmqxzukhcuvwaziyowfvylrxwugzicnyvqluwuljgpdscplxivhhcnnhonmrevyzmzxiktbxftikqufqlxdwifcwmvd')
+;
+insert into t2(a,b) values ('fquadxhlfxwlueytdzkakkmaunvkopdlvcnefyteqozzrsdqbcubthwurvgcvknpnnosmbdbdawqfjvalnyzieuqcyjkljajdgonrtoeguldnihrcfsaeuwxovrdjirtanwbuywzmdtiaqysczgfxfzznbqlivpwqtaxhsblbfkzewjnpxhwwlowyjz','uvkzjcrwofbebrjduwkmnlfffpktowiqbuziqtmjmhromekhhmjstscrekpttluzpanvgcksofbn')
+;
+insert into t2(a,b) values ('ccyuoaqngcrrilvdbmpjseskzbbcobtiywndiguwyipdbrvzsmznlafipktkglophxnmmazegdbzuocmuixsyqhjxazqbdvlfljwlknljkpcuywurhbukiolbayutkcolfdjyogebbotskydxzcvseqjktpplyqlvutuggjthfpcfetqwzxokyoboruylgccqccqihvuvjhwwl','sbcbrgzqwoctvdcrtuwgpmedtxhikjgbegdkuqubzjrjgfwfsoeepuxacrsfuyskqkxsyjyhqsrzkkwdhnyngokyovalemwfzxgxicuudnodcciytbsqqggjycjltfphlhesmnhpnkjuwczykpawkhgynxtpxccyosj')
+;
+insert into t2(a,b) values ('gycllmnrtywarvbyerioqczhnvsprfwitagwayefrojhkgwbrbyewiljhreqxjzarntopmksnhnwzdjjexyyrvmrhupgiftbleokayiojwtqgmjqstaswujrnvmvrzvhwxbxgcfqmygwctaeoryyvgzqrbsoyfgyzaalgttnsptbboermqxrqlpskdjwtvlitioctxn','qqiutjbohfqalnraitdlgcwceqvknquiqvyehcwcqouocrpwcqmmleclytiwysjpetyvkrwwtzpqaekaixjvrjwholmthjfhnqcoknjkepmwcxpugrrlztcusf')
+;
+insert into t2(a,b) values ('aaygwwedp','hvrgmfhyuhjdaqmvrxmrhlfwvalsoabseygyxqcmyzglglopgioigptxrvvcikliernelwjynjkhijczxrlhqqxfeztgivjevgaoohfmcvheibprhpzdvffyhzvuucnhvnruzedzkmfjoolapzuexxnfdtumqyaxfnkrccgqvmrqcxzqmpmobktftldtmvnjl')
+;
+insert into t2(a,b) values ('rpszmcvsmyqmbkzluyxfjdfwilltaefouhofhirtdsrvnutqvcnqvopyyivlmjcuoclmjrizsttbjvogsiz','wwpgwzwrxmgkgymxqhgamuhhrqtyhiybynoaxdmrujiwstzxecoeorekkxqixdopxeeplwkwdfakekxjdbmyotxejqtxndparvcikqlkgsyhgsxxvlntm')
+;
+insert into t2(a,b) values ('daiddbappffldqetrpsfmuciaimvtteokwwvftnofxntxyxmdazzgsplusvcmfreyeuuktclplthutfimebrdodptxsbstbftrtrdzbymttsblgqlpgjmocpathdfwczpbhmvejsytyjqhufcbsoaszkzvcdompvwjbeiruvrureyzqgmzqiq','qjvlxahrrtyudmbkgsmukxubrbffvrzyejgwjayeyifeyavsgfxtffrmhhzvv')
+;
+insert into t2(a,b) values ('focxkxbxhawrbgiwfcencbhwqbhowlmjmhhqjydvagangvaeqjcncpkqzbgdaqhaacdixmaiugoapkkknrcewialpgodcmpwgrcfhgcidivsbeakuohvhxdfkoyrewyadjqphutxrigkfmczeuerrldbsotzlpxkkouxmcpsktwgqghzddiwuxuttjrdyzgemssvplgyyzies','ntgqktwqiztpunfwpixvqaanvtarurnxinqcnfxfhhpagstjwoj')
+;
+insert into t2(a,b) values ('rnlelnoxtqjpzifjtagprogqscpswnrswzvacmbbonzdarqzreewbocjaoqhkxoytjkuqzsqfkyk','awpdiheomgnbwfnvzurtkjwvsdmaljbamqdxshpmqibifmjgtshdhalufnvpfcfwkzzaugwtrxfhsenngdjxsuxtapmzjbhjwjsfycknheqgoyrrdzwhtnwftydwhobcclowwfvmxbonrcirorsvthnogzdypgocryffujgzmvfexoajlgtxzsnxuixphckuegoiqylcabujnafopbepeochbgnkktbbuyidwxkingapstnlrfrgn')
+;
+insert into t2(a,b) values ('vtrpfpazsouwwfjkkogccbhds','wbrwlooqipxjhwtkmifgfjnansknkumscxqeucbyygplenqadifxvegktecjfcxngabzsmjaatxbsnyv')
+;
+insert into t2(a,b) values ('irjskkrwkeppuurgpatnacvqlvmifsdjlvauluueebegwxsvtoyyyvtoaojjfjwgvadzmqvbjzeryazwobmxrlcsxnewtaesnwjvwxitsflfwmmhtiyoleuglnlgykhsdtttr','apkqaxvvllyvzsuqrnvpvspzcwtdyphkwjfossbbbsyklqfrnbbjmvnbdstluqkmwikzchbjwrzuttrrnjjaipnpigjvfuycgttozynehzvtemjxbohzjqawnjymxgrxeognxxeacnnmxrmzwbrtxmaerkskhsmylhnmqkpbtoxtlpnhibeicbqmzfotldwtwhowixmslcggxkumcsccfltbcpvuolmakeoiwzishmdxhdwfpkd')
+;
+insert into t2(a,b) values ('taekhjnyhibhomc','nzmknxvnfqbskgznizwkkbxseqqvzjcw')
+;
+insert into t2(a,b) values ('masdkttvwnrmrapxuixflcstoejmeqtsgqoxwdsglydxbudqmbckihcyrthfbakqkmlqumpwegwytjkiqivzdmaneaaokkkrdkszwdhrgjectuyfyrlnpuzvngrnxnlzjkg','vknmfcpfxsnlcgdwnqdntmkgblqbivzfwmgakqpoqwulftlestnvnxakkovqpiuzwswyxbtwrcjmyllmvzfzypjaxbqxaxlqnfnjshhusfifbuwvtslzuswppzjmuinyewhaxsfamdjthsyyddfxssh')
+;
+insert into t2(a,b) values ('zovpbtizdalmrdseeownebndamfmxihuxckattvgoillomvswmawcugmaykcphkuuowfoqwekxvxjhjhwrzkmksewgotsaaiwcnjuegqtdpqghscezracohwlmymqcycvpthbtvhrhazwyexlztxsyqddylhvzohgpobemkbieosmczyhboxqxlbggftxdhwzjqpwnqiskuwkqvryglbswol','ahamfhgljrbtkoruadgxygfidmbimzqzbhkpkslvbibuoaqvevdnmdzahwghuzkuswjhxyollpkvhfapykdxtsrjwqvblzjrsibvacgbmstvqzbjyewwbhwxhhfxewjumjbgvqtytsozfntqlexfccuqudnulrtznzauoabjsrkxnuafbazowwkqdgltfwceftexdkdcnltbgifvnnabhrsnhmhliylhmfdbtumwvitdpzfuwsg')
+;
+insert into t2(a,b) values ('dlkckyhsnnyizsgnrmhfabhmxhhmevrztemcddmmlzcgdufdccjadzqgntwyplayhhckqkjqmzwblipwfxjghsyjhlseqnccvabwmeukvcksnhhceyrghnnrkzareeisfaqntjuvyozbkkxojjeupmnzdvdthzknokuwzhvmmvfdmdusedyuhmwysvemrwvoioogndrflgoslrwendgjctihjmmwddddsbfdb','qjcwjxjayhgnncjcrrycxoestmenoiwfposqpsjhwruhgfwltnkdpkhhfpguunwfygpuzflwdywkngauqnsocqeyqsmdbbzsjjgznxqxobvhhyithxjnmnb')
+;
+insert into t2(a,b) values ('owkxgtomxoqxwmszcokbtgjejyzomobnrraexkqkpxbcuhedvaoazyjrzrhbiciheqzwyoqhfbokspjy','aizlaowbmctfygfolhdpsiigtwqhsdpdjoeawtanxruxaeudifluzplrvabltzupffewtwnrwhuwqdxnepxsypssvxecxhythagijufsmgnqfwwjyzghcteyutxsjqeocoqukdtasigvbwzjljhjlklpaskxmepvmfxmumxyboqdjmzoikgfbwrwhmgkucrewifpxycoigzxdrkhaqzpvfekqcflpzpywfgbduxtgpxstrbxsfct')
+;
+insert into t2(a,b) values ('jmpehpkcwjtroermwbp','eonvmfzwnlgzwvndgxubpxydfyyjzidbkzecbtfouqb')
+;
+insert into t2(a,b) values ('mgvijfexfeqmarvddtrdlipppwnulxirjrhwjqcdjkgcsfkgtnwphznxnsduxqpwqkabxnxupavdcvdaoycwajvpvsriguzxxsodiubzfblcqhnmzyqhthrghokvtx','ufdmbbbcdtqokeekmayeqvzimastbanqhwembhhkgqoazzmdetxewmcnfpbiuahzpmfwyeuxxcyliovvrroerbfhbgpfcuxapjccvtvgsqfdlqobowphlhehvhseqnapoxbplybkufnypnrmfmrnddhjbsncwdcjbuvdmaqlmpiuxebcrnwenexqyidbyky')
+;
+insert into t2(a,b) values ('vagxbfebmazgduojxojuxnwumsipbhrtscacdeumirlrcevqljuirndmreyodbbptlnjsywlczskpiknbzakbpkafbkkiedjrnyoklunjwzoshltcam','yitvyqgaahuuvjzytnouirnrrrgeeycqajsnhzlgtpanchdrbdjsqgivhrvcpmjizocaurrfdwznhvvyqackimgwqpsqmhbavjkpwwpfrxszt')
+;
+insert into t2(a,b) values ('quenmztcnnqutmqdinmaogysworvrymgdrirczhpfsytjegwmbjgkpvuvohzaqbufxeqvwywnjboqlonqnoocvvcgoasaqejnxuqaubabddponjkjyoikmvknsejyqsapicbwvdpvpbqdvvtcirgicrmqvjlqwimmtjkcvzhebneaarvoymtzfuhdaveqokgdunvokjgaeepdmslnszmvrtktajmumxsrbejyciq','cwqjmlkkjhkclphjmdbkcnlujvhyhjiewnqnaffpkxavcqqcokkongoampwggzvwlsjdgxzgaczuabjtrqfgmmmsmwhqbepelmosdchuckifdixeoqjogbmgik')
+;
+insert into t2(a,b) values ('ypfseovofsunustovlxftkykmbxdcdjjikfcuyujlzfaudtwamcyewgvuyjhkrolmpejjndvfrhrmubdgvdghhhkkjwuwcrrjukjqifypdqtkhntupzzonxvtzbisgjvyxikqhbegcnooayflpthbqthcaktmnktjhxadruuhdkvvfrovswamqtnsxjarrjmcijxpojtjbrnrurwrlujujujlus','fjvvbagyyktlgp')
+;
+insert into t2(a,b) values ('wxtxytllamfumzdfnaxdkzzryiljuysyedzgynszmdbwqxfbkqbjetxrhtxhikjzecyblqkzlbcjdlfbhgarxlmgbzyfley','trqgvpswufinsoddhnrsijaoujcopeucyvblijtbhvqdybkcejdogpzxpjhzsspotwlpyboukljhdrkycovrasxbgkvfblcwhlmqpgtbyzwncpucfjnlfwuujicbcenzlcvvynowsrxojachiqzzrafllv')
+;
+insert into t2(a,b) values ('tkopwxoummdttpcokxoezuvzzxuqrlqlktcrucdksaiaoxqqfii','nkrynlhpczjfkavpcqfnorbbttwshzllqbfwvizrjzglctuttlkdpbsqbbcbgvkbnsacuovhjnrtyuiimtqgcjabdbyjfsctdjwawxvoogfslcoaehpzpfycygowjqgbqgpprdpvirdvznegwdjliggojyqllxznvxxbbtughokznislatwrwqysgpcopochhbwhvhhckievtrnlszgfxnaosouoobvifbkkjgjwof')
+;
+insert into t2(a,b) values ('lmcoirspkuojwpyahelwxrnsqzmqkmfgfyfoehppcvkcarnrjpkyjoczrkahaqwuwthesdnfvpygczrdcehufknxbkuawebcxywqrdnsspzdtyvcgagmzvycokxrndslcrenyogbjhbmnantkwt','jfhzdqvwnyvddazf')
+;
+insert into t2(a,b) values ('xztvcedenzqlxumqfbfxxivbkxiyghhtoluelkugvyucoykcxzrbwnkgkpqrnfibwytqsjhczhgnitmrkxrzksjtumvxvyetezxotmodguknuqsherlymmcdembenpyhmuzugajpynotvwllxngezwlfttpdhdccxdwrqwrnxsjuuhbzcvvmbbjjjzfpatgubvvjoeenftqllsafhbtlp','pgwljrhrojbvlbobyoqvkmyqvehoaxwuvynxdelgsbkkzjscdqtwmevtxxuhymcuphwqdvschocmiwslgotnkgvygbfemdvvxsxlrwu')
+;
+insert into t2(a,b) values ('ymwdmfwmztojogkejhpnrgpktntnbgvrvrhohirwfodazzflabnldhwecqbghpfsjcyrcxyjxfzervurtoxviemoxbxkpkjcexywlkjxfgjclnlqklhqzahslorlgujvsmlvjkbgtiudasgcndrcglgllezueaxfblmejkuxhlmdxbqaloztccptgvlrorslkjvdkjpjbjknvsuorhdmerfgqlgppuruyogcuyjpocv','kmpovilhnwpiysuciaixgnuoceysqmsifzjyinporlnxyufbnmipuglqcsbkatuxocfuhapobhuscwmrlkljorjyuzbzmjlwmqvavgdwqirzfxfkncygutvijglkdnlhlwmclyduwxqvtxdkxmpotwwejcmgijhqjyjkcwqewjifcyhpgcjdryqdbzqxtdghedsmdfmzoiyeralnwlian')
+;
+insert into t2(a,b) values ('xtcjwrliempfrnrqxghfmixfyyytlceddspgtqazdmzpassbnmvgyhwhkrnxkcbzudjuihdsiunigblojfyiuarlriwzknnrzkxshvauoncknywtlsfuscmwdszjhsadykh','dvivelgoaeokfbgrysissnryhwxbonzaxudiqfrtcucwknmkfgjrunzwgzmzmefxlgypcdubrgamyduaxeykmgebrnciiwhulzlqxfbttswsbejcitpbwytnhyzvcqhmdgpjzxcpyggrsecgfmopwatzfnpcpekizifiwbpfhxauttpohdvycjrangvyupnujustbyfcyoadtondlfinhxejaepfxreorb')
+;
+insert into t2(a,b) values ('nkjvyrhrkqcnuogbpwafcrgjlekmteqcvosfyamwocqbjklrmejnrolkonzwvubggccpogcivazspmklbaduemiianrhxzawohhtitzujgyttisnbxf','laozarapksrmradgtdeehkqlknncbjpfsmfktcuimsmyxbnzrdmclibvcuobljenslbuuwuftifbtdgzlnzhhcxfmatztihjbkhymwhizivngoyetliordwnjvrizvixnzwgnix')
+;
+insert into t2(a,b) values ('kulwrebezjepnhnyinshzundrsktsq','cqlrwusjzmmvckswessxvsqhhtkcxtieuvsyooccndwwaplsozsitrlchtsummyctkmsklvxgjanxatixmormqakvzochjbaelnzkiepaetuowhseycdawtohkkgmzlorwdeodearyqgrpxdgdedlshmwlhyahipkaxdiliccufzzenelxmgemwaokxlsllisrybctdfnz')
+;
+insert into t2(a,b) values ('tacwrypncsfllzkrizunjdcsjqiiivzkwzhszvbmevihahzcxqgexwgeatoemjdbywheecjjsrsfezuhxcqotlqauqhttiztomijctqsucfijjnozxv','yoyvulomlsmhrkpsneovfbpvkwilkybwmxjsnljpsjobidbbehbymsqwlexrczdlsrteredotbngrlchwpexoyuvsrhtstdldwelsimrevbqhgzxoyybsfqtnerabpuxhkrhofpgrlp')
+;
+insert into t2(a,b) values ('rddhsxggamfdyaeguhycraduegklbskpeemgbfksqkmvnrgqmdmgtggwjjcalewnmjobcmyffreumwvkpsysjmjqeviwiwzdiutlkagrbcqseamxog','satgtaqxfvrbldnaxfckrdmbuhhiktpzswrcyamcovxxiktxhaqqkksfhkbrwigj')
+;
+insert into t2(a,b) values ('aoiuxzjkgwkpszbxafllpqdbqglxjtxlihtcplldljgulpiyyensalugequbkhmeyhsbhwhnsexwchkdaeaecmwsrbxcwgvxermjpjbyanpyqeerxe','lzlrzhtmxqkumoaueixsdretzqpuekuxtpazondqeafetimuimmblfgvlgmankzqpxbegefklfnmtkysnthknugsetndpqdbmzxtjxunfwgemdrdmlonzlkbiruleuqhxmwrfndbqpwbkimzsrvutygecyktvlohsnohezgdlg')
+;
+insert into t2(a,b) values ('ezyirbqlclkvcwmolvegeraqagefwpkcfxcbolduuzlhnoublswcyzdizbyimhbt','ikroyyhudug')
+;
+insert into t2(a,b) values ('snvpzbuppvauempismbeejelojvjhaonkdsdaojfmrzdjaxijaqxyjtssuoixykuvygijiltgodjcznduotrnonbyvshyghzqmlqwcxxggjvsjchszwbevzikpxhqsnfrhfydnuzlhiyffjkanymjvlxqoumlltyfyyqttzwozybkifrqgpaszupidebooabrulrzvifawgfduzqksxzsajyokrbjkddnpuquqyu','glvxdsvtxmwepmppsjrwgkgvnjulgnwhpblnmgtbslsinwydrfqtfvumajvasfzmdhbsfeea')
+;
+insert into t2(a,b) values ('jllocapjzjqbvsrgxkzajvsnxifsacpznasjrbkmpzssmkmmvjelldbuzxxhklygxejpwz','xtwdpaoufrdxfi')
+;
+insert into t2(a,b) values ('gyxzzvmtqgpxzxy','sjakddvtglniwdnexyvpwcvcscxuimbctsmfsrhwkfrrzmxzmerfjlwkjwesofldfesytvivpfrsocgojkvifhlgloqxtokyg')
+;
+insert into t2(a,b) values ('wfrwjhabvlahvvhbsqctfznphpypsluaicsatjqlvcywngphhsp','qkkwdyrnauolbhmjxdujdmfxpuqeahsfiylogqdzpgdmfgoraromwuwelotkqievqdkabgyjtepzsfwfndsljlmeeacuflclmhceurnlotticvloakwlglb')
+;
+insert into t2(a,b) values ('cgjleuteteaexoaqmgebhnwqtpbosgsqkzpgiuiesxrriaygdetvvpvlfevkpjzqtraoxrqrthqfbcnhjnqegtmbckhkepdvtupkdmamwommnvtvmebpjonqovtgrmrcktwefgvpratpibozyzgvdwxkzjbzcljkglqintbakbcjtebowc','etuocljuktzazfxhgwdnpoldmjqtahwaxvijonrxevzmjiqmgoncsxblhpclwivzofnonutyoedwvfemhyrftmgluprndvmytmaoxaxqchfbwmrfowuazbvbrwnlkwcjnnnompojjvzeqxwwjnicbayrvgkyqaijsxdnyfmtrrhzhvoxhjvbpzrzhepajmznofctgmovcsptqrmnnop')
+;
+insert into t2(a,b) values ('cvczctrzczyakdwrclzhlxxygealtlpkngvbawwnlaqlojbqxezlblsiumzvditrufiiqebbwodircnwtdcfbbbzvclnszjphqailqdwcgzrxcvkmrsydlvumkvkhjslaurmytcaigdkxtfaaidwsfbtiuhrpczqyuxbhxlwpuhwyxsuoypn','mwfzjnucscxsfdrygoimnunzdjzzkglvspcjkiondlpfsblrkrtzlsubkxnsvmkgiqufleemmqhqypkenhconutwyesrbfmhbxgrkksotntyhceeajkrojkjabmgqquhkqfjifijuicmxktjsvdvkefyfrvxjjkyfkhefftarctzwxynowtgyavvzmqpkkr')
+;
+insert into t2(a,b) values ('ifrdayqnvvvrvtonenqsxkieqmrfntnddrbpjqvfooskycvqtojjiewqpnmlhwtpxgjplbaaxeedjtxrpdtodbgcdzlhknenqhsbljglbdecslflvxxqpwdxulimnmnggmmccwregcrbjeiictnjofmayehmlvepbozyhqascmctrhjxizhyiktefjtooubvajwseugbdtxuhliwuvojnspa','fxizkmhhazkiuzfopxcexihskmilnhqqkhgzcoupgwjmoggpbcfyafzblgtrhwygvancuvbbhzwezoeigocgaylbuklopusdlanruqurclzsvygdtvbukxwtzdgbtxkmslhhegpxonljhpbninvegvvqcjdicrucxdlmcrvitrypyxrkctxemvjafoyghdyintltdriqhxcfispbfwwtlsbaghtoxqbrnsspptqnpgctufgr')
+;
+insert into t2(a,b) values ('tlthikbuhoivzqaeipgwhykwmhfqxfqrzxfddlhfiqkzlvvkpdntdxlneopicbnkhggwayucxstkgqmjtkwkxastxnmhizccqhjsdcyeecwwanrsivqrpjaeuyuxqkleqtiyegujojphhuygfsgvvroexcqiyxsycuduxrzyaxipgscgdvdulpwgbbpeyntvqqismkdcpsuuwzucrayseseimnhecmcu','bwuqlmxxqaxefwhsoecnrqrkznyepimnhtuwhcdxytwwxmwfspgryfoiqkaptmdsiasovtzljoutyywgcabifooaoictfslbnlehprswtehcvnngczpqcvpcelfxumberqzihlwiygvcmdocfhpydwwqyxlvvkjeiyzsmnplmpebgwfgrknrvctugkacmebtgdxokrera')
+;
+insert into t2(a,b) values ('amcdtvexfdcdbjnmawigrhrklypqsredyhggstzgfjyeejwvyemjtobdssofvqwlpntdkqcxfhlhrisejkxhbjiwpqcnmhkflzbhsqfksswoxpzizapgkhxzaqb','qrzzundlyeamvwpkdmgdknsjvejwkijftrrkjiubglpbpuf')
+;
+insert into t2(a,b) values ('zicyddkxsuruzvvnftklfrwwgrjujihhrrcyxowcqwhcfexsqbfjenrytytrlitddmwessoiwlmluxpndjfa','puzsrgjluwnkbhidliajcpwoqpvkfnclwbgpnsvgigvbulzdkwkpva')
+;
+insert into t2(a,b) values ('brqtfplhtbkvfuserzelfvewstglhbsrrcktpcjcnjhnumarkwoyfikcwmwhpyvmzuigvbudpwnfyongkgckqysxlnokrpzrijrtqqavqbhazydbnexhevaoanxarvrsycrtbhtxzwdfohjlovuyohgyvlgogamfkohrzc','asxyrserpchpcqzjcoxngtfgzizxaqdhosiycstfawcuswuwvaumwifrvwresznajkonytcdgmmgmipyljwototjpdytrahrtkabyewecetbidncjamhobyawjacyqgjrndcyxgrivntzpguefuezwfzcphltdnvatmosjt')
+;
+insert into t2(a,b) values ('vlcxfgkbzdqpqufoqmdesnaqawqsxgkxrzlbtoxpiteitfvupsczxmtbbtgvxjmhlaniybvnnkbzjwaeh','jmucqoglsotomjdzpg')
+;
+insert into t2(a,b) values ('wripcjqiaytfbtntrdwtpofogtnrjhrwpouibkdzczoqdumvpaqiqhywwfjxvtcsqchcivjrrahfcejsdzfzlzkznlon','odyjgjmplrlzacdequvyqprxdgwptoamqdkrgpbpecpogvnwaxfhrpptboumllzupxdvdjfwnvuowttebmsxidhgyjvthdtamlfdamncsvtljxonkjrelladtzvyzsowasxqqasbcqodpplszhisuxgutlwojgldlwvhmzb')
+;
+insert into t2(a,b) values ('hogcujjxvcvamspwllvqjezazcbltwkbkwfcqoiyhhwevdpsqbkcalwofrxdihndtrrjlt','cxqbjvenmwtehmpyvwpkxoenfcglihbbfedbbvmlddjmgfqbxrcgqoowxbhkgpxshzgafknhyodxwplfasbbmhkollpvhugaessahbnakjrolbfxdupplcwezcnsiaeseyzkpphxgqzgpbkrqhyynkcpvpjcrmtvilpctiuktvuzleeygfxxkyddandvlxxljbf')
+;
+insert into t2(a,b) values ('wgxalqgzsfdcjxorbfreooefgkdqypmgztzwmersrxqribxrepdvxiyauwuqvsyjdt','omwruvhtnlkgnkywyjofrlfmjrjblhstdbukjemeumkomaeevr')
+;
+insert into t2(a,b) values ('uslbfhatvdwwdzqyhdpamkpulprfrhlbmlrlmaxwywqygumssmrjflcmqqcgqeimbgproevrdafluzfcmloctphbjyqwbdoxvywxumhrmxeruxnfaeusjbtlptlrkaxildtqinjqwtckaeoruveqxkkqajjbxgeptztvjjjqlykkvgbssgaptdaykkuoktpalgplmtdqhkbtgliqxniagrefbhpysgifmqkgcvdtvsntkbxex','javbdgcmaiybtqvusxtgfqgdgrprbjwgbcfijsnjtomgatusqdceasaejvxrzshqcwooaomtkswmazfmkskiyrgescyikbnvtlzwzjilihcabzngwtlxegiipuslzhazixuipiszlbsfovwcjmiaupxavbmptnrujcojhennnmdwmegiydrskr')
+;
+insert into t2(a,b) values ('hmwoaeywlehmjzfbcgwldiyqurzetfydyhzacqgfoaazkectekktntnljilvilfntjulfpyplglofyqpkalleodwjwcmxczyhzlrqlzlihgvrvzbxnvyfekcxjrdlpgdceepqpqhwwacjgkhhxezgrumvkvshgtpnwxyuzsbynixojqudjjkibtbhjoalpwxmmsitnzmgnqyyy','odxprfhsdyefivydcaebzfnrxozakurztettlualpoqfojncmswfifdbxpepaeirmgiynxhqpyrrapfcpeotrkryfcqckrecyhrxmvzmpiquckijqgytasvgmdnnnptwyxfjhziztfnxscxkyitagqukejkpxtcqtscqwrrljwfqrfsbfiknyheljkmsimfbzqxlutjcwzmmkszevudecszeojhdl')
+;
+insert into t2(a,b) values ('ymqvfdvjtnhrnhdfivodpogz','pbpomkzqstdmgxzpnznptsqezpkyjybiaguikjtvkfwuxwhktewbjhoieikdciwzcodurbajgjjbqjzfaqplzplnfqjxwcnhfjpsktmhiktlbphhsrewqlpmxcqonuxnlkjiwmlmkhwiectbfejseycngramewxilmpksmkthi')
+;
+insert into t2(a,b) values ('uezlihtywqzwaylfixcglnecdcmqpsnylaqgjqgkgohmujnzeayrjcwhtyfmcxonflprdhuwdfaeprxvrb','dppwfkhaiowuyzfweljjvjehgxnmyojwvzuuszjwaorxovdbsgjmnyvyrfydjkbystufailanseyhfihsnpozbhgtiuqwhhqnpnaemfobslvbuvxyobyeuvfreotolaaeyksdeeuenezgkgrkdgduayfdyqryybeljfrrwlqippiookdximelfznpwgxoxumyfaoqlhqewixdhyiehrenovjhflfbqmavmrczumpwzzc')
+;
+insert into t2(a,b) values ('xsonldfbvordcurtdaeuqghfgcjbzcwepvbyguboxtraluzspfomoeafbvaqkzrbuymdcw','vctenoustmoohonzgbpwdiqsrkxzunmvqukslebmkmwlnzczquiewusgmvsdnsliqqcxefgeplvxludootsxveeqojktimdaudktkfhswyrmyxwsudnaqcirvvcmjtzluttnkjnpmilksuasnv')
+;
+insert into t2(a,b) values ('arxyhxzggxpdowblzehvjyrzldbkdgfgbxrvlmlohgghnbmbzktfkntjntdaepzbczbyqsdchxfkdssldbzzhcttqzvgoiizotgbtdlfasjmjbdyevdllblngxlfjjtalgxjujmievsivxrmymiogcykemapqzidjltixtvmxkmuxkogfgrqgelmjvpdeghjjetyfxemkoaneajvmrhxrbotzedxzmegukzfvtssdtiebvomktwybfcszdhtgw','lwwdijcfzlwsrlyfkjxxelprsbmzynwuamejmpnnxshavefinfhgklcyrqfvntndzbdhoqeosscde')
+;
+insert into t2(a,b) values ('djrdogvlqismrtawbyhpuqpxcltzvhctocguddibfwteuwpcxnxdcqroghwvlmyjzejmxtszyphazrxbxromrgjibmlqbvqnjiqdrvujlxysufuqusiysexffamakort','emoazgrvtllxixfhbaibnvmrlzmrov')
+;
+insert into t2(a,b) values ('lijxwchahzwayndfmklxeyowmmtwgtlhikairiqkbtbehoixpl','ladxygzoscwgzfiw')
+;
+insert into t2(a,b) values ('hzptrkesrymgsiflsfkvguiyfjsbzwatkqkncqjfbpywbjywjeeolyauyggszsuksglmdqffbuzsibstncwhzpxhivivaswjbrtsciyodk','wtpgxcgvefnezmzraagfrfvzsgcazjzrcxfmdxladcjpgtvnywylcbunykwtvkufdxaezcpnulqqvunrurkbguepqompkaffedljvivtqodgmeumfvvgjmcgplrpzvoqhzlliogrtpwbuwvqaijueifyshghsjislwgywdiowxszwhilsuszjdxqsdphsqlkqynuorzxncjogtdcwohxvidbijcjoqt')
+;
+insert into t2(a,b) values ('retkoeyujpinwjbbwjgfziwpwoasfdyzhrzhoyqxaeqrnftmjuiumgcijxeopcvojtbcvxtwekznujphdsykdjwbkuqrpvqpzmufzmjtehvucjdcydgoxhyheufxjjlmerbytsecmckvtmnzjikyhaiqjobrsmufgzcobbjhj','bpnntxsgmacngcpifschwowetkhqkhrbblwefdupojzjeokmjnprdnsssqkssqyhggqopbngpyvbb')
+;
+insert into t2(a,b) values ('ytdoryvxtblrtfypdlxyanitgzvoalzxekbugxeafdcxvzzzxgjnernqklzqghxjgkyopxvoolevkhdubourkvmcubnmjmywdxhqxakjmnzxmhobtybdgfvaomscjmndmvbqrtfclmecjgojdsptnheumiqcudkbfgyzrvctuijdmami','zprvuztficylqmmkuaxzfxcizxnzmldroilecaavrakaoytesstswwicclauwleamjgdofbyhocgfdqhjzptdyewmgeufwr')
+;
+insert into t2(a,b) values ('dvsmoeazxagcfthupolveejgshqganvtupmlhervzodowfgxonuqurictdwgllwprtrxndzodvxucrecfibgfzuxthe','dwenrcumcjfvqimwpzmccmgxucguixynapobqoucznarfrnkfdisxogltjbra')
+;
+insert into t2(a,b) values ('xpyuxoifyhfzvzlmhtjijnrwibdcrjswflxarsaxp','bisqnnivskjwwqrcyfsdgfyoafhjolhixdgfivcwimfqhumquxetdnhrintaotulufbhanbamcuepkkbieavupydizmbqrbaefrfliqaxrqdzjhmmqmeyndpmvfonqsabtsuqtqkxfcsezhnnqjyeqmjarmgtme')
+;
+insert into t2(a,b) values ('wezudrpzuqblerkfzfvbuqjrnzkbsdsitrxglayztwnmotqcnkvnmecapkiftfuxulzlkuiwpgofajjslyrjzpcwrqaciqykjbwmpakrysznwktrfexjqgyyloigbblvyktizoohjwccyjgmhuwwytvwhbuhfjvbrpxtaokpjltarrbjrnjfcsxcgrxalksaoosqxcvyoqytlwaklgwhjzurmzamk','tskosznrbjresydacfcfpvuqtjdcvjkezfncamcnilpjfspuzdkzluktchsblbkqcwoiejahducdcegwydzgxegawddtcoutuqbepxxqydlifhwmntokacqhofjcxwkebilzzizxinucqkhleut')
+;
+insert into t2(a,b) values ('ajrgpdgdfzohilxwweytmxxoqazonlshebdpcgjxaqrhjrkzsjxfutdzdnuguhdkzxzhuygrkyztkglfinelpxhvbfymipyvcncpbywebzhkhgmxvpmlvnjgoeudrlmpksgbdvmoyrmimvnhshcfgdfbtwkmfbhzsnqkmqxoglgijemkiqfoywquwwwmvephqkjgckdafzuutnhfeytdzwwqqnngbfpgrnd','iozzgjtxwufgqbzptitbbnjfdaqrspqpgmbikeqavksigehdowkmresyuxfjhpvoxoompvdgmsjmzohqawtoxodhpmsfzmiaezdwcolbwtobldzcwjyctnjqrulafmrybbinuuagyxtezb')
+;
+insert into t2(a,b) values ('kscwbmajgdowgkatpjjrykojtoadhgrgbelviakhznrqbfttpkzmbxqcbkscqxtklpljpynfcobvqrghnulaywyojosugmprbtxrmcplgutbghxkcnkdnpqhfcdrlsqxtgtfgtnwovirrxepydxbxrtdzwrgpyeqjiugtdthrpxxqwhyfsltrxgxfixkljfuzlbpupben','xbnxxalvqoqiluecchkeaugmvselvpntxcqjtvaqdnwdbnnlodxjrotjxhflwtuqjbgzprjytkiseitxpbkxktxtmkpkifdlwzwhlsiffxqwgfuqdigzurkwxrhagiupluxargqtybggcjxbvrekrifiuagsqqxwhsiudhpknhjhyipkjyjpdwmimtlyxplkzuhmjjhxprqssrftxrrpkfgksf')
+;
+insert into t2(a,b) values ('aabumxqlgfqyzkcwuogcwyskcvshrqtchxfosqpfrsnshojfvwozgadazhizrgoon','gfhndcllqmmv')
+;
+insert into t2(a,b) values ('ynnwvmnxodlqdhiiegwrsxqlmmbudxwkbtddroqdmbqaroxbhqorykryelvxztrdwpekjasekynyxjnxxbaxkayuxrehlharszpojqaqezqtacosrambwobsrzzqfcfdoqhsycriuwesgogykxdkjvquzeqjfxaxkruzixvdqfsqfiylhhcvfpnbvwybbfhyvcvwrpuficegqwklpijrezhbzkixdhhqkvhhnbqnbehxwqaujpbxmtrlzwle','kxdxncndhzgcswaoycbjdyvyizeebbvqoyuehbsjwbuujpglxvcmuggbyjqzutnfddrezcqhvzwufkrungecl')
+;
+insert into t2(a,b) values ('nwtsvsltwnreevfxmvptqokfaskiqgsivvzugyeyfxvspsqubvwklaihqwjtxktzxqxoqqaogouhyvirpyuwyxrunxgkukahnuztnkuslfrtbusfxxbpfdgnzaqniwhuvzgfpuutzihkbevundjgfopejolkphs','mupobgtwfwiarc')
+;
+insert into t2(a,b) values ('soldbdoujvvqhxeruonabymqidxrybqahicaaggjfeshuvurzilqtzwghwhqmsyzxluieswmlfozaweeadwokfkitcwtkmdkottuerrqwffbnuuphqoktezstigkbdavaqtpnwyxkvedkvteedglcigyahsqeduzkxzdgrbjcuqtrfdlwdibbpagudasosufwxbkesppwvpbautwqeggtlkijxa','rqouytqikcpownndebhiflthayokacigfvonjijifwxehmktnictrqoapqrwnkxcixnzijlqvdixnifvvt')
+;
+insert into t2(a,b) values ('izcxgvjhzcndsqavyjpoghlghskbvivuomskakuhybfrroyihraggfmfhdwhhwjvbdcbvsxuvhnlfkeimoxjzmyjniizcvwxqexflqmcgbuwikwpgjuitbkthjhoynckiyglmyfpwopitkqhwfhhzlevdzbboowwyahdsebnoojg','sozqbayypjsnzyuyxrjtyzqroicnxwiqyayuldijvydobh')
+;
+insert into t2(a,b) values ('ufl','rtqxwizvwrieykkidqfuqmvqfwfjmuolsruwpcyluangcikvomvoiuahrcwewcodhzsfahhskcuisskvqwljcssxuyecakpqxurtbrjhsqbedxnkfasjlabkzvzolyjnahmmcyzglvcgjiwqqrtkwaatkthotnkghbxybklcmcmrfhnposfvu')
+;
+insert into t2(a,b) values ('akhboopztzwwhhuuslgdayhbjltaqxkukdcchaugolppolffvjmr','bmzhsjermloialvcyiufekctlnwmqdyvocrobslpnshnqwrelrrhmvhjmbxqpgxknopnvsutwsqcytcnssacftgcwtcmwigubyiqcgjtlpwlljvinvelinzumpvfnrrzbekaljggcvagupzlocvqfvxvjnhovipqeeoml')
+;
+insert into t2(a,b) values ('biqazupxedqlyhjvegujduthadfxzzeawvubyzfbnemnfnutugrlzcnfnhjvkwjldajcsywkoqhxdasywyfhbrgzfrnfevelctxymjxiabgwbvuwqiyuzmpbxxxwvpwyejzzsbxxtyzafvnhbbvdnhmibzghjysdzurkgonypftvqozvvvqzsfegfgpefibudeeuajcdtcxqezzujfogrkzrazwavigmboiuonvmfjrgdtrphlhfxnsht','czbwetoujwjifkmqywauejrajwfkrqbqxghgrnuyykprjbmhrnelejicgeegbxfrsixdyrgkoxgfzyxbxumomnglxpeiaetvyusrysyjgbwstjmditkbzewsldhtjcuwotcucepzaaxfjphklupkbxkerbjrwlwyqdhvdercdzwarwzroppgjfub')
+;
+insert into t2(a,b) values ('hvfinhmlrdejcwuhvzztexrukqvtaiatuxefvldmlsfowkqihmwweopfumlonohnxfohzfybiliceptebftwprcvizsynqikbpwnnldasqooqsijhkwqnqxscjzlvrovenbntbtbbwdejdgwixpqrzjhafjljwhvpixqpqjddvhdadwdsksaqkejysssojsompqs','bwrloshdvbonclnqbmuokbuk')
+;
+insert into t2(a,b) values ('qmrwnldpkjxhtkxodqbihivbkujuzdkrgckimdjnwzwmmtyqepexyxnffibyhhrtgzwolotznzsxltyvqpziizfdgqgleeqqcuplkxiqfjlsmodjzrmdomwmatnnyynpuxnmycecmosvtsvvwsdcamtshdugrirxcuulwocumvxalacdlpxabpgbshxglhnwgkunvslknsutqxc','tpepinslulmvjfotxcwtryzmumkikscxivmllkooekehswbmjjnbvhcvlmsyovltqborffmtlqnuitkdwefolqcbxyhggrezdvrkrzocgunjhjwubrnihowck')
+;
+insert into t2(a,b) values ('uhvqwpwvbxxveiszsjvbsqwwryelfptaztrmdgmmoeeqzknbkfdmtecfehgsqmrcktrvuysmgbcgccclyieodymkukggrqspgpyfwzbsdsateohicfjxiscilelnbglludzjdaveygmzvldhjjqmrqqxgbpfipkzxwq','puvurgstyooewhoboajchiljmfzzcuregcjvheiwiqttqbibovtdteanqmiyncrlobwewnwvvxujnedhjhaamtqlcnxytdagbhbquegbcrxgasxjpdtvvnenttmcvornlzdadpprknidjupsvpegjonzfqybtwc')
+;
+insert into t2(a,b) values ('shehuaeihsbbqusbvfsflqcxeskokqmzqgoxgkvqvmwohsawdrumxvyjwxluyvzdooewutjnjmsspdzfafbbkpqmqktjxyxbocolwnfwmzqaprzrutmkoqapvbcuwpnhzwatshfzpuxnmrhxorkxzjpfgpywcgqdrzevwdgxhoombkxjjmx','lldkiicreblvlllhufyznpcrpkghbcnvbkppgxvxpomarmpmmnuczjlvyrkvyesosuernlzwwxrbcxcshrwnajcupmkvsnddqpzcbmvgjybjepuztbzaftkkbkkzbxoizqzbklqgohyeuoosiamejeeksttlshizfqwlrmckhridpkslukjrlydeivmubvgvsscobgrassyfqxpkduvhfiysdwydjxqhidkstcthjhvkujpphkxliulpd')
+;
+insert into t2(a,b) values ('ymjvrzywxxfwzzvvojkrhqjyttqrvorprkzxnocpepixlsqswroglyemruxghnrabjonnezqp','tqubktsrkxjuwmrpvkmnukldpgrkdsrsfsowxglgwqmwtarhqohdzvicoumrjmgjcsepzscvsraoyuqnunuzftwczxzvnckauzckcbgwjarihuhdutrbcivyufaerfwbsrgoaizfgencrffipgcdgpwdqgfodtyopyqghcqdveectvzrpjtrjcjlevocvkjwepqpphiqzqzzqukfbnqzovlovfebumegiapcbqzddtk')
+;
+check table t2 extended;
+insert into t2(a,b) values ('khtlbejbtbtllowhmyhjyuyrioqcobsdzehdydiosshlsxmcazvggwvfdbsljoslaqbdmqunazcsmlvslxzkzwgihyfqmurpvhnxfdnqkzbegwboqymsxnfcespljoutxnfsomfamunmxklsklxxugokmhfoeetuxaqvrdmtpkpivjygmnpevzxodicjlwnloxizngjkwmfs','oa')
+;
+check table t2 extended;
+if (0)
+{
+insert into t2(a,b) values ('jaiaxujiqrrozh','oieurlfbbwwlkguvnloqsslsvhwuscyczrabztoaplqxfkxfxzbheiiqaxxdlkouwsdokanmrybgumlkwndavk')
+;
+insert into t2(a,b) values ('omjfobinorjjzunhhvttazeyaqsyzkmxaglnrvloidfvbcmtnzljwhrlsmfgcdxfxbrpvkgkpubwpxbnrdchqvkclttixvjaedmnmpsnvajjmboqcnammkydqdajqcdemkiwrxvhtrkygviuhoewderwszmxvgruofwqk','lqdgwouzhktfrlxbbezsxgzponchhognwjkqgovqxzgbgsmuilvhipqeyxttiyhbuvbhwjdtnttlneqhmxsbggejridrzniyadovgquxlgpgjpsrdeemjikkhe')
+;
+insert into t2(a,b) values ('rvztndyrduzfvqswkfobmrhdicgirglvgdqdvlqffkunhluuavbstbjfatdszpmmoiphxlzqcqwhpytepzhemvnprmjyjsyflpaxfkmxybtth','ajmqjmsvpprllxueyimhtwnygndnaxunwqnnnmipslptqpsrvbjvyhgrihpgnujoedameugdgkgppdjvpycolvbwiezxjfgsxjuswaacqmpibogvsbpawfxfrowkxqbcuoaqyexvnnnidcfuhdqdzgajplunvezzuwxmrjeydtvvvhwyqeqgcjebzsnweznkwpbkmyfbmrgyrneiipsenugvzcmarsjhwnhwavgsbvyhrmebaqbekqdi')
+;
+insert into t2(a,b) values ('yfhtxdaieucxceupuwgjezizkbyvatiqicjzvsgkyisdyqzzgofnuyybcvfuozbavvtitycvbodmvj','lcyaiuppvdmjfkzvtigdjaqsyqjkighscbggtkhwyohhiemlheiupxtczntcflboifdxxpeyvkdfuawxyytvkjqwrpgpjouykirkmafognrebcznxspyoqgwbwskyuaohyenarspoamtiotkgugcryqfgzhkfdcymjkqnticzjltgavzqayazpykbkzbqmfpsxnfzjkdseemfjifnojiwkbwrdrzeyfaeralrsozzg')
+;
+insert into t2(a,b) values ('dogtixzzovxzgbxvkeoyestikrqcpewofqgbqnflxddchbbfygtsxqxjbcswxwayunllassbpzvdvgtv','slsdbolmkgeqdrproialwotmztzhxtihhjjyavybfyilkmevostbqyazvolcvgprybyjnykctumhjxqborzjgtipdapjgjmdssbjitejecvfqxettjcqvqamjlihmwkjtbmehhzaomptbarfmbltznkaanexhtkzuoibxlmccqyifgtnfdpzyxz')
+;
+insert into t2(a,b) values ('yuxvydybypefrvcfwxafilsxxyubyqfrxdouenmylvjbhuzlllwidgqdvcykoycubuxssgquprtjnkspmrknsplmhnabcgwsurphonouwrptcyjpydyuyba','iw')
+;
+insert into t2(a,b) values ('oplymjapswqobrlhhhlfadgnzgnaeseloxfwvgqksyxxjbvlnarwebtvgpfataxzmepflfuezwxfrqpbwxpdxzllneaeivmxzgixhvbccyzulbdxrmvgctmjlxhyhywjizbateryatlrlyfgnxqblaatkajgjefzbomvnsysyezprbimnqxpoorzwzyygynapmjtpzvckkdronnveedjfathmtwygvkwgjdajhztkjpti','zsyapjvjwnaarbeiggrgycstqglunoatsxduhkytpfgxqasrdlfvvbohhdwctggsvedkyqwqiabfcqeawqudlwjai')
+;
+insert into t2(a,b) values ('ferleltqffbnqnkwkrdputdmwcvlawyzotjlsuqekzyrwvlanptjmuaoqyutzoxlmdlezjuynhckwclcvtgqikvvctkojqrowimqleumzimyzjfaznaeqtgvpnmozklpztnqqeajphqvfrvwukhfjtaqbqsgszkixhrvepgimwsurjjnrksrgrcpabwuobqdrk','ewlviqhupneyvexhonwcmsteodqbumsgckpgngpbmgwcisozabsizvrkcwgtpodptgbsaxijtngcqvzbfgextagodgzeyprxvibnontdqrxuedrhepsqsbvjubloblpfhllcjymgpadymywgpnc')
+;
+insert into t2(a,b) values ('qkitmuseyuikdjudejfauacwavvvcdvyrxahxwwigvflspcwelutqouqjfttncwtldevbetqqdyzubrmiugfjwpnitojiokcpyylzfnpnaoqgeudzthmizneinzzmochrpyfrzfebiniqghgwuskvaqymfoxybkzmsimafhbblrakqvuqzfgvgxkpbybyhgzhvldom','ztguyqkjuurxixwuwoxczpwmmbkjmkiuvpzlxqmowwwubkixetnnojysmxsilksmiucszgnhldzzgyogdazkhzxmhkuqadhzrqnoxwwnnndglmbjgprvdw')
+;
+insert into t2(a,b) values ('kyhlcprflweywzhlnjxqrgygwjghwghubqtfwcgajnyzmdwcjkixhjpundwfxwqqgajfpardeqgstc','xdgwznqakmhxdnspwexasqtmxkeogmhfvqxocuhgwukpmuwmfshypdbrtgozahvumktvvpfrlsmakfznyzjuwtoobebtuimbqhvgnpvltrhjkieujsijqovefgdjvrtkhuiiollbtoxuhlxiccgeaonjasncghlxvjeerladplwylfaofulehckngxyvwtieoukqayvzsrhqgcmwnpumhukibtiwtpwcmlzmzusrmxqwtxchiriurafa')
+;
+insert into t2(a,b) values ('ujlrxfcgqzywbrlzkndcygczlppw','lgepjtnuzfksfbldyudaigqlnjziwuzngrnjvaokailcjavjlkjkwhrukiklyqhhvgcdxezuxaoidlzmzhenlbeuxnyelaxragvzlccubfterrexfldafduitwgoiqhhahsxxglhwllkpkyrmonheywajxcsjrvcblccdsqyndxmfehpdccgshcheygitakzeubdblbllqvhw')
+;
+insert into t2(a,b) values ('rsefcjdjlvjuzyqvvgyhcabmvdeaphasawvcbhmtfuxmiaxpixvhqbsywbmptwxfpqtyqunhdrrikttlbndqxuvocbjvzlehqsgbnmhgrbowsgwsirbsdlxcoqgvusyidppomdwhoortogqmcpcoicyfmylrvmhpgmltzdhvrqrzgtvwugmfqebjkiemtzojehdkfpozggjzvzubxpsmvlqmxfmvanjigd','qsemzavuambwygcedndactyciyllpuxpkcnlsczclwcieyawrphaxaxwvemljlawwrsfnioerqceehpldmmkjodlvkwqtlbyrztcucnetatukkgdltiqaulyhblxintkhdkrrftrujtljjpvrlunqqthmlpxyzqoblmsmelryqkdnvxiijsaudscyjuptzjtcovmwpflrqfiiwqgbsmheaf')
+;
+insert into t2(a,b) values ('agiykjlqendrilibdwoorgdzjoqwuwlmxwezfgifyamfdegoaxqjpbfugoqykwmyixtxcqmwnduiezgexqozqpwvyqqt','wjnuxwudltlkcsygvznoshomytwjoxiheerzqtjqjlpvxxbgkcprsqtmwacgvefbbneqqnrrckjgdypoyeaciccsbggbehtvxtrxmohnyctxxpkhvzxsrfphpgnjtgr')
+;
+insert into t2(a,b) values ('ktrxcivucqosbzqdloltocbchxrjuejjcaivcecfmicizdfrzwezykiy','jwjvvtsakwyvixcpxzzslsphwzgfrpvvxodvsncdtcmbfdwoevenvlvzepmlvlwiafezrdpkcjwvhxrycftjrrqbbqoycqysyztpuaemvupxzgtxojzlwlteuykgndvdzsnnvdwckzgdgasxatqixamszwrezbdaabgsxqgscpnugpstqnropc')
+;
+insert into t2(a,b) values ('oqgqyxruodhbvvkklfknbatzsdcjkbpmdiodnnswwtkkqqzxxsikbaddqyzwvmbotpletqooohngwxruwasmtugmtfhnamziporwxulltudgshhzdrojuuuielcjkwmpprdcusxubyscfcrsajluxdrvhio','oibvbmnrnfkbggghommculkvebgghgphjxnmzezigsdqsnptnkkqezspkkuojmhxmsdqajcrbxibgwyhrdtldzfagahpqgmtzlyvhzejmlnjlklceqwttgkftldmwnyfacwbbvedidfiiewravbqwz')
+;
+insert into t2(a,b) values ('skiisquydccgjrowpurlyajzuukebbkulvdixrbfpsdxjqezjtnrmqftwxsjighnuhunlgnimdrjegftnxmvqmxvnudkbtntdnpicezgmwmsbodfmzsfpvixplpojzzrvleqiaqphjqwuvxjojnzqlkrkhuepkyfyltjgqbrnqjpysjlvbnvypgngzk','irvrqtfqmpvzbymjfwbzhpaibuxwlkfzkklftlikavlrgmkxzqssaoybwrblgoqxhfhznvigdppcwyorzxhpkinbqyvgrnhqwmacoaoimwppzekjqomtgyltofqcifjysqhbxqsnz')
+;
+insert into t2(a,b) values ('okxksjcnqokorymkrayigiwzmkzjrdvcdunbydjgpjpsjwwlqxkqvxvliwbcsjeeiqkemwvjnvmizxrmphsxlh','patsosrfioayccqclzvfebfqyhujlpogkvfpajorunmyfkawhhhwjbnisotqhfspndzjuzrlixxoeypntntylzvdyhmkdcjdmywckdgrjbbegkhhcgzuuqsbhgbpxdbgfkdlgyxqvvcjklhmdamdqusdrlxberzbgznjdapwhumuaopfrkgjhwupuvraqtfyvpvgpfyv')
+;
+insert into t2(a,b) values ('zvyxujquolqobqomsesabgjtryrmviircgnwizbgrbadznwgiawktxtkjihoqkjyzjretknctwomrkyuwvmdivgvlnmdnqzwkaafyakeaqtawshskclqfaxohodhbllbfsgkinimcqxf','xkbmtpkzgriehvlmibsggqebqoyvmplyivelsqayofcv')
+;
+insert into t2(a,b) values ('ykxthuxpzywkqawimzpxbqvwzvapdbmhnfkzlanjybjgiamadktctoqiatufabslfndypogtmfkniepfirjegkjqrkcdywdqubwdsdpjkmtqltzdemqpzkpdyattcyvreirvylhhcnemgfexvay','anxrfgnvpcmxpmsamdzxqoxrtehudcplajmafsbrctyvh')
+;
+insert into t2(a,b) values ('cfrjimmspfqyqziuzsavqbibawqzezugidoculncqpehjtkgetaeknmujerkdbhpaokkalnphmeijshphituivultinupilhrnnnsinytjrlpkuaqaznandbusobhzrwzsorxhxptakzqygrdwehoqpgqakeotvnjziyuktdbtrgpxridqpexxtivfmsxunkzljaiurlkpafrneeckkijmokmbvpnuefthnviwqiboh','lnuzopwtwumitieokdwqlcncnaxewgynhsfwhhcvkcwolzhytobhnykihplidzjqkcteodsobadlzlibfolmmaxmmhaiyzwnbeshvjdmrqulpyiqyrbsphrcicfavaabjyilowwbrrgfsnxmycnzwobeofbmerrdotpufexpxhdizc')
+;
+insert into t2(a,b) values ('tsnzidmzgxstjfqnkoyeiobjuupvxfjnhynwtoaeodtjgudxljmqhcytozcarhfbcxbhwxxrytlroywmuipwihgeqoivukknmofelqfhutvoorhqbudptudajqosqrgiodmzuacoiggcravjvaccwyopmfxbshgxcprvdknzkkaxsbobbqlgvklocmnmfvkvevslypgtnyqitzuuoyyfdyytithj','clqwfudcmoybxetuvvwtezmcrzdcglwwysuniqircltcspkjakamudqvycnrguudgzihpthpyglbtmfuiuthfanhfysskorxruimbycpa')
+;
+insert into t2(a,b) values ('ldcuhloaigqndigzefrjbpkfakmtaiqldakrwwxsbquhboguichrhffjtkmqufkwzmwumtkbgeabcodqylodphjblsdlomfrcwadebfayfdfjpbmrkgjmwzovigshepxwmkgscxjtovqjwktbyquvffrvdxhyjqqnkvegdeqrponvodwydxquv','zurhtunknlfkwsmuwswmlnimtxjerpfvfookndrwyghraesartjqpndilwlunpugyfxxlfacxtpinsxjoewhkkrevsyvnpauxaamlarlqqfmwdcbsongztpqttgovvdfvrptzhpoybhnxcnyfalvjhwlebtdpzytjypakimjiqwzkhftltmiqp')
+;
+insert into t2(a,b) values ('hekzxrliyelsjatvetxuhyewvulkeetnmqxanuzulaqrpkknzmaklcxirtintzpywwvnudwqpyrtbaeucprojxqmuhycgnlibcetvawngkizmhihymynseoyabacjdnuampzkuhnwbwyrylvzfnrtembpgunxffpvzfdovkgjfekl','zkchtcdhytggrqhxmdudieqoxgfeibwotsqqtksshzuratopkmwjvrdgatkwevrngmjqvxuaydozfxxrdccotqchewqazrdoeszbirmjozmvweuquxlyesytpnioblthoixjqwkzifqkbfdxybybcaudskknigqseqnjxfnfvxkcyrhmcnikhjaypuwnuurynzgrpacltvjfbglpbiuilwujj')
+;
+insert into t2(a,b) values ('pitujzweipnnruhhlbzomqsuqfhzoxkjaosjufkxzibqxdeoltnzsmlxgnfyefxjwpxroizkyqlgfxydhgbcsvfilzbilezasfpxaitthofjtubnxzvubtxtnceamiq','vecbmnsupxlebyzlxknejkfpmenydlqbxzezqfbxnjbxmxpheydvzdzoqnjgbtozlgzmmrvhgfwnazjhxxmciawkbljsbpzrmenegbqmwhfjmrvmfflykwkatvqqsyknpnjsvzanboxhfxkwmwtppgxeaemejebnldhoqmzbbozvdbojcqblmgpixigtbvogdfgfrzsutekrvybhsbz')
+;
+insert into t2(a,b) values ('dnrxarbgpqxuxiybtluselrmfxuymvelkbwnarhxahettblhcbgwftiqeexxnxfsondqdhbcajhwnshzdnbmfmjycsnlmgwgknrpbqjzvohryjmjqbqcbosehrerzeznkmvezqprdfwynlojecqhubvylwhwnlexounzwbdbsfrwwtfxemeacie','uyhnckhybnloqfjpmrxhsdtgioegwqnmcgzicrrdwmkiakumyorfcgdhmgommayinuqwrldhwpcmwaaemoleyqlqftlbuyvxczyqrjbyzsdgwhqjpoiawcvfrqxctjhqfmpzilmwwcbywolqbdkwmggdjmcqrzojmgehrgcuitixfjgitpoygidyyschafdleknkdnpvvol')
+;
+insert into t2(a,b) values ('kdmcsxfxvbdrbpshnqwrkdquqjtpncizehiviimqzrzqrynxzjzeqbk','pmhuvavhmmxrhdumqjbhucjghiyoteajbgguzucrxkrfhluxvfujuwupzvhochuprihhxgzijqxzuzqhmfsvvjyjycfdpyowttnevysogrnacycjmakfjhthzfgbdrtkwfintmfhcmbjtvdsspfzavxnqvlwqujqxm')
+;
+insert into t2(a,b) values ('uoeahafyfegdjggzbsrnoutvtlnlabuusoohcwtjlaamdgiocnkfqoicyogioofpugdestfesnqjzdifquucrfkaiinqpsjpirmhgnqx','tszuftxjirxguyovgfbit')
+;
+insert into t2(a,b) values ('bgqieyrhwxrfiuylqvxxjmpsfsmuvqhzqxtceuoomrriqdaefogpltyowellgetuzgnjmsvjzlssrleciqehhzzipulaxdfedjgsnqbmuakcmuuchhywnfawypfmzaghqbaxfvtlcgszsjcscxgvpggnobifhcqbwkfriajkdcsrnzkysevwhlryx','vmrqgadhysycdzkenrwhwsnezjxeoayyjqptawzjgkxeuiujddobktrhhzdyoaxfchvhihjvcnomomtczuaqmravoitfmxdpdmozjxpprvmmudsqfbuuocvhxmiaurwdvmmvxttqvhddchzepundmxqynctdaiqtynjpsmkayoihquadbuldzwrulfxbjhhucnljjtxloonwprhtxexgoaa')
+;
+insert into t2(a,b) values ('xougormdnfgflcemvmtfjlradzhmwtzheqtklxwafcpoadgmuiatyhyxwubmqjychmvgtlmiaamckklxjgwcrovxmrwwurnhbaiwqbifvrxrhvdeufvnsgoivfelmbajcuheupdsudergyrsdpsplxefpvazsjlunjwwgncygbuacwuxmgcwhmiuxtyhnejgny','paknpntzdeoxlpihejmnjmiqrujfliqwtujobeltguyqviqzbaevzhfeweqilegkccnnvxllxnhfcwpjgseikjnkrtayetdddpovncstzcruexfoaaseqlojznvdkhzbdqclkvkllcvkquq')
+;
+insert into t2(a,b) values ('hbhoqojsguzvttlbzxmjwaakwbnrqhosdbasfdjeajlqtelmawfkbhhwaroonpphoxhwohuvjcmppxwxpuweabhxunuqljnvhssplcbhelfswonatfgzhfhsnczrbzetdnoudhagfpotlfnbegxzjruhhoboxxvbwjevcbrdwtvrymflspotsbtiw','rfqnbvcxeduuebzntrrounznmfmfhdrpmyxciervmltylgtociidyndiusfxhbjrrwmpggbyxjgoebyyimptwfmdekrdtfecqkbkdecztutjcufrksmcmttlmoyrcfbrdomtmvhpusslaiqzykfalkdauqgmxrtxaoacolmnirimxuhbssyavmsxupeykkgnxfqtfmhssgtmcjyvtthjvedyzgehcbpgcdwaunlkwat')
+;
+insert into t2(a,b) values ('aktzsqxnhfjxxwyowhhehgmfcyxvutkssizoaifekmjwwsolevwilbfaabhdxmuorvkvbwnqcgbofxfnxglckmkjhnxkhikojqkdvheyhfrsocojlbjvrytcmbymrjhzsyyotlwhaunmhldqaus','heyfiwpsomlavhxqkqmqqtybjcxvejpzrwusjrnysdxrwfkukjokubgjghepwzyexxsudnwepumdzaazrxwtafhcomekptzclpukzzegxkyjtpoyoiirwilhxlstkcfzeael')
+;
+insert into t2(a,b) values ('soxckxbkzydgfcuhbhghrpdswsuesiniwexblnvrdnubnviuaawbisggbsvjuzhpubtxgmqeutwfvqqxxoywlorwpbafthombpgfrdjmjcrrdrqezqtsuykzbglltpqtbtwuulmnzvzizilrjwysbxxraevuvnuygedpdahekxbzwudunlpcyhsdpvdlyfcravomeqhjtfonygopqyyuxensrunliifwxxbmsfguruvokw','rhryqsklglsnjzadtgjgojbrvfqoxlvrwmfghsdnryrcgmhbeppkdroihpjakvrszwc')
+;
+insert into t2(a,b) values ('ucxmxwzhhkfxfhgikhwbtjwpubmwig','jcgplmxrxrmvxjjjdavzljnyuwgzwaynkxxivzqxwwpcjkwmibnebgglwhhkjbrqbssnkthbsiugrndhpyblzqfnifymaaxl')
+;
+insert into t2(a,b) values ('bwdeoeqrtkvrfhqkgoxtkckufjgvxwrclageorsuvnjqxixeohtuntwxhkyfgekgbwzgxlokxtyijuusmndkpwiipkidbzuiewmtwgqdyxgpgljsjnqxijurefdmwjvxlxacvpkwwqvlmjtdprybhmwqfzmwhml','zdigsbdjafcgaswtzwzyojnhlojodfvwi')
+;
+insert into t2(a,b) values ('imaqflbcjjtgztgxfxdweeabwhv','zllikshysfkcsqiefjqqhrttneepppomyvvsiqcwtwkihcfvtaygbaqdomqgzuiqxivgxzzoneyuxqxyzdbjrtywmwtzdnybkvteykjrgopwblufwxjfnkacanbpwptsfiuywlxketcfsnefnonxljhfunbozbfnqoobylekuvf')
+;
+insert into t2(a,b) values ('h','ldsjzxbfrgwvltiriimsmcwhnxaisgwhpfzalbfjnqnkpkdxmkrzscruwrbygywoabmlxfdvslpyichhfyldtdsrsvpxfnbtlnjkgfnslvgurzmdguivkptxdmmblfvyzstywhmhofczojqyoczghfmtumvbydnoaxehlsbyijyumfgagkzlkpnbchnxflztfrlcvjwfewnzqbqirmclxinrpbmxkrfsperaoclmzfcloh')
+;
+insert into t2(a,b) values ('greafddcuygvsvnpmnutnreytvhwmvogugbznjrxfzeaatqpzuusphpbyvqvwqiosmlwlvztyrixhbdochsjjimhabbmddgkczgfnzkqxnoqlqgmusgdihfqirbhytvdrufmlclvmukhjhgeerpehknxdpsqkzvrfottntsxgzuqpiyzbpcehmrzohewritzglggxaesdwqsvcixxsxazclewwctfocensgkwqpevqyxnopoh','fdmriyildrwdavkbugvbjvryubujowegbtdcicsdcqygslbisgmuutkydmqrtfykinyilghwlljgtxwbxrfhfifwviexnaaiagfgaiwrnoioxkuikbmepjgbvjhmrmuvastddbsbzjjlsqqtmqoxmbggwdkjvawoiechpzfcr')
+;
+insert into t2(a,b) values ('qqrshrstkxtxwmrnvzvmdrmlmfoimmwgyshfksnvqoktzqlwrntfnpiaipkxbwtkjsxhvwdnas','qlcfzjdevjeywcgqdsogmtmfsqudwochdfykmtbxbkdkqzgyouqjqcxwsrhyaubhyyrvrhrjuyzulawrkdszynegafqumtbpdzldzehqevlqwkcvqlwyubgkwufrmbrkviqmuimrzqhxltmvkwphdbyyspsllbjirggvyajwxslegczjdykdfzukouusfjntfgbzawvhrlldegsxogzoooavwxlwwfxgelj')
+;
+insert into t2(a,b) values ('qxiekcsxrswzzgigxrczirawxbyjgghkagifsmpwtzxkuyaxwztosjtgbwdcaybpyzvksbcynduapyprqfitelmugphiqeevdwdinertqkdqcsgahiveqbdyzmmmwuxjfoephorrdlujllgccnqhqnqucbulheyihkbsnofd','jnjovnvfpptdbptyidtiygcmmuwwfbczhxeqjqdehipyjcalenrhyxgfhektyrrvylznwrfsvcdeqtdnvagthencqdtnmkxbdsurmdwcqabzzbpdkqflncaytjzlzgdijoijncklclsilwfbdnpbmmbpsban')
+;
+insert into t2(a,b) values ('njlfslcchsxivlgandgpnwdvtsmrfn','nnwuasupapzshnidrahjndtsphyiobpvyahieikrhzdoliwxpplmumlgmcbqcqplskiygaqkrcfjqgfedcponqzqfsyvaaozubtmepzttlptqytaavlvybdwxdlcsmkmkzvixmtdohdffqyobelbttvbe')
+;
+insert into t2(a,b) values ('udxxlxqhqxlqgowbkkuzqnfqrjimmmvmvgwywhghaagzntbwrslbpylhrqqabgnlxqlknqeutditldfupltvuprigchazpkfxibswmnzebvorzzfgsjnfrgdnjquewwkfniimtvgyfwyyczpgckpabwszglmcjkezhmihpphfrtkfleyi','vlrujjrzcbmqgvru')
+;
+insert into t2(a,b) values ('fblbdmjsgrdhxnlyxlnuihylwasotgivdcmwvcfzgiyesrfvbwttflkhncrtytrokgvxqhyidnojywpilzzskhedqokz','yiqbooqeozruocejivqcpzbvdnuddxcjnoybifpnyleqiitilucctvzfxkzxhlucirlhhixxlxqsaljnbpquvngvqquaxrsjbpxpcqzqoibuhglusjknqpbjqtihhanapoxelcksbksblugpadevcsntvrtrhqtlziczqqoulhjq')
+;
+insert into t2(a,b) values ('ofnydtjrczvpjwsjrwmaxmoqedvgaobrqwuvgohaxzgglywynnugcnmacptocialwvdwwgwjuuykf','amucgcjibvxxvkpnxsxfkoyhvkcbfe')
+;
+insert into t2(a,b) values ('vknopfvrnlzckvbfslvvgyshgvgvyyiwiyzuilxlfazhfrzhlukirnjcsmfychxfqgzplunqvluqcnlgyojnwcpe','kikfpuueauligpdzyskudyeplpqoqwldkikzurrhfyccpdnlhaptxhefmlahftkctoqoqrpxtjgeriyzuwqrvtqnmhmduvzzotiqbfmacmqiwywssmcefzjtgltnvefoikxlkrnbnjatgztvythkpkusxzqdowadbtmyrrojrufhzqoihmnupyzmpaldsziqvvtpksbwvlgfazvfcrzhtvew')
+;
+insert into t2(a,b) values ('erjbnbmsypumcysjsotmuiqhjwbdrzxupsvocfscfahmkfcjtfvgyetvvjkiadwdzhebtnpnndjrfpimbajperlnrnmjuuztutnnzbwvllxufbykyzkjacsxxgnhghhbpqbaushcdwcudipgnnuuuinhakoveibeqzqzsakpxw','fvlmoqadpsikbeybqibstcrykqxubcsohowgdnimxgvrfsuwvkcahiavgxgzhxjqueugnnttouqbyztzkpqwjcfpafcjcffpzrjwshcbvvlbeioqcxdefrzsqglbzhytqsffjdlxsyjkgshdsoraktiqqguahxjvx')
+;
+insert into t2(a,b) values ('ervrflghxbcppecracddqizdbuinptncomavznyylcbewqgwnkmhllfavjlfwlvcmsoiyztry','ejjisvxqzxfesostfjfaixgrjkatqnjayxvnjflfjfnhgiljrullbmyrkcxvqrpwtoyaycgjmmovumkpbwenqivrgwursffauavqicujsodzfjofzpwfawxtzycytyrxgjddawzysayasrfzshexgdlxeelebnswithlerxncltwoboygxbyvmnszwahnvangctkaynhedgajdzpvnufnseyomiowrpnyaykczfdrovwsamyrmayhqzkoe')
+;
+insert into t2(a,b) values ('qwyubxctklhepinuepnpkxtkdijczrqoojxrnfkifrijjudyctlysndusjwpwzbfsqrlvogpybebquvzxztmzdisencoiweoayvesssnvcdvbkomvgolpayxonorhetzenhwqhotujgkdmxkevlhqbnogmryzcryprezjkstf','czqsuxdqpvvghxjuxhkjaqtqtkogtooxjfhfxzpnkem')
+;
+insert into t2(a,b) values ('xyyapswtsoiisbtdmjmzelplljmcbksajgypxvtqarobvfqhhcakrdgkwbrabfqyvaecbqkbhkcljjpmrirmcklqktbpoxbvraakcwqhciaz','onyqzmfeuuzxqwysedyunkbgbjpxjtzdqezduudpnsohsxyqeugevppodqyzgbeviyoviclfjgxoshpfazjdrysldpbjgdfmganewpjfaiqsqhzdtpxpgtecoqvmurijmmsyqorndvasksxyjmfmlhh')
+;
+insert into t2(a,b) values ('glftiusptdnjbsreupdgwlwsskjnredudsdpmfujbwcvtrpxumbwmshpqpeefvgconifsptfgkzbtuvkillgq','unmvcshmijqhmkrdoxeezfpbocxsgahhwjdfddjfbmcyhsjatoahgpvsmjelqknrggwuwkanxvpdmablnnqwqlntyawllbflrypxfsasbaqdqtddluajoysrgpymxaboyypjzvyonosxqwhevdkzuhwhluywtilycbrylezppiatlmmwhtihvrceihvlsesdzfvdpwvxtdpzbstzmcnriqdxzecsqtgcladhncdoogbkfmwssjch')
+;
+insert into t2(a,b) values ('vdypigdzycrldcfovmctkgeplggrowiuhybmwcwfna','vrgastbijxhdhxwksqngemzpqpjfodkpgwpixwqsieximfrzziqsnzwzjfgpozrujjshqveucwlitaywuiuykptvfoyrzfwqnjkcnwecnlezqnerfvtehybypevmfdcflkykbwpoqaedqtdgnlhfkyrxyfxibahiojscpihattskdcwkaiqxnsebxstebvqqgaqhhrzzxfaqs')
+;
+insert into t2(a,b) values ('mozkakabudlebgqdozmskoznveytfekierfwfretwuirnxwdbhxfrembjguuizghjbgsiykzuenzgnrwpitpkbzdlaoofyzgkjisfsmgzaeqefothgxtxfnetuooyasqpmlfuoumztxryckfferfigfhlwjthlupgyrfbeneqsdnhftrhuldhgdkkpryrgazwergqxlhnboydjepgphierwwwcdreo','odaetcnblobbncllnwikkemfggnqwdmasluatsjltlrnkjxbtwofsxwtxjksejcmcihtbisgplpzjfmlldwporhoexdfaakpsziliengmjhkinoedmtfesewdtpjhksehtezhbujkbgtwxpyqzkwzaywyiocnplccfxuznlrbkligsazzng')
+;
+}
+enable_query_log;
+drop table t2;
diff --git a/mysql-test/suite/maria/t/maria-connect.test b/mysql-test/suite/maria/t/maria-connect.test
new file mode 100644
index 00000000000..8fa23909ecb
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-connect.test
@@ -0,0 +1,40 @@
+#
+# Test that can't be run with --extern
+#
+
+-- source include/have_maria.inc
+-- source include/have_log_bin.inc
+
+let $default=`select @@global.storage_engine`;
+set global storage_engine=maria;
+set session storage_engine=maria;
+
+# Initialise
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+SET SQL_WARNINGS=1;
+
+#
+# UNIQUE key test
+#
+# as long as maria cannot rollback, binlog should contain both inserts
+#
+RESET MASTER;
+set binlog_format=statement;
+CREATE TABLE t1 (a int primary key);
+insert t1 values (1),(2),(3);
+--error ER_DUP_ENTRY
+insert t1 values (4),(2),(5);
+select * from t1;
+SHOW BINLOG EVENTS FROM 106;
+drop table t1;
+set binlog_format=default;
+
+# End of 5.2 tests
+
+--disable_result_log
+--disable_query_log
+eval set global storage_engine=$default;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria-gis-rtree-dynamic.test b/mysql-test/suite/maria/t/maria-gis-rtree-dynamic.test
new file mode 100644
index 00000000000..228998c01c3
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-gis-rtree-dynamic.test
@@ -0,0 +1,891 @@
+-- source include/have_maria.inc
+-- source include/have_geometry.inc
+
+set storage_engine=maria;
+
+#
+# test of rtree (using with spatial data)
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+CREATE TABLE t1 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL,
+ SPATIAL KEY(g)
+) row_format=dynamic;
+
+SHOW CREATE TABLE t1;
+
+let $1=150;
+let $2=150;
+while ($1)
+{
+ eval INSERT INTO t1 (g) VALUES (GeomFromText('LineString($1 $1, $2 $2)'));
+ dec $1;
+ inc $2;
+}
+
+SELECT count(*) FROM t1;
+EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+
+DROP TABLE t1;
+
+CREATE TABLE t2 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL
+) row_format=dynamic;
+
+let $1=10;
+while ($1)
+{
+ let $2=10;
+ while ($2)
+ {
+ eval INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10))));
+ dec $2;
+ }
+ dec $1;
+}
+
+ALTER TABLE t2 ADD SPATIAL KEY(g);
+SHOW CREATE TABLE t2;
+SELECT count(*) FROM t2;
+EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+ GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+ GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+
+let $1=10;
+while ($1)
+{
+ let $2=10;
+ while ($2)
+ {
+ eval DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10)))));
+ SELECT count(*) FROM t2;
+ dec $2;
+ }
+ dec $1;
+}
+
+DROP TABLE t2;
+
+drop table if exists t1;
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a)) row_format=dynamic;
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+analyze table t1;
+drop table t1;
+
+#
+# The following crashed gis
+#
+
+CREATE TABLE t1 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL,
+ SPATIAL KEY(g)
+) row_format=dynamic;
+
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
+#select * from t1 where g<GeomFromText('LineString(1 2, 2 3)');
+drop table t1;
+
+CREATE TABLE t1 (
+ line LINESTRING NOT NULL,
+ kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+ name VARCHAR(32),
+
+ SPATIAL KEY (line)
+
+
+) row_format=dynamic;
+
+ALTER TABLE t1 DISABLE KEYS;
+
+INSERT INTO t1 (name, kind, line) VALUES
+ ("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+ ("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+ ("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+ ("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+ ("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+ ("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+ ("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+ ("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+ ("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+ ("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+ ("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+ ("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+ ("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+ ("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+ ("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+ ("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+ ("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+ ("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+ ("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+ ("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+ ("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+ ("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+ ("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+
+ALTER TABLE t1 ENABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES ("austria", "pp", GeomFromText('LINESTRING(14.9906 48.9887,14.9946 48.9904,14.9947 48.9916)'));
+drop table t1;
+
+CREATE TABLE t1 (st varchar(100));
+INSERT INTO t1 VALUES ("Fake string");
+CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)) row_format=dynamic;
+--error 1416
+INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
+drop table t1, t2;
+
+CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) row_format=dynamic DEFAULT CHARSET=latin1;
+
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
+-66.8158332999, -18.7186111000 -66.8102777000, -18.7211111000 -66.9269443999,
+-18.6086111000 -66.9327777000))'));
+
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-65.7402776999 -96.6686111000, -65.7372222000
+-96.5516666000, -65.8502777000 -96.5461111000, -65.8527777000 -96.6627777000,
+-65.7402776999 -96.6686111000))'));
+check table t1 extended;
+
+drop table t1;
+
+#
+# Bug#17877 - Corrupted spatial index
+#
+CREATE TABLE t1 (
+ c1 geometry NOT NULL default '',
+ SPATIAL KEY i1 (c1)
+) row_format=dynamic DEFAULT CHARSET=latin1;
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+# This showed a missing key.
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+#
+CREATE TABLE t1 (
+ c1 geometry NOT NULL default '',
+ SPATIAL KEY i1 (c1)
+) row_format=dynamic DEFAULT CHARSET=latin1;
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-65.7402776999 -96.6686111000,
+ -65.7372222000 -96.5516666000,
+ -65.8502777000 -96.5461111000,
+ -65.8527777000 -96.6627777000,
+ -65.7402776999 -96.6686111000))'));
+# This is the same as the first insert to get a non-unique key.
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+# This showed (and still shows) OK.
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Bug #21888: Query on GEOMETRY field using PointFromWKB() results in lost connection
+#
+CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) row_format=dynamic;
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
+SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
+DROP TABLE t1;
+
+#
+# Bug#25673 - spatial index corruption, error 126 incorrect key file for table
+#
+CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
+ c2 varchar(15) collate utf8_bin default NULL,
+ c1 varchar(15) collate utf8_bin default NULL,
+ c3 varchar(10) collate utf8_bin default NULL,
+ spatial_point point NOT NULL,
+ PRIMARY KEY(id),
+ SPATIAL KEY (spatial_point)
+ )row_format=dynamic DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+#
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('y', 's', 'j', GeomFromText('POINT(167 74)')),
+ ('r', 'n', 'd', GeomFromText('POINT(215 118)')),
+ ('g', 'n', 'e', GeomFromText('POINT(203 98)')),
+ ('h', 'd', 'd', GeomFromText('POINT(54 193)')),
+ ('r', 'x', 'y', GeomFromText('POINT(47 69)')),
+ ('t', 'q', 'r', GeomFromText('POINT(109 42)')),
+ ('a', 'z', 'd', GeomFromText('POINT(0 154)')),
+ ('x', 'v', 'o', GeomFromText('POINT(174 131)')),
+ ('b', 'r', 'a', GeomFromText('POINT(114 253)')),
+ ('x', 'z', 'i', GeomFromText('POINT(163 21)')),
+ ('w', 'p', 'i', GeomFromText('POINT(42 102)')),
+ ('g', 'j', 'j', GeomFromText('POINT(170 133)')),
+ ('m', 'g', 'n', GeomFromText('POINT(28 22)')),
+ ('b', 'z', 'h', GeomFromText('POINT(174 28)')),
+ ('q', 'k', 'f', GeomFromText('POINT(233 73)')),
+ ('w', 'w', 'a', GeomFromText('POINT(124 200)')),
+ ('t', 'j', 'w', GeomFromText('POINT(252 101)')),
+ ('d', 'r', 'd', GeomFromText('POINT(98 18)')),
+ ('w', 'o', 'y', GeomFromText('POINT(165 31)')),
+ ('y', 'h', 't', GeomFromText('POINT(14 220)')),
+ ('d', 'p', 'u', GeomFromText('POINT(223 196)')),
+ ('g', 'y', 'g', GeomFromText('POINT(207 96)')),
+ ('x', 'm', 'n', GeomFromText('POINT(214 3)')),
+ ('g', 'v', 'e', GeomFromText('POINT(140 205)')),
+ ('g', 'm', 'm', GeomFromText('POINT(10 236)')),
+ ('i', 'r', 'j', GeomFromText('POINT(137 228)')),
+ ('w', 's', 'p', GeomFromText('POINT(115 6)')),
+ ('o', 'n', 'k', GeomFromText('POINT(158 129)')),
+ ('j', 'h', 'l', GeomFromText('POINT(129 72)')),
+ ('f', 'x', 'l', GeomFromText('POINT(139 207)')),
+ ('u', 'd', 'n', GeomFromText('POINT(125 109)')),
+ ('b', 'a', 'z', GeomFromText('POINT(30 32)')),
+ ('m', 'h', 'o', GeomFromText('POINT(251 251)')),
+ ('f', 'r', 'd', GeomFromText('POINT(243 211)')),
+ ('b', 'd', 'r', GeomFromText('POINT(232 80)')),
+ ('g', 'k', 'v', GeomFromText('POINT(15 100)')),
+ ('i', 'f', 'c', GeomFromText('POINT(109 66)')),
+ ('r', 't', 'j', GeomFromText('POINT(178 6)')),
+ ('y', 'n', 'f', GeomFromText('POINT(233 211)')),
+ ('f', 'y', 'm', GeomFromText('POINT(99 16)')),
+ ('z', 'q', 'l', GeomFromText('POINT(39 49)')),
+ ('j', 'c', 'r', GeomFromText('POINT(75 187)')),
+ ('c', 'y', 'y', GeomFromText('POINT(246 253)')),
+ ('w', 'u', 'd', GeomFromText('POINT(56 190)')),
+ ('n', 'q', 'm', GeomFromText('POINT(73 149)')),
+ ('d', 'y', 'a', GeomFromText('POINT(134 6)')),
+ ('z', 's', 'w', GeomFromText('POINT(216 225)')),
+ ('d', 'u', 'k', GeomFromText('POINT(132 70)')),
+ ('f', 'v', 't', GeomFromText('POINT(187 141)')),
+ ('r', 'r', 'a', GeomFromText('POINT(152 39)')),
+ ('y', 'p', 'o', GeomFromText('POINT(45 27)')),
+ ('p', 'n', 'm', GeomFromText('POINT(228 148)')),
+ ('e', 'g', 'e', GeomFromText('POINT(88 81)')),
+ ('m', 'a', 'h', GeomFromText('POINT(35 29)')),
+ ('m', 'h', 'f', GeomFromText('POINT(30 71)')),
+ ('h', 'k', 'i', GeomFromText('POINT(244 78)')),
+ ('z', 'v', 'd', GeomFromText('POINT(241 38)')),
+ ('q', 'l', 'j', GeomFromText('POINT(13 71)')),
+ ('s', 'p', 'g', GeomFromText('POINT(108 38)')),
+ ('q', 's', 'j', GeomFromText('POINT(92 101)')),
+ ('l', 'h', 'g', GeomFromText('POINT(120 78)')),
+ ('w', 't', 'b', GeomFromText('POINT(193 109)')),
+ ('b', 's', 's', GeomFromText('POINT(223 211)')),
+ ('w', 'w', 'y', GeomFromText('POINT(122 42)')),
+ ('q', 'c', 'c', GeomFromText('POINT(104 102)')),
+ ('w', 'g', 'n', GeomFromText('POINT(213 120)')),
+ ('p', 'q', 'a', GeomFromText('POINT(247 148)')),
+ ('c', 'z', 'e', GeomFromText('POINT(18 106)')),
+ ('z', 'u', 'n', GeomFromText('POINT(70 133)')),
+ ('j', 'n', 'x', GeomFromText('POINT(232 13)')),
+ ('e', 'h', 'f', GeomFromText('POINT(22 135)')),
+ ('w', 'l', 'f', GeomFromText('POINT(9 180)')),
+ ('a', 'v', 'q', GeomFromText('POINT(163 228)')),
+ ('i', 'z', 'o', GeomFromText('POINT(180 100)')),
+ ('e', 'c', 'l', GeomFromText('POINT(182 231)')),
+ ('c', 'k', 'o', GeomFromText('POINT(19 60)')),
+ ('q', 'f', 'p', GeomFromText('POINT(79 95)')),
+ ('m', 'd', 'r', GeomFromText('POINT(3 127)')),
+ ('m', 'e', 't', GeomFromText('POINT(136 154)')),
+ ('w', 'w', 'w', GeomFromText('POINT(102 15)')),
+ ('l', 'n', 'q', GeomFromText('POINT(71 196)')),
+ ('p', 'k', 'c', GeomFromText('POINT(47 139)')),
+ ('j', 'o', 'r', GeomFromText('POINT(177 128)')),
+ ('j', 'q', 'a', GeomFromText('POINT(170 6)')),
+ ('b', 'a', 'o', GeomFromText('POINT(63 211)')),
+ ('g', 's', 'o', GeomFromText('POINT(144 251)')),
+ ('w', 'u', 'w', GeomFromText('POINT(221 214)')),
+ ('g', 'a', 'm', GeomFromText('POINT(14 102)')),
+ ('u', 'q', 'z', GeomFromText('POINT(86 200)')),
+ ('k', 'a', 'm', GeomFromText('POINT(144 222)')),
+ ('j', 'u', 'r', GeomFromText('POINT(216 142)')),
+ ('q', 'k', 'v', GeomFromText('POINT(121 236)')),
+ ('p', 'o', 'r', GeomFromText('POINT(108 102)')),
+ ('b', 'd', 'x', GeomFromText('POINT(127 198)')),
+ ('k', 's', 'a', GeomFromText('POINT(2 150)')),
+ ('f', 'm', 'f', GeomFromText('POINT(160 191)')),
+ ('q', 'y', 'x', GeomFromText('POINT(98 111)')),
+ ('o', 'f', 'm', GeomFromText('POINT(232 218)')),
+ ('c', 'w', 'j', GeomFromText('POINT(156 165)')),
+ ('s', 'q', 'v', GeomFromText('POINT(98 161)'));
+SET @@RAND_SEED1=692635050, @@RAND_SEED2=297339954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=159925977, @@RAND_SEED2=942570618;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=328169745, @@RAND_SEED2=410451954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+CHECK TABLE t1 extended;
+UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(19 81)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(20 177)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(221 193)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(195 205)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(15 213)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(214 63)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(243 171)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(198 82)') where c1 like 'y%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('f', 'y', 'p', GeomFromText('POINT(109 235)')),
+ ('b', 'e', 'v', GeomFromText('POINT(20 48)')),
+ ('i', 'u', 'f', GeomFromText('POINT(15 55)')),
+ ('o', 'r', 'z', GeomFromText('POINT(105 64)')),
+ ('a', 'p', 'a', GeomFromText('POINT(142 236)')),
+ ('g', 'i', 'k', GeomFromText('POINT(10 49)')),
+ ('x', 'z', 'x', GeomFromText('POINT(192 200)')),
+ ('c', 'v', 'r', GeomFromText('POINT(94 168)')),
+ ('y', 'z', 'e', GeomFromText('POINT(141 51)')),
+ ('h', 'm', 'd', GeomFromText('POINT(35 251)')),
+ ('v', 'm', 'q', GeomFromText('POINT(44 90)')),
+ ('j', 'l', 'z', GeomFromText('POINT(67 237)')),
+ ('i', 'v', 'a', GeomFromText('POINT(75 14)')),
+ ('b', 'q', 't', GeomFromText('POINT(153 33)')),
+ ('e', 'm', 'a', GeomFromText('POINT(247 49)')),
+ ('l', 'y', 'g', GeomFromText('POINT(56 203)')),
+ ('v', 'o', 'r', GeomFromText('POINT(90 54)')),
+ ('r', 'n', 'd', GeomFromText('POINT(135 83)')),
+ ('j', 't', 'u', GeomFromText('POINT(174 239)')),
+ ('u', 'n', 'g', GeomFromText('POINT(104 191)')),
+ ('p', 'q', 'y', GeomFromText('POINT(63 171)')),
+ ('o', 'q', 'p', GeomFromText('POINT(192 103)')),
+ ('f', 'x', 'e', GeomFromText('POINT(244 30)')),
+ ('n', 'x', 'c', GeomFromText('POINT(92 103)')),
+ ('r', 'q', 'z', GeomFromText('POINT(166 20)')),
+ ('s', 'a', 'j', GeomFromText('POINT(137 205)')),
+ ('z', 't', 't', GeomFromText('POINT(99 134)')),
+ ('o', 'm', 'j', GeomFromText('POINT(217 3)')),
+ ('n', 'h', 'j', GeomFromText('POINT(211 17)')),
+ ('v', 'v', 'a', GeomFromText('POINT(41 137)')),
+ ('q', 'o', 'j', GeomFromText('POINT(5 92)')),
+ ('z', 'y', 'e', GeomFromText('POINT(175 212)')),
+ ('j', 'z', 'h', GeomFromText('POINT(224 194)')),
+ ('a', 'g', 'm', GeomFromText('POINT(31 119)')),
+ ('p', 'c', 'f', GeomFromText('POINT(17 221)')),
+ ('t', 'h', 'k', GeomFromText('POINT(26 203)')),
+ ('u', 'w', 'p', GeomFromText('POINT(47 185)')),
+ ('z', 'a', 'c', GeomFromText('POINT(61 133)')),
+ ('u', 'k', 'a', GeomFromText('POINT(210 115)')),
+ ('k', 'f', 'h', GeomFromText('POINT(125 113)')),
+ ('t', 'v', 'y', GeomFromText('POINT(12 239)')),
+ ('u', 'v', 'd', GeomFromText('POINT(90 24)')),
+ ('m', 'y', 'w', GeomFromText('POINT(25 243)')),
+ ('d', 'n', 'g', GeomFromText('POINT(122 92)')),
+ ('z', 'm', 'f', GeomFromText('POINT(235 110)')),
+ ('q', 'd', 'f', GeomFromText('POINT(233 217)')),
+ ('a', 'v', 'u', GeomFromText('POINT(69 59)')),
+ ('x', 'k', 'p', GeomFromText('POINT(240 14)')),
+ ('i', 'v', 'r', GeomFromText('POINT(154 42)')),
+ ('w', 'h', 'l', GeomFromText('POINT(178 156)')),
+ ('d', 'h', 'n', GeomFromText('POINT(65 157)')),
+ ('c', 'k', 'z', GeomFromText('POINT(62 33)')),
+ ('e', 'l', 'w', GeomFromText('POINT(162 1)')),
+ ('r', 'f', 'i', GeomFromText('POINT(127 71)')),
+ ('q', 'm', 'c', GeomFromText('POINT(63 118)')),
+ ('c', 'h', 'u', GeomFromText('POINT(205 203)')),
+ ('d', 't', 'p', GeomFromText('POINT(234 87)')),
+ ('s', 'g', 'h', GeomFromText('POINT(149 34)')),
+ ('o', 'b', 'q', GeomFromText('POINT(159 179)')),
+ ('k', 'u', 'f', GeomFromText('POINT(202 254)')),
+ ('u', 'f', 'g', GeomFromText('POINT(70 15)')),
+ ('x', 's', 'b', GeomFromText('POINT(25 181)')),
+ ('s', 'c', 'g', GeomFromText('POINT(252 17)')),
+ ('a', 'c', 'f', GeomFromText('POINT(89 67)')),
+ ('r', 'e', 'q', GeomFromText('POINT(55 54)')),
+ ('f', 'i', 'k', GeomFromText('POINT(178 230)')),
+ ('p', 'e', 'l', GeomFromText('POINT(198 28)')),
+ ('w', 'o', 'd', GeomFromText('POINT(204 189)')),
+ ('c', 'a', 'g', GeomFromText('POINT(230 178)')),
+ ('r', 'o', 'e', GeomFromText('POINT(61 116)')),
+ ('w', 'a', 'a', GeomFromText('POINT(178 237)')),
+ ('v', 'd', 'e', GeomFromText('POINT(70 85)')),
+ ('k', 'c', 'e', GeomFromText('POINT(147 118)')),
+ ('d', 'q', 't', GeomFromText('POINT(218 77)')),
+ ('k', 'g', 'f', GeomFromText('POINT(192 113)')),
+ ('w', 'n', 'e', GeomFromText('POINT(92 124)')),
+ ('r', 'm', 'q', GeomFromText('POINT(130 65)')),
+ ('o', 'r', 'r', GeomFromText('POINT(174 233)')),
+ ('k', 'n', 't', GeomFromText('POINT(175 147)')),
+ ('q', 'm', 'r', GeomFromText('POINT(18 208)')),
+ ('l', 'd', 'i', GeomFromText('POINT(13 104)')),
+ ('w', 'o', 'y', GeomFromText('POINT(207 39)')),
+ ('p', 'u', 'o', GeomFromText('POINT(114 31)')),
+ ('y', 'a', 'p', GeomFromText('POINT(106 59)')),
+ ('a', 'x', 'z', GeomFromText('POINT(17 57)')),
+ ('v', 'h', 'x', GeomFromText('POINT(170 13)')),
+ ('t', 's', 'u', GeomFromText('POINT(84 18)')),
+ ('z', 'z', 'f', GeomFromText('POINT(250 197)')),
+ ('l', 'z', 't', GeomFromText('POINT(59 80)')),
+ ('j', 'g', 's', GeomFromText('POINT(54 26)')),
+ ('g', 'v', 'm', GeomFromText('POINT(89 98)')),
+ ('q', 'v', 'b', GeomFromText('POINT(39 240)')),
+ ('x', 'k', 'v', GeomFromText('POINT(246 207)')),
+ ('k', 'u', 'i', GeomFromText('POINT(105 111)')),
+ ('w', 'z', 's', GeomFromText('POINT(235 8)')),
+ ('d', 'd', 'd', GeomFromText('POINT(105 4)')),
+ ('c', 'z', 'q', GeomFromText('POINT(13 140)')),
+ ('m', 'k', 'i', GeomFromText('POINT(208 120)')),
+ ('g', 'a', 'g', GeomFromText('POINT(9 182)')),
+ ('z', 'j', 'r', GeomFromText('POINT(149 153)')),
+ ('h', 'f', 'g', GeomFromText('POINT(81 236)')),
+ ('m', 'e', 'q', GeomFromText('POINT(209 215)')),
+ ('c', 'h', 'y', GeomFromText('POINT(235 70)')),
+ ('i', 'e', 'g', GeomFromText('POINT(138 26)')),
+ ('m', 't', 'u', GeomFromText('POINT(119 237)')),
+ ('o', 'w', 's', GeomFromText('POINT(193 166)')),
+ ('f', 'm', 'q', GeomFromText('POINT(85 96)')),
+ ('x', 'l', 'x', GeomFromText('POINT(58 115)')),
+ ('x', 'q', 'u', GeomFromText('POINT(108 210)')),
+ ('b', 'h', 'i', GeomFromText('POINT(250 139)')),
+ ('y', 'd', 'x', GeomFromText('POINT(199 135)')),
+ ('w', 'h', 'p', GeomFromText('POINT(247 233)')),
+ ('p', 'z', 't', GeomFromText('POINT(148 249)')),
+ ('q', 'a', 'u', GeomFromText('POINT(174 78)')),
+ ('v', 't', 'm', GeomFromText('POINT(70 228)')),
+ ('t', 'n', 'f', GeomFromText('POINT(123 2)')),
+ ('x', 't', 'b', GeomFromText('POINT(35 50)')),
+ ('r', 'j', 'f', GeomFromText('POINT(200 51)')),
+ ('s', 'q', 'o', GeomFromText('POINT(23 184)')),
+ ('u', 'v', 'z', GeomFromText('POINT(7 113)')),
+ ('v', 'u', 'l', GeomFromText('POINT(145 190)')),
+ ('o', 'k', 'i', GeomFromText('POINT(161 122)')),
+ ('l', 'y', 'e', GeomFromText('POINT(17 232)')),
+ ('t', 'b', 'e', GeomFromText('POINT(120 50)')),
+ ('e', 's', 'u', GeomFromText('POINT(254 1)')),
+ ('d', 'd', 'u', GeomFromText('POINT(167 140)')),
+ ('o', 'b', 'x', GeomFromText('POINT(186 237)')),
+ ('m', 's', 's', GeomFromText('POINT(172 149)')),
+ ('t', 'y', 'a', GeomFromText('POINT(149 85)')),
+ ('x', 't', 'r', GeomFromText('POINT(10 165)')),
+ ('g', 'c', 'e', GeomFromText('POINT(95 165)')),
+ ('e', 'e', 'z', GeomFromText('POINT(98 65)')),
+ ('f', 'v', 'i', GeomFromText('POINT(149 144)')),
+ ('o', 'p', 'm', GeomFromText('POINT(233 67)')),
+ ('t', 'u', 'b', GeomFromText('POINT(109 215)')),
+ ('o', 'o', 'b', GeomFromText('POINT(130 48)')),
+ ('e', 'm', 'h', GeomFromText('POINT(88 189)')),
+ ('e', 'v', 'y', GeomFromText('POINT(55 29)')),
+ ('e', 't', 'm', GeomFromText('POINT(129 55)')),
+ ('p', 'p', 'i', GeomFromText('POINT(126 222)')),
+ ('c', 'i', 'c', GeomFromText('POINT(19 158)')),
+ ('c', 'b', 's', GeomFromText('POINT(13 19)')),
+ ('u', 'y', 'a', GeomFromText('POINT(114 5)')),
+ ('a', 'o', 'f', GeomFromText('POINT(227 232)')),
+ ('t', 'c', 'z', GeomFromText('POINT(63 62)')),
+ ('d', 'o', 'k', GeomFromText('POINT(48 228)')),
+ ('x', 'c', 'e', GeomFromText('POINT(204 2)')),
+ ('e', 'e', 'g', GeomFromText('POINT(125 43)')),
+ ('o', 'r', 'f', GeomFromText('POINT(171 140)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(163 157)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(53 151)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(96 183)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(57 91)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 110)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
+check table t1 extended;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('b', 'c', 'e', GeomFromText('POINT(41 137)')),
+ ('p', 'y', 'k', GeomFromText('POINT(50 22)')),
+ ('s', 'c', 'h', GeomFromText('POINT(208 173)')),
+ ('x', 'u', 'l', GeomFromText('POINT(199 175)')),
+ ('s', 'r', 'h', GeomFromText('POINT(85 192)')),
+ ('j', 'k', 'u', GeomFromText('POINT(18 25)')),
+ ('p', 'w', 'h', GeomFromText('POINT(152 197)')),
+ ('e', 'd', 'c', GeomFromText('POINT(229 3)')),
+ ('o', 'x', 'k', GeomFromText('POINT(187 155)')),
+ ('o', 'b', 'k', GeomFromText('POINT(208 150)')),
+ ('d', 'a', 'j', GeomFromText('POINT(70 87)')),
+ ('f', 'e', 'k', GeomFromText('POINT(156 96)')),
+ ('u', 'y', 'p', GeomFromText('POINT(239 193)')),
+ ('n', 'v', 'p', GeomFromText('POINT(223 98)')),
+ ('z', 'j', 'r', GeomFromText('POINT(87 89)')),
+ ('h', 'x', 'x', GeomFromText('POINT(92 0)')),
+ ('r', 'v', 'r', GeomFromText('POINT(159 139)')),
+ ('v', 'g', 'g', GeomFromText('POINT(16 229)')),
+ ('z', 'k', 'u', GeomFromText('POINT(99 52)')),
+ ('p', 'p', 'o', GeomFromText('POINT(105 125)')),
+ ('w', 'h', 'y', GeomFromText('POINT(105 154)')),
+ ('v', 'y', 'z', GeomFromText('POINT(134 238)')),
+ ('x', 'o', 'o', GeomFromText('POINT(178 88)')),
+ ('z', 'w', 'd', GeomFromText('POINT(123 60)')),
+ ('q', 'f', 'u', GeomFromText('POINT(64 90)')),
+ ('s', 'n', 't', GeomFromText('POINT(50 138)')),
+ ('v', 'p', 't', GeomFromText('POINT(114 91)')),
+ ('a', 'o', 'n', GeomFromText('POINT(78 43)')),
+ ('k', 'u', 'd', GeomFromText('POINT(185 161)')),
+ ('w', 'd', 'n', GeomFromText('POINT(25 92)')),
+ ('k', 'w', 'a', GeomFromText('POINT(59 238)')),
+ ('t', 'c', 'f', GeomFromText('POINT(65 87)')),
+ ('g', 's', 'p', GeomFromText('POINT(238 126)')),
+ ('d', 'n', 'y', GeomFromText('POINT(107 173)')),
+ ('l', 'a', 'w', GeomFromText('POINT(125 152)')),
+ ('m', 'd', 'j', GeomFromText('POINT(146 53)')),
+ ('q', 'm', 'c', GeomFromText('POINT(217 187)')),
+ ('i', 'r', 'r', GeomFromText('POINT(6 113)')),
+ ('e', 'j', 'b', GeomFromText('POINT(37 83)')),
+ ('w', 'w', 'h', GeomFromText('POINT(83 199)')),
+ ('k', 'b', 's', GeomFromText('POINT(170 64)')),
+ ('s', 'b', 'c', GeomFromText('POINT(163 130)')),
+ ('c', 'h', 'a', GeomFromText('POINT(141 3)')),
+ ('k', 'j', 'u', GeomFromText('POINT(143 76)')),
+ ('r', 'h', 'o', GeomFromText('POINT(243 92)')),
+ ('i', 'd', 'b', GeomFromText('POINT(205 13)')),
+ ('r', 'y', 'q', GeomFromText('POINT(138 8)')),
+ ('m', 'o', 'i', GeomFromText('POINT(36 45)')),
+ ('v', 'g', 'm', GeomFromText('POINT(0 40)')),
+ ('f', 'e', 'i', GeomFromText('POINT(76 6)')),
+ ('c', 'q', 'q', GeomFromText('POINT(115 248)')),
+ ('x', 'c', 'i', GeomFromText('POINT(29 74)')),
+ ('l', 's', 't', GeomFromText('POINT(83 18)')),
+ ('t', 't', 'a', GeomFromText('POINT(26 168)')),
+ ('u', 'n', 'x', GeomFromText('POINT(200 110)')),
+ ('j', 'b', 'd', GeomFromText('POINT(216 136)')),
+ ('s', 'p', 'w', GeomFromText('POINT(38 156)')),
+ ('f', 'b', 'v', GeomFromText('POINT(29 186)')),
+ ('v', 'e', 'r', GeomFromText('POINT(149 40)')),
+ ('v', 't', 'm', GeomFromText('POINT(184 24)')),
+ ('y', 'g', 'a', GeomFromText('POINT(219 105)')),
+ ('s', 'f', 'i', GeomFromText('POINT(114 130)')),
+ ('e', 'q', 'h', GeomFromText('POINT(203 135)')),
+ ('h', 'g', 'b', GeomFromText('POINT(9 208)')),
+ ('o', 'l', 'r', GeomFromText('POINT(245 79)')),
+ ('s', 's', 'v', GeomFromText('POINT(238 198)')),
+ ('w', 'w', 'z', GeomFromText('POINT(209 232)')),
+ ('v', 'd', 'n', GeomFromText('POINT(30 193)')),
+ ('q', 'w', 'k', GeomFromText('POINT(133 18)')),
+ ('o', 'h', 'o', GeomFromText('POINT(42 140)')),
+ ('f', 'f', 'h', GeomFromText('POINT(145 1)')),
+ ('u', 's', 'r', GeomFromText('POINT(70 62)')),
+ ('x', 'n', 'q', GeomFromText('POINT(33 86)')),
+ ('u', 'p', 'v', GeomFromText('POINT(232 220)')),
+ ('z', 'e', 'a', GeomFromText('POINT(130 69)')),
+ ('r', 'u', 'z', GeomFromText('POINT(243 241)')),
+ ('b', 'n', 't', GeomFromText('POINT(120 12)')),
+ ('u', 'f', 's', GeomFromText('POINT(190 212)')),
+ ('a', 'd', 'q', GeomFromText('POINT(235 191)')),
+ ('f', 'q', 'm', GeomFromText('POINT(176 2)')),
+ ('n', 'c', 's', GeomFromText('POINT(218 163)')),
+ ('e', 'm', 'h', GeomFromText('POINT(163 108)')),
+ ('c', 'f', 'l', GeomFromText('POINT(220 115)')),
+ ('c', 'v', 'q', GeomFromText('POINT(66 45)')),
+ ('w', 'v', 'x', GeomFromText('POINT(251 220)')),
+ ('f', 'w', 'z', GeomFromText('POINT(146 149)')),
+ ('h', 'n', 'h', GeomFromText('POINT(148 128)')),
+ ('y', 'k', 'v', GeomFromText('POINT(28 110)')),
+ ('c', 'x', 'q', GeomFromText('POINT(13 13)')),
+ ('e', 'd', 's', GeomFromText('POINT(91 190)')),
+ ('c', 'w', 'c', GeomFromText('POINT(10 231)')),
+ ('u', 'j', 'n', GeomFromText('POINT(250 21)')),
+ ('w', 'n', 'x', GeomFromText('POINT(141 69)')),
+ ('f', 'p', 'y', GeomFromText('POINT(228 246)')),
+ ('d', 'q', 'f', GeomFromText('POINT(194 22)')),
+ ('d', 'z', 'l', GeomFromText('POINT(233 181)')),
+ ('c', 'a', 'q', GeomFromText('POINT(183 96)')),
+ ('m', 'i', 'd', GeomFromText('POINT(117 226)')),
+ ('z', 'y', 'y', GeomFromText('POINT(62 81)')),
+ ('g', 'v', 'm', GeomFromText('POINT(66 158)'));
+check table t1 extended;
+SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1072017234, @@RAND_SEED2=484203885;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=358851897, @@RAND_SEED2=358495224;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=509031459, @@RAND_SEED2=675962925;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(61 203)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 194)') where c1 like 'f%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(228 18)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 18)') where c1 like 'l%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(176 94)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(44 47)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 191)') where c1 like 'b%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(179 218)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(239 40)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(248 41)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(167 82)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(13 104)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(139 84)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(145 108)') where c1 like 'p%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(147 57)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(217 144)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(160 224)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(38 28)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(104 114)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 19)') where c1 like 'c%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('f', 'x', 'p', GeomFromText('POINT(92 181)')),
+ ('s', 'i', 'c', GeomFromText('POINT(49 60)')),
+ ('c', 'c', 'i', GeomFromText('POINT(7 57)')),
+ ('n', 'g', 'k', GeomFromText('POINT(252 105)')),
+ ('g', 'b', 'm', GeomFromText('POINT(180 11)')),
+ ('u', 'l', 'r', GeomFromText('POINT(32 90)')),
+ ('c', 'x', 'e', GeomFromText('POINT(143 24)')),
+ ('x', 'u', 'a', GeomFromText('POINT(123 92)')),
+ ('s', 'b', 'h', GeomFromText('POINT(190 108)')),
+ ('c', 'x', 'b', GeomFromText('POINT(104 100)')),
+ ('i', 'd', 't', GeomFromText('POINT(214 104)')),
+ ('r', 'w', 'g', GeomFromText('POINT(29 67)')),
+ ('b', 'f', 'g', GeomFromText('POINT(149 46)')),
+ ('r', 'r', 'd', GeomFromText('POINT(242 196)')),
+ ('j', 'l', 'a', GeomFromText('POINT(90 196)')),
+ ('e', 't', 'b', GeomFromText('POINT(190 64)')),
+ ('l', 'x', 'w', GeomFromText('POINT(250 73)')),
+ ('q', 'y', 'r', GeomFromText('POINT(120 182)')),
+ ('s', 'j', 'a', GeomFromText('POINT(180 175)')),
+ ('n', 'i', 'y', GeomFromText('POINT(124 136)')),
+ ('s', 'x', 's', GeomFromText('POINT(176 209)')),
+ ('u', 'f', 's', GeomFromText('POINT(215 173)')),
+ ('m', 'j', 'x', GeomFromText('POINT(44 140)')),
+ ('v', 'g', 'x', GeomFromText('POINT(177 233)')),
+ ('u', 't', 'b', GeomFromText('POINT(136 197)')),
+ ('f', 'g', 'b', GeomFromText('POINT(10 8)')),
+ ('v', 'c', 'j', GeomFromText('POINT(13 81)')),
+ ('d', 's', 'q', GeomFromText('POINT(200 100)')),
+ ('a', 'p', 'j', GeomFromText('POINT(33 40)')),
+ ('i', 'c', 'g', GeomFromText('POINT(168 204)')),
+ ('k', 'h', 'i', GeomFromText('POINT(93 243)')),
+ ('s', 'b', 's', GeomFromText('POINT(157 13)')),
+ ('v', 'l', 'l', GeomFromText('POINT(103 6)')),
+ ('r', 'b', 'k', GeomFromText('POINT(244 137)')),
+ ('l', 'd', 'r', GeomFromText('POINT(162 254)')),
+ ('q', 'b', 'z', GeomFromText('POINT(136 246)')),
+ ('x', 'x', 'p', GeomFromText('POINT(120 37)')),
+ ('m', 'e', 'z', GeomFromText('POINT(203 167)')),
+ ('q', 'n', 'p', GeomFromText('POINT(94 119)')),
+ ('b', 'g', 'u', GeomFromText('POINT(93 248)')),
+ ('r', 'v', 'v', GeomFromText('POINT(53 88)')),
+ ('y', 'a', 'i', GeomFromText('POINT(98 219)')),
+ ('a', 's', 'g', GeomFromText('POINT(173 138)')),
+ ('c', 'a', 't', GeomFromText('POINT(235 135)')),
+ ('q', 'm', 'd', GeomFromText('POINT(224 208)')),
+ ('e', 'p', 'k', GeomFromText('POINT(161 238)')),
+ ('n', 'g', 'q', GeomFromText('POINT(35 204)')),
+ ('t', 't', 'x', GeomFromText('POINT(230 178)')),
+ ('w', 'f', 'a', GeomFromText('POINT(150 221)')),
+ ('z', 'm', 'z', GeomFromText('POINT(119 42)')),
+ ('l', 'j', 's', GeomFromText('POINT(97 96)')),
+ ('f', 'z', 'x', GeomFromText('POINT(208 65)')),
+ ('i', 'v', 'c', GeomFromText('POINT(145 79)')),
+ ('l', 'f', 'k', GeomFromText('POINT(83 234)')),
+ ('u', 'a', 's', GeomFromText('POINT(250 49)')),
+ ('o', 'k', 'p', GeomFromText('POINT(46 50)')),
+ ('d', 'e', 'z', GeomFromText('POINT(30 198)')),
+ ('r', 'r', 'l', GeomFromText('POINT(78 189)')),
+ ('y', 'l', 'f', GeomFromText('POINT(188 132)')),
+ ('d', 'q', 'm', GeomFromText('POINT(247 107)')),
+ ('p', 'j', 'n', GeomFromText('POINT(148 227)')),
+ ('b', 'o', 'i', GeomFromText('POINT(172 25)')),
+ ('e', 'v', 'd', GeomFromText('POINT(94 248)')),
+ ('q', 'd', 'f', GeomFromText('POINT(15 29)')),
+ ('w', 'b', 'b', GeomFromText('POINT(74 111)')),
+ ('g', 'q', 'f', GeomFromText('POINT(107 215)')),
+ ('o', 'h', 'r', GeomFromText('POINT(25 168)')),
+ ('u', 't', 'w', GeomFromText('POINT(251 188)')),
+ ('h', 's', 'w', GeomFromText('POINT(254 247)')),
+ ('f', 'f', 'b', GeomFromText('POINT(166 103)'));
+SET @@RAND_SEED1=866613816, @@RAND_SEED2=92289615;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('l', 'c', 'l', GeomFromText('POINT(202 98)')),
+ ('k', 'c', 'b', GeomFromText('POINT(46 206)')),
+ ('r', 'y', 'm', GeomFromText('POINT(74 140)')),
+ ('y', 'z', 'd', GeomFromText('POINT(200 160)')),
+ ('s', 'y', 's', GeomFromText('POINT(156 205)')),
+ ('u', 'v', 'p', GeomFromText('POINT(86 82)')),
+ ('j', 's', 's', GeomFromText('POINT(91 233)')),
+ ('x', 'j', 'f', GeomFromText('POINT(3 14)')),
+ ('l', 'z', 'v', GeomFromText('POINT(123 156)')),
+ ('h', 'i', 'o', GeomFromText('POINT(145 229)')),
+ ('o', 'r', 'd', GeomFromText('POINT(15 22)')),
+ ('f', 'x', 't', GeomFromText('POINT(21 60)')),
+ ('t', 'g', 'h', GeomFromText('POINT(50 153)')),
+ ('g', 'u', 'b', GeomFromText('POINT(82 85)')),
+ ('v', 'a', 'p', GeomFromText('POINT(231 178)')),
+ ('n', 'v', 'o', GeomFromText('POINT(183 25)')),
+ ('j', 'n', 'm', GeomFromText('POINT(50 144)')),
+ ('e', 'f', 'i', GeomFromText('POINT(46 16)')),
+ ('d', 'w', 'a', GeomFromText('POINT(66 6)')),
+ ('f', 'x', 'a', GeomFromText('POINT(107 197)')),
+ ('m', 'o', 'a', GeomFromText('POINT(142 80)')),
+ ('q', 'l', 'g', GeomFromText('POINT(251 23)')),
+ ('c', 's', 's', GeomFromText('POINT(158 43)')),
+ ('y', 'd', 'o', GeomFromText('POINT(196 228)')),
+ ('d', 'p', 'l', GeomFromText('POINT(107 5)')),
+ ('h', 'a', 'b', GeomFromText('POINT(183 166)')),
+ ('m', 'w', 'p', GeomFromText('POINT(19 59)')),
+ ('b', 'y', 'o', GeomFromText('POINT(178 30)')),
+ ('x', 'w', 'i', GeomFromText('POINT(168 94)')),
+ ('t', 'k', 'z', GeomFromText('POINT(171 5)')),
+ ('r', 'm', 'a', GeomFromText('POINT(222 19)')),
+ ('u', 'v', 'e', GeomFromText('POINT(224 80)')),
+ ('q', 'r', 'k', GeomFromText('POINT(212 218)')),
+ ('d', 'p', 'j', GeomFromText('POINT(169 7)')),
+ ('d', 'r', 'v', GeomFromText('POINT(193 23)')),
+ ('n', 'y', 'y', GeomFromText('POINT(130 178)')),
+ ('m', 'z', 'r', GeomFromText('POINT(81 200)')),
+ ('j', 'e', 'w', GeomFromText('POINT(145 239)')),
+ ('v', 'h', 'x', GeomFromText('POINT(24 105)')),
+ ('z', 'm', 'a', GeomFromText('POINT(175 129)')),
+ ('b', 'c', 'v', GeomFromText('POINT(213 10)')),
+ ('t', 't', 'u', GeomFromText('POINT(2 129)')),
+ ('r', 's', 'v', GeomFromText('POINT(209 192)')),
+ ('x', 'p', 'g', GeomFromText('POINT(43 63)')),
+ ('t', 'e', 'u', GeomFromText('POINT(139 210)')),
+ ('l', 'e', 't', GeomFromText('POINT(245 148)')),
+ ('a', 'i', 'k', GeomFromText('POINT(167 195)')),
+ ('m', 'o', 'h', GeomFromText('POINT(206 120)')),
+ ('g', 'z', 's', GeomFromText('POINT(169 240)')),
+ ('z', 'u', 's', GeomFromText('POINT(202 120)')),
+ ('i', 'b', 'a', GeomFromText('POINT(216 18)')),
+ ('w', 'y', 'g', GeomFromText('POINT(119 236)')),
+ ('h', 'y', 'p', GeomFromText('POINT(161 24)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(33 100)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(41 46)') where c1 like 'f%';
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Bug #30286 spatial index cause corruption and server crash!
+#
+
+create table t1 (a geometry not null, spatial index(a)) row_format=dynamic;
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072)));
+insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0)));
+insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241)));
+insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231)));
+insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260)));
+insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125)));
+insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29)));
+insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86)));
+insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130)));
+insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34)));
+insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183)));
+insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178)));
+drop table t1;
+
+# End of 4.1 tests
+
+#
+# bug #21790 (UNKNOWN ERROR on NULLs in RTree)
+#
+CREATE TABLE t1(foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) row_format=dynamic;
+--error 1048
+INSERT INTO t1(foo) VALUES (NULL);
+--error 1416
+INSERT INTO t1() VALUES ();
+--error 1416
+INSERT INTO t1(foo) VALUES ('');
+DROP TABLE t1;
+
+#
+# Bug #23578: Corruption prevents Optimize table from working properly with a
+# spatial index
+#
+
+CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)) row_format=dynamic;
+
+INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)'));
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+
+OPTIMIZE TABLE t1;
+DROP TABLE t1;
+
+
+#
+# Bug #29070: Error in spatial index
+#
+
+CREATE TABLE t1 (a INT, b GEOMETRY NOT NULL, SPATIAL KEY b(b)) row_format=dynamic;
+INSERT INTO t1 VALUES (1, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+INSERT INTO t1 VALUES (2, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+
+# must return the same number as the next select
+SELECT COUNT(*) FROM t1 WHERE
+ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE
+ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+
+DROP TABLE t1;
+
+--echo End of 5.0 tests.
diff --git a/mysql-test/suite/maria/t/maria-gis-rtree-trans.test b/mysql-test/suite/maria/t/maria-gis-rtree-trans.test
new file mode 100644
index 00000000000..f530699c755
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-gis-rtree-trans.test
@@ -0,0 +1,891 @@
+# Because state.key_root is updated differently between transactional
+# and non-trans tables, we have several maria-gis-rtree-* tests.
+
+-- source include/have_maria.inc
+-- source include/have_geometry.inc
+
+set storage_engine=maria;
+
+#
+# test of rtree (using with spatial data)
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+CREATE TABLE t1 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL,
+ SPATIAL KEY(g)
+) transactional=1 row_format=page;
+
+SHOW CREATE TABLE t1;
+
+let $1=150;
+let $2=150;
+while ($1)
+{
+ eval INSERT INTO t1 (g) VALUES (GeomFromText('LineString($1 $1, $2 $2)'));
+ dec $1;
+ inc $2;
+}
+
+SELECT count(*) FROM t1;
+EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+
+DROP TABLE t1;
+
+CREATE TABLE t2 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL
+) transactional=1 row_format=page;
+
+let $1=10;
+while ($1)
+{
+ let $2=10;
+ while ($2)
+ {
+ eval INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10))));
+ dec $2;
+ }
+ dec $1;
+}
+
+ALTER TABLE t2 ADD SPATIAL KEY(g);
+SHOW CREATE TABLE t2;
+SELECT count(*) FROM t2;
+EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+ GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+ GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+
+let $1=10;
+while ($1)
+{
+ let $2=10;
+ while ($2)
+ {
+ eval DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10)))));
+ SELECT count(*) FROM t2;
+ dec $2;
+ }
+ dec $1;
+}
+
+DROP TABLE t2;
+
+drop table if exists t1;
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a)) transactional=1 row_format=page;
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+analyze table t1;
+drop table t1;
+
+#
+# The following crashed gis
+#
+
+CREATE TABLE t1 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL,
+ SPATIAL KEY(g)
+) transactional=1 row_format=page;
+
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
+#select * from t1 where g<GeomFromText('LineString(1 2, 2 3)');
+drop table t1;
+
+CREATE TABLE t1 (
+ line LINESTRING NOT NULL,
+ kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+ name VARCHAR(32),
+
+ SPATIAL KEY (line)
+
+
+) transactional=1 row_format=page;
+
+ALTER TABLE t1 DISABLE KEYS;
+
+INSERT INTO t1 (name, kind, line) VALUES
+ ("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+ ("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+ ("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+ ("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+ ("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+ ("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+ ("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+ ("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+ ("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+ ("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+ ("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+ ("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+ ("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+ ("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+ ("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+ ("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+ ("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+ ("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+ ("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+ ("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+ ("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+ ("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+ ("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+
+ALTER TABLE t1 ENABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES ("austria", "pp", GeomFromText('LINESTRING(14.9906 48.9887,14.9946 48.9904,14.9947 48.9916)'));
+drop table t1;
+
+CREATE TABLE t1 (st varchar(100));
+INSERT INTO t1 VALUES ("Fake string");
+CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)) transactional=1 row_format=page;
+--error 1416
+INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
+drop table t1, t2;
+
+CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) transactional=1 row_format=page DEFAULT CHARSET=latin1;
+
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
+-66.8158332999, -18.7186111000 -66.8102777000, -18.7211111000 -66.9269443999,
+-18.6086111000 -66.9327777000))'));
+
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-65.7402776999 -96.6686111000, -65.7372222000
+-96.5516666000, -65.8502777000 -96.5461111000, -65.8527777000 -96.6627777000,
+-65.7402776999 -96.6686111000))'));
+check table t1 extended;
+
+drop table t1;
+
+#
+# Bug#17877 - Corrupted spatial index
+#
+CREATE TABLE t1 (
+ c1 geometry NOT NULL default '',
+ SPATIAL KEY i1 (c1)
+) transactional=1 row_format=page DEFAULT CHARSET=latin1;
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+# This showed a missing key.
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+#
+CREATE TABLE t1 (
+ c1 geometry NOT NULL default '',
+ SPATIAL KEY i1 (c1)
+) transactional=1 row_format=page DEFAULT CHARSET=latin1;
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-65.7402776999 -96.6686111000,
+ -65.7372222000 -96.5516666000,
+ -65.8502777000 -96.5461111000,
+ -65.8527777000 -96.6627777000,
+ -65.7402776999 -96.6686111000))'));
+# This is the same as the first insert to get a non-unique key.
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+# This showed (and still shows) OK.
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Bug #21888: Query on GEOMETRY field using PointFromWKB() results in lost connection
+#
+CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=1 row_format=page;
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
+SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
+DROP TABLE t1;
+
+#
+# Bug#25673 - spatial index corruption, error 126 incorrect key file for table
+#
+CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
+ c2 varchar(15) collate utf8_bin default NULL,
+ c1 varchar(15) collate utf8_bin default NULL,
+ c3 varchar(10) collate utf8_bin default NULL,
+ spatial_point point NOT NULL,
+ PRIMARY KEY(id),
+ SPATIAL KEY (spatial_point)
+ )transactional=1 row_format=page DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+#
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('y', 's', 'j', GeomFromText('POINT(167 74)')),
+ ('r', 'n', 'd', GeomFromText('POINT(215 118)')),
+ ('g', 'n', 'e', GeomFromText('POINT(203 98)')),
+ ('h', 'd', 'd', GeomFromText('POINT(54 193)')),
+ ('r', 'x', 'y', GeomFromText('POINT(47 69)')),
+ ('t', 'q', 'r', GeomFromText('POINT(109 42)')),
+ ('a', 'z', 'd', GeomFromText('POINT(0 154)')),
+ ('x', 'v', 'o', GeomFromText('POINT(174 131)')),
+ ('b', 'r', 'a', GeomFromText('POINT(114 253)')),
+ ('x', 'z', 'i', GeomFromText('POINT(163 21)')),
+ ('w', 'p', 'i', GeomFromText('POINT(42 102)')),
+ ('g', 'j', 'j', GeomFromText('POINT(170 133)')),
+ ('m', 'g', 'n', GeomFromText('POINT(28 22)')),
+ ('b', 'z', 'h', GeomFromText('POINT(174 28)')),
+ ('q', 'k', 'f', GeomFromText('POINT(233 73)')),
+ ('w', 'w', 'a', GeomFromText('POINT(124 200)')),
+ ('t', 'j', 'w', GeomFromText('POINT(252 101)')),
+ ('d', 'r', 'd', GeomFromText('POINT(98 18)')),
+ ('w', 'o', 'y', GeomFromText('POINT(165 31)')),
+ ('y', 'h', 't', GeomFromText('POINT(14 220)')),
+ ('d', 'p', 'u', GeomFromText('POINT(223 196)')),
+ ('g', 'y', 'g', GeomFromText('POINT(207 96)')),
+ ('x', 'm', 'n', GeomFromText('POINT(214 3)')),
+ ('g', 'v', 'e', GeomFromText('POINT(140 205)')),
+ ('g', 'm', 'm', GeomFromText('POINT(10 236)')),
+ ('i', 'r', 'j', GeomFromText('POINT(137 228)')),
+ ('w', 's', 'p', GeomFromText('POINT(115 6)')),
+ ('o', 'n', 'k', GeomFromText('POINT(158 129)')),
+ ('j', 'h', 'l', GeomFromText('POINT(129 72)')),
+ ('f', 'x', 'l', GeomFromText('POINT(139 207)')),
+ ('u', 'd', 'n', GeomFromText('POINT(125 109)')),
+ ('b', 'a', 'z', GeomFromText('POINT(30 32)')),
+ ('m', 'h', 'o', GeomFromText('POINT(251 251)')),
+ ('f', 'r', 'd', GeomFromText('POINT(243 211)')),
+ ('b', 'd', 'r', GeomFromText('POINT(232 80)')),
+ ('g', 'k', 'v', GeomFromText('POINT(15 100)')),
+ ('i', 'f', 'c', GeomFromText('POINT(109 66)')),
+ ('r', 't', 'j', GeomFromText('POINT(178 6)')),
+ ('y', 'n', 'f', GeomFromText('POINT(233 211)')),
+ ('f', 'y', 'm', GeomFromText('POINT(99 16)')),
+ ('z', 'q', 'l', GeomFromText('POINT(39 49)')),
+ ('j', 'c', 'r', GeomFromText('POINT(75 187)')),
+ ('c', 'y', 'y', GeomFromText('POINT(246 253)')),
+ ('w', 'u', 'd', GeomFromText('POINT(56 190)')),
+ ('n', 'q', 'm', GeomFromText('POINT(73 149)')),
+ ('d', 'y', 'a', GeomFromText('POINT(134 6)')),
+ ('z', 's', 'w', GeomFromText('POINT(216 225)')),
+ ('d', 'u', 'k', GeomFromText('POINT(132 70)')),
+ ('f', 'v', 't', GeomFromText('POINT(187 141)')),
+ ('r', 'r', 'a', GeomFromText('POINT(152 39)')),
+ ('y', 'p', 'o', GeomFromText('POINT(45 27)')),
+ ('p', 'n', 'm', GeomFromText('POINT(228 148)')),
+ ('e', 'g', 'e', GeomFromText('POINT(88 81)')),
+ ('m', 'a', 'h', GeomFromText('POINT(35 29)')),
+ ('m', 'h', 'f', GeomFromText('POINT(30 71)')),
+ ('h', 'k', 'i', GeomFromText('POINT(244 78)')),
+ ('z', 'v', 'd', GeomFromText('POINT(241 38)')),
+ ('q', 'l', 'j', GeomFromText('POINT(13 71)')),
+ ('s', 'p', 'g', GeomFromText('POINT(108 38)')),
+ ('q', 's', 'j', GeomFromText('POINT(92 101)')),
+ ('l', 'h', 'g', GeomFromText('POINT(120 78)')),
+ ('w', 't', 'b', GeomFromText('POINT(193 109)')),
+ ('b', 's', 's', GeomFromText('POINT(223 211)')),
+ ('w', 'w', 'y', GeomFromText('POINT(122 42)')),
+ ('q', 'c', 'c', GeomFromText('POINT(104 102)')),
+ ('w', 'g', 'n', GeomFromText('POINT(213 120)')),
+ ('p', 'q', 'a', GeomFromText('POINT(247 148)')),
+ ('c', 'z', 'e', GeomFromText('POINT(18 106)')),
+ ('z', 'u', 'n', GeomFromText('POINT(70 133)')),
+ ('j', 'n', 'x', GeomFromText('POINT(232 13)')),
+ ('e', 'h', 'f', GeomFromText('POINT(22 135)')),
+ ('w', 'l', 'f', GeomFromText('POINT(9 180)')),
+ ('a', 'v', 'q', GeomFromText('POINT(163 228)')),
+ ('i', 'z', 'o', GeomFromText('POINT(180 100)')),
+ ('e', 'c', 'l', GeomFromText('POINT(182 231)')),
+ ('c', 'k', 'o', GeomFromText('POINT(19 60)')),
+ ('q', 'f', 'p', GeomFromText('POINT(79 95)')),
+ ('m', 'd', 'r', GeomFromText('POINT(3 127)')),
+ ('m', 'e', 't', GeomFromText('POINT(136 154)')),
+ ('w', 'w', 'w', GeomFromText('POINT(102 15)')),
+ ('l', 'n', 'q', GeomFromText('POINT(71 196)')),
+ ('p', 'k', 'c', GeomFromText('POINT(47 139)')),
+ ('j', 'o', 'r', GeomFromText('POINT(177 128)')),
+ ('j', 'q', 'a', GeomFromText('POINT(170 6)')),
+ ('b', 'a', 'o', GeomFromText('POINT(63 211)')),
+ ('g', 's', 'o', GeomFromText('POINT(144 251)')),
+ ('w', 'u', 'w', GeomFromText('POINT(221 214)')),
+ ('g', 'a', 'm', GeomFromText('POINT(14 102)')),
+ ('u', 'q', 'z', GeomFromText('POINT(86 200)')),
+ ('k', 'a', 'm', GeomFromText('POINT(144 222)')),
+ ('j', 'u', 'r', GeomFromText('POINT(216 142)')),
+ ('q', 'k', 'v', GeomFromText('POINT(121 236)')),
+ ('p', 'o', 'r', GeomFromText('POINT(108 102)')),
+ ('b', 'd', 'x', GeomFromText('POINT(127 198)')),
+ ('k', 's', 'a', GeomFromText('POINT(2 150)')),
+ ('f', 'm', 'f', GeomFromText('POINT(160 191)')),
+ ('q', 'y', 'x', GeomFromText('POINT(98 111)')),
+ ('o', 'f', 'm', GeomFromText('POINT(232 218)')),
+ ('c', 'w', 'j', GeomFromText('POINT(156 165)')),
+ ('s', 'q', 'v', GeomFromText('POINT(98 161)'));
+SET @@RAND_SEED1=692635050, @@RAND_SEED2=297339954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=159925977, @@RAND_SEED2=942570618;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=328169745, @@RAND_SEED2=410451954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(19 81)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(20 177)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(221 193)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(195 205)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(15 213)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(214 63)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(243 171)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(198 82)') where c1 like 'y%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('f', 'y', 'p', GeomFromText('POINT(109 235)')),
+ ('b', 'e', 'v', GeomFromText('POINT(20 48)')),
+ ('i', 'u', 'f', GeomFromText('POINT(15 55)')),
+ ('o', 'r', 'z', GeomFromText('POINT(105 64)')),
+ ('a', 'p', 'a', GeomFromText('POINT(142 236)')),
+ ('g', 'i', 'k', GeomFromText('POINT(10 49)')),
+ ('x', 'z', 'x', GeomFromText('POINT(192 200)')),
+ ('c', 'v', 'r', GeomFromText('POINT(94 168)')),
+ ('y', 'z', 'e', GeomFromText('POINT(141 51)')),
+ ('h', 'm', 'd', GeomFromText('POINT(35 251)')),
+ ('v', 'm', 'q', GeomFromText('POINT(44 90)')),
+ ('j', 'l', 'z', GeomFromText('POINT(67 237)')),
+ ('i', 'v', 'a', GeomFromText('POINT(75 14)')),
+ ('b', 'q', 't', GeomFromText('POINT(153 33)')),
+ ('e', 'm', 'a', GeomFromText('POINT(247 49)')),
+ ('l', 'y', 'g', GeomFromText('POINT(56 203)')),
+ ('v', 'o', 'r', GeomFromText('POINT(90 54)')),
+ ('r', 'n', 'd', GeomFromText('POINT(135 83)')),
+ ('j', 't', 'u', GeomFromText('POINT(174 239)')),
+ ('u', 'n', 'g', GeomFromText('POINT(104 191)')),
+ ('p', 'q', 'y', GeomFromText('POINT(63 171)')),
+ ('o', 'q', 'p', GeomFromText('POINT(192 103)')),
+ ('f', 'x', 'e', GeomFromText('POINT(244 30)')),
+ ('n', 'x', 'c', GeomFromText('POINT(92 103)')),
+ ('r', 'q', 'z', GeomFromText('POINT(166 20)')),
+ ('s', 'a', 'j', GeomFromText('POINT(137 205)')),
+ ('z', 't', 't', GeomFromText('POINT(99 134)')),
+ ('o', 'm', 'j', GeomFromText('POINT(217 3)')),
+ ('n', 'h', 'j', GeomFromText('POINT(211 17)')),
+ ('v', 'v', 'a', GeomFromText('POINT(41 137)')),
+ ('q', 'o', 'j', GeomFromText('POINT(5 92)')),
+ ('z', 'y', 'e', GeomFromText('POINT(175 212)')),
+ ('j', 'z', 'h', GeomFromText('POINT(224 194)')),
+ ('a', 'g', 'm', GeomFromText('POINT(31 119)')),
+ ('p', 'c', 'f', GeomFromText('POINT(17 221)')),
+ ('t', 'h', 'k', GeomFromText('POINT(26 203)')),
+ ('u', 'w', 'p', GeomFromText('POINT(47 185)')),
+ ('z', 'a', 'c', GeomFromText('POINT(61 133)')),
+ ('u', 'k', 'a', GeomFromText('POINT(210 115)')),
+ ('k', 'f', 'h', GeomFromText('POINT(125 113)')),
+ ('t', 'v', 'y', GeomFromText('POINT(12 239)')),
+ ('u', 'v', 'd', GeomFromText('POINT(90 24)')),
+ ('m', 'y', 'w', GeomFromText('POINT(25 243)')),
+ ('d', 'n', 'g', GeomFromText('POINT(122 92)')),
+ ('z', 'm', 'f', GeomFromText('POINT(235 110)')),
+ ('q', 'd', 'f', GeomFromText('POINT(233 217)')),
+ ('a', 'v', 'u', GeomFromText('POINT(69 59)')),
+ ('x', 'k', 'p', GeomFromText('POINT(240 14)')),
+ ('i', 'v', 'r', GeomFromText('POINT(154 42)')),
+ ('w', 'h', 'l', GeomFromText('POINT(178 156)')),
+ ('d', 'h', 'n', GeomFromText('POINT(65 157)')),
+ ('c', 'k', 'z', GeomFromText('POINT(62 33)')),
+ ('e', 'l', 'w', GeomFromText('POINT(162 1)')),
+ ('r', 'f', 'i', GeomFromText('POINT(127 71)')),
+ ('q', 'm', 'c', GeomFromText('POINT(63 118)')),
+ ('c', 'h', 'u', GeomFromText('POINT(205 203)')),
+ ('d', 't', 'p', GeomFromText('POINT(234 87)')),
+ ('s', 'g', 'h', GeomFromText('POINT(149 34)')),
+ ('o', 'b', 'q', GeomFromText('POINT(159 179)')),
+ ('k', 'u', 'f', GeomFromText('POINT(202 254)')),
+ ('u', 'f', 'g', GeomFromText('POINT(70 15)')),
+ ('x', 's', 'b', GeomFromText('POINT(25 181)')),
+ ('s', 'c', 'g', GeomFromText('POINT(252 17)')),
+ ('a', 'c', 'f', GeomFromText('POINT(89 67)')),
+ ('r', 'e', 'q', GeomFromText('POINT(55 54)')),
+ ('f', 'i', 'k', GeomFromText('POINT(178 230)')),
+ ('p', 'e', 'l', GeomFromText('POINT(198 28)')),
+ ('w', 'o', 'd', GeomFromText('POINT(204 189)')),
+ ('c', 'a', 'g', GeomFromText('POINT(230 178)')),
+ ('r', 'o', 'e', GeomFromText('POINT(61 116)')),
+ ('w', 'a', 'a', GeomFromText('POINT(178 237)')),
+ ('v', 'd', 'e', GeomFromText('POINT(70 85)')),
+ ('k', 'c', 'e', GeomFromText('POINT(147 118)')),
+ ('d', 'q', 't', GeomFromText('POINT(218 77)')),
+ ('k', 'g', 'f', GeomFromText('POINT(192 113)')),
+ ('w', 'n', 'e', GeomFromText('POINT(92 124)')),
+ ('r', 'm', 'q', GeomFromText('POINT(130 65)')),
+ ('o', 'r', 'r', GeomFromText('POINT(174 233)')),
+ ('k', 'n', 't', GeomFromText('POINT(175 147)')),
+ ('q', 'm', 'r', GeomFromText('POINT(18 208)')),
+ ('l', 'd', 'i', GeomFromText('POINT(13 104)')),
+ ('w', 'o', 'y', GeomFromText('POINT(207 39)')),
+ ('p', 'u', 'o', GeomFromText('POINT(114 31)')),
+ ('y', 'a', 'p', GeomFromText('POINT(106 59)')),
+ ('a', 'x', 'z', GeomFromText('POINT(17 57)')),
+ ('v', 'h', 'x', GeomFromText('POINT(170 13)')),
+ ('t', 's', 'u', GeomFromText('POINT(84 18)')),
+ ('z', 'z', 'f', GeomFromText('POINT(250 197)')),
+ ('l', 'z', 't', GeomFromText('POINT(59 80)')),
+ ('j', 'g', 's', GeomFromText('POINT(54 26)')),
+ ('g', 'v', 'm', GeomFromText('POINT(89 98)')),
+ ('q', 'v', 'b', GeomFromText('POINT(39 240)')),
+ ('x', 'k', 'v', GeomFromText('POINT(246 207)')),
+ ('k', 'u', 'i', GeomFromText('POINT(105 111)')),
+ ('w', 'z', 's', GeomFromText('POINT(235 8)')),
+ ('d', 'd', 'd', GeomFromText('POINT(105 4)')),
+ ('c', 'z', 'q', GeomFromText('POINT(13 140)')),
+ ('m', 'k', 'i', GeomFromText('POINT(208 120)')),
+ ('g', 'a', 'g', GeomFromText('POINT(9 182)')),
+ ('z', 'j', 'r', GeomFromText('POINT(149 153)')),
+ ('h', 'f', 'g', GeomFromText('POINT(81 236)')),
+ ('m', 'e', 'q', GeomFromText('POINT(209 215)')),
+ ('c', 'h', 'y', GeomFromText('POINT(235 70)')),
+ ('i', 'e', 'g', GeomFromText('POINT(138 26)')),
+ ('m', 't', 'u', GeomFromText('POINT(119 237)')),
+ ('o', 'w', 's', GeomFromText('POINT(193 166)')),
+ ('f', 'm', 'q', GeomFromText('POINT(85 96)')),
+ ('x', 'l', 'x', GeomFromText('POINT(58 115)')),
+ ('x', 'q', 'u', GeomFromText('POINT(108 210)')),
+ ('b', 'h', 'i', GeomFromText('POINT(250 139)')),
+ ('y', 'd', 'x', GeomFromText('POINT(199 135)')),
+ ('w', 'h', 'p', GeomFromText('POINT(247 233)')),
+ ('p', 'z', 't', GeomFromText('POINT(148 249)')),
+ ('q', 'a', 'u', GeomFromText('POINT(174 78)')),
+ ('v', 't', 'm', GeomFromText('POINT(70 228)')),
+ ('t', 'n', 'f', GeomFromText('POINT(123 2)')),
+ ('x', 't', 'b', GeomFromText('POINT(35 50)')),
+ ('r', 'j', 'f', GeomFromText('POINT(200 51)')),
+ ('s', 'q', 'o', GeomFromText('POINT(23 184)')),
+ ('u', 'v', 'z', GeomFromText('POINT(7 113)')),
+ ('v', 'u', 'l', GeomFromText('POINT(145 190)')),
+ ('o', 'k', 'i', GeomFromText('POINT(161 122)')),
+ ('l', 'y', 'e', GeomFromText('POINT(17 232)')),
+ ('t', 'b', 'e', GeomFromText('POINT(120 50)')),
+ ('e', 's', 'u', GeomFromText('POINT(254 1)')),
+ ('d', 'd', 'u', GeomFromText('POINT(167 140)')),
+ ('o', 'b', 'x', GeomFromText('POINT(186 237)')),
+ ('m', 's', 's', GeomFromText('POINT(172 149)')),
+ ('t', 'y', 'a', GeomFromText('POINT(149 85)')),
+ ('x', 't', 'r', GeomFromText('POINT(10 165)')),
+ ('g', 'c', 'e', GeomFromText('POINT(95 165)')),
+ ('e', 'e', 'z', GeomFromText('POINT(98 65)')),
+ ('f', 'v', 'i', GeomFromText('POINT(149 144)')),
+ ('o', 'p', 'm', GeomFromText('POINT(233 67)')),
+ ('t', 'u', 'b', GeomFromText('POINT(109 215)')),
+ ('o', 'o', 'b', GeomFromText('POINT(130 48)')),
+ ('e', 'm', 'h', GeomFromText('POINT(88 189)')),
+ ('e', 'v', 'y', GeomFromText('POINT(55 29)')),
+ ('e', 't', 'm', GeomFromText('POINT(129 55)')),
+ ('p', 'p', 'i', GeomFromText('POINT(126 222)')),
+ ('c', 'i', 'c', GeomFromText('POINT(19 158)')),
+ ('c', 'b', 's', GeomFromText('POINT(13 19)')),
+ ('u', 'y', 'a', GeomFromText('POINT(114 5)')),
+ ('a', 'o', 'f', GeomFromText('POINT(227 232)')),
+ ('t', 'c', 'z', GeomFromText('POINT(63 62)')),
+ ('d', 'o', 'k', GeomFromText('POINT(48 228)')),
+ ('x', 'c', 'e', GeomFromText('POINT(204 2)')),
+ ('e', 'e', 'g', GeomFromText('POINT(125 43)')),
+ ('o', 'r', 'f', GeomFromText('POINT(171 140)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(163 157)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(53 151)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(96 183)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(57 91)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 110)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('b', 'c', 'e', GeomFromText('POINT(41 137)')),
+ ('p', 'y', 'k', GeomFromText('POINT(50 22)')),
+ ('s', 'c', 'h', GeomFromText('POINT(208 173)')),
+ ('x', 'u', 'l', GeomFromText('POINT(199 175)')),
+ ('s', 'r', 'h', GeomFromText('POINT(85 192)')),
+ ('j', 'k', 'u', GeomFromText('POINT(18 25)')),
+ ('p', 'w', 'h', GeomFromText('POINT(152 197)')),
+ ('e', 'd', 'c', GeomFromText('POINT(229 3)')),
+ ('o', 'x', 'k', GeomFromText('POINT(187 155)')),
+ ('o', 'b', 'k', GeomFromText('POINT(208 150)')),
+ ('d', 'a', 'j', GeomFromText('POINT(70 87)')),
+ ('f', 'e', 'k', GeomFromText('POINT(156 96)')),
+ ('u', 'y', 'p', GeomFromText('POINT(239 193)')),
+ ('n', 'v', 'p', GeomFromText('POINT(223 98)')),
+ ('z', 'j', 'r', GeomFromText('POINT(87 89)')),
+ ('h', 'x', 'x', GeomFromText('POINT(92 0)')),
+ ('r', 'v', 'r', GeomFromText('POINT(159 139)')),
+ ('v', 'g', 'g', GeomFromText('POINT(16 229)')),
+ ('z', 'k', 'u', GeomFromText('POINT(99 52)')),
+ ('p', 'p', 'o', GeomFromText('POINT(105 125)')),
+ ('w', 'h', 'y', GeomFromText('POINT(105 154)')),
+ ('v', 'y', 'z', GeomFromText('POINT(134 238)')),
+ ('x', 'o', 'o', GeomFromText('POINT(178 88)')),
+ ('z', 'w', 'd', GeomFromText('POINT(123 60)')),
+ ('q', 'f', 'u', GeomFromText('POINT(64 90)')),
+ ('s', 'n', 't', GeomFromText('POINT(50 138)')),
+ ('v', 'p', 't', GeomFromText('POINT(114 91)')),
+ ('a', 'o', 'n', GeomFromText('POINT(78 43)')),
+ ('k', 'u', 'd', GeomFromText('POINT(185 161)')),
+ ('w', 'd', 'n', GeomFromText('POINT(25 92)')),
+ ('k', 'w', 'a', GeomFromText('POINT(59 238)')),
+ ('t', 'c', 'f', GeomFromText('POINT(65 87)')),
+ ('g', 's', 'p', GeomFromText('POINT(238 126)')),
+ ('d', 'n', 'y', GeomFromText('POINT(107 173)')),
+ ('l', 'a', 'w', GeomFromText('POINT(125 152)')),
+ ('m', 'd', 'j', GeomFromText('POINT(146 53)')),
+ ('q', 'm', 'c', GeomFromText('POINT(217 187)')),
+ ('i', 'r', 'r', GeomFromText('POINT(6 113)')),
+ ('e', 'j', 'b', GeomFromText('POINT(37 83)')),
+ ('w', 'w', 'h', GeomFromText('POINT(83 199)')),
+ ('k', 'b', 's', GeomFromText('POINT(170 64)')),
+ ('s', 'b', 'c', GeomFromText('POINT(163 130)')),
+ ('c', 'h', 'a', GeomFromText('POINT(141 3)')),
+ ('k', 'j', 'u', GeomFromText('POINT(143 76)')),
+ ('r', 'h', 'o', GeomFromText('POINT(243 92)')),
+ ('i', 'd', 'b', GeomFromText('POINT(205 13)')),
+ ('r', 'y', 'q', GeomFromText('POINT(138 8)')),
+ ('m', 'o', 'i', GeomFromText('POINT(36 45)')),
+ ('v', 'g', 'm', GeomFromText('POINT(0 40)')),
+ ('f', 'e', 'i', GeomFromText('POINT(76 6)')),
+ ('c', 'q', 'q', GeomFromText('POINT(115 248)')),
+ ('x', 'c', 'i', GeomFromText('POINT(29 74)')),
+ ('l', 's', 't', GeomFromText('POINT(83 18)')),
+ ('t', 't', 'a', GeomFromText('POINT(26 168)')),
+ ('u', 'n', 'x', GeomFromText('POINT(200 110)')),
+ ('j', 'b', 'd', GeomFromText('POINT(216 136)')),
+ ('s', 'p', 'w', GeomFromText('POINT(38 156)')),
+ ('f', 'b', 'v', GeomFromText('POINT(29 186)')),
+ ('v', 'e', 'r', GeomFromText('POINT(149 40)')),
+ ('v', 't', 'm', GeomFromText('POINT(184 24)')),
+ ('y', 'g', 'a', GeomFromText('POINT(219 105)')),
+ ('s', 'f', 'i', GeomFromText('POINT(114 130)')),
+ ('e', 'q', 'h', GeomFromText('POINT(203 135)')),
+ ('h', 'g', 'b', GeomFromText('POINT(9 208)')),
+ ('o', 'l', 'r', GeomFromText('POINT(245 79)')),
+ ('s', 's', 'v', GeomFromText('POINT(238 198)')),
+ ('w', 'w', 'z', GeomFromText('POINT(209 232)')),
+ ('v', 'd', 'n', GeomFromText('POINT(30 193)')),
+ ('q', 'w', 'k', GeomFromText('POINT(133 18)')),
+ ('o', 'h', 'o', GeomFromText('POINT(42 140)')),
+ ('f', 'f', 'h', GeomFromText('POINT(145 1)')),
+ ('u', 's', 'r', GeomFromText('POINT(70 62)')),
+ ('x', 'n', 'q', GeomFromText('POINT(33 86)')),
+ ('u', 'p', 'v', GeomFromText('POINT(232 220)')),
+ ('z', 'e', 'a', GeomFromText('POINT(130 69)')),
+ ('r', 'u', 'z', GeomFromText('POINT(243 241)')),
+ ('b', 'n', 't', GeomFromText('POINT(120 12)')),
+ ('u', 'f', 's', GeomFromText('POINT(190 212)')),
+ ('a', 'd', 'q', GeomFromText('POINT(235 191)')),
+ ('f', 'q', 'm', GeomFromText('POINT(176 2)')),
+ ('n', 'c', 's', GeomFromText('POINT(218 163)')),
+ ('e', 'm', 'h', GeomFromText('POINT(163 108)')),
+ ('c', 'f', 'l', GeomFromText('POINT(220 115)')),
+ ('c', 'v', 'q', GeomFromText('POINT(66 45)')),
+ ('w', 'v', 'x', GeomFromText('POINT(251 220)')),
+ ('f', 'w', 'z', GeomFromText('POINT(146 149)')),
+ ('h', 'n', 'h', GeomFromText('POINT(148 128)')),
+ ('y', 'k', 'v', GeomFromText('POINT(28 110)')),
+ ('c', 'x', 'q', GeomFromText('POINT(13 13)')),
+ ('e', 'd', 's', GeomFromText('POINT(91 190)')),
+ ('c', 'w', 'c', GeomFromText('POINT(10 231)')),
+ ('u', 'j', 'n', GeomFromText('POINT(250 21)')),
+ ('w', 'n', 'x', GeomFromText('POINT(141 69)')),
+ ('f', 'p', 'y', GeomFromText('POINT(228 246)')),
+ ('d', 'q', 'f', GeomFromText('POINT(194 22)')),
+ ('d', 'z', 'l', GeomFromText('POINT(233 181)')),
+ ('c', 'a', 'q', GeomFromText('POINT(183 96)')),
+ ('m', 'i', 'd', GeomFromText('POINT(117 226)')),
+ ('z', 'y', 'y', GeomFromText('POINT(62 81)')),
+ ('g', 'v', 'm', GeomFromText('POINT(66 158)'));
+SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1072017234, @@RAND_SEED2=484203885;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=358851897, @@RAND_SEED2=358495224;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=509031459, @@RAND_SEED2=675962925;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(61 203)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 194)') where c1 like 'f%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(228 18)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 18)') where c1 like 'l%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(176 94)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(44 47)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 191)') where c1 like 'b%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(179 218)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(239 40)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(248 41)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(167 82)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(13 104)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(139 84)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(145 108)') where c1 like 'p%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(147 57)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(217 144)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(160 224)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(38 28)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(104 114)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 19)') where c1 like 'c%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('f', 'x', 'p', GeomFromText('POINT(92 181)')),
+ ('s', 'i', 'c', GeomFromText('POINT(49 60)')),
+ ('c', 'c', 'i', GeomFromText('POINT(7 57)')),
+ ('n', 'g', 'k', GeomFromText('POINT(252 105)')),
+ ('g', 'b', 'm', GeomFromText('POINT(180 11)')),
+ ('u', 'l', 'r', GeomFromText('POINT(32 90)')),
+ ('c', 'x', 'e', GeomFromText('POINT(143 24)')),
+ ('x', 'u', 'a', GeomFromText('POINT(123 92)')),
+ ('s', 'b', 'h', GeomFromText('POINT(190 108)')),
+ ('c', 'x', 'b', GeomFromText('POINT(104 100)')),
+ ('i', 'd', 't', GeomFromText('POINT(214 104)')),
+ ('r', 'w', 'g', GeomFromText('POINT(29 67)')),
+ ('b', 'f', 'g', GeomFromText('POINT(149 46)')),
+ ('r', 'r', 'd', GeomFromText('POINT(242 196)')),
+ ('j', 'l', 'a', GeomFromText('POINT(90 196)')),
+ ('e', 't', 'b', GeomFromText('POINT(190 64)')),
+ ('l', 'x', 'w', GeomFromText('POINT(250 73)')),
+ ('q', 'y', 'r', GeomFromText('POINT(120 182)')),
+ ('s', 'j', 'a', GeomFromText('POINT(180 175)')),
+ ('n', 'i', 'y', GeomFromText('POINT(124 136)')),
+ ('s', 'x', 's', GeomFromText('POINT(176 209)')),
+ ('u', 'f', 's', GeomFromText('POINT(215 173)')),
+ ('m', 'j', 'x', GeomFromText('POINT(44 140)')),
+ ('v', 'g', 'x', GeomFromText('POINT(177 233)')),
+ ('u', 't', 'b', GeomFromText('POINT(136 197)')),
+ ('f', 'g', 'b', GeomFromText('POINT(10 8)')),
+ ('v', 'c', 'j', GeomFromText('POINT(13 81)')),
+ ('d', 's', 'q', GeomFromText('POINT(200 100)')),
+ ('a', 'p', 'j', GeomFromText('POINT(33 40)')),
+ ('i', 'c', 'g', GeomFromText('POINT(168 204)')),
+ ('k', 'h', 'i', GeomFromText('POINT(93 243)')),
+ ('s', 'b', 's', GeomFromText('POINT(157 13)')),
+ ('v', 'l', 'l', GeomFromText('POINT(103 6)')),
+ ('r', 'b', 'k', GeomFromText('POINT(244 137)')),
+ ('l', 'd', 'r', GeomFromText('POINT(162 254)')),
+ ('q', 'b', 'z', GeomFromText('POINT(136 246)')),
+ ('x', 'x', 'p', GeomFromText('POINT(120 37)')),
+ ('m', 'e', 'z', GeomFromText('POINT(203 167)')),
+ ('q', 'n', 'p', GeomFromText('POINT(94 119)')),
+ ('b', 'g', 'u', GeomFromText('POINT(93 248)')),
+ ('r', 'v', 'v', GeomFromText('POINT(53 88)')),
+ ('y', 'a', 'i', GeomFromText('POINT(98 219)')),
+ ('a', 's', 'g', GeomFromText('POINT(173 138)')),
+ ('c', 'a', 't', GeomFromText('POINT(235 135)')),
+ ('q', 'm', 'd', GeomFromText('POINT(224 208)')),
+ ('e', 'p', 'k', GeomFromText('POINT(161 238)')),
+ ('n', 'g', 'q', GeomFromText('POINT(35 204)')),
+ ('t', 't', 'x', GeomFromText('POINT(230 178)')),
+ ('w', 'f', 'a', GeomFromText('POINT(150 221)')),
+ ('z', 'm', 'z', GeomFromText('POINT(119 42)')),
+ ('l', 'j', 's', GeomFromText('POINT(97 96)')),
+ ('f', 'z', 'x', GeomFromText('POINT(208 65)')),
+ ('i', 'v', 'c', GeomFromText('POINT(145 79)')),
+ ('l', 'f', 'k', GeomFromText('POINT(83 234)')),
+ ('u', 'a', 's', GeomFromText('POINT(250 49)')),
+ ('o', 'k', 'p', GeomFromText('POINT(46 50)')),
+ ('d', 'e', 'z', GeomFromText('POINT(30 198)')),
+ ('r', 'r', 'l', GeomFromText('POINT(78 189)')),
+ ('y', 'l', 'f', GeomFromText('POINT(188 132)')),
+ ('d', 'q', 'm', GeomFromText('POINT(247 107)')),
+ ('p', 'j', 'n', GeomFromText('POINT(148 227)')),
+ ('b', 'o', 'i', GeomFromText('POINT(172 25)')),
+ ('e', 'v', 'd', GeomFromText('POINT(94 248)')),
+ ('q', 'd', 'f', GeomFromText('POINT(15 29)')),
+ ('w', 'b', 'b', GeomFromText('POINT(74 111)')),
+ ('g', 'q', 'f', GeomFromText('POINT(107 215)')),
+ ('o', 'h', 'r', GeomFromText('POINT(25 168)')),
+ ('u', 't', 'w', GeomFromText('POINT(251 188)')),
+ ('h', 's', 'w', GeomFromText('POINT(254 247)')),
+ ('f', 'f', 'b', GeomFromText('POINT(166 103)'));
+SET @@RAND_SEED1=866613816, @@RAND_SEED2=92289615;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('l', 'c', 'l', GeomFromText('POINT(202 98)')),
+ ('k', 'c', 'b', GeomFromText('POINT(46 206)')),
+ ('r', 'y', 'm', GeomFromText('POINT(74 140)')),
+ ('y', 'z', 'd', GeomFromText('POINT(200 160)')),
+ ('s', 'y', 's', GeomFromText('POINT(156 205)')),
+ ('u', 'v', 'p', GeomFromText('POINT(86 82)')),
+ ('j', 's', 's', GeomFromText('POINT(91 233)')),
+ ('x', 'j', 'f', GeomFromText('POINT(3 14)')),
+ ('l', 'z', 'v', GeomFromText('POINT(123 156)')),
+ ('h', 'i', 'o', GeomFromText('POINT(145 229)')),
+ ('o', 'r', 'd', GeomFromText('POINT(15 22)')),
+ ('f', 'x', 't', GeomFromText('POINT(21 60)')),
+ ('t', 'g', 'h', GeomFromText('POINT(50 153)')),
+ ('g', 'u', 'b', GeomFromText('POINT(82 85)')),
+ ('v', 'a', 'p', GeomFromText('POINT(231 178)')),
+ ('n', 'v', 'o', GeomFromText('POINT(183 25)')),
+ ('j', 'n', 'm', GeomFromText('POINT(50 144)')),
+ ('e', 'f', 'i', GeomFromText('POINT(46 16)')),
+ ('d', 'w', 'a', GeomFromText('POINT(66 6)')),
+ ('f', 'x', 'a', GeomFromText('POINT(107 197)')),
+ ('m', 'o', 'a', GeomFromText('POINT(142 80)')),
+ ('q', 'l', 'g', GeomFromText('POINT(251 23)')),
+ ('c', 's', 's', GeomFromText('POINT(158 43)')),
+ ('y', 'd', 'o', GeomFromText('POINT(196 228)')),
+ ('d', 'p', 'l', GeomFromText('POINT(107 5)')),
+ ('h', 'a', 'b', GeomFromText('POINT(183 166)')),
+ ('m', 'w', 'p', GeomFromText('POINT(19 59)')),
+ ('b', 'y', 'o', GeomFromText('POINT(178 30)')),
+ ('x', 'w', 'i', GeomFromText('POINT(168 94)')),
+ ('t', 'k', 'z', GeomFromText('POINT(171 5)')),
+ ('r', 'm', 'a', GeomFromText('POINT(222 19)')),
+ ('u', 'v', 'e', GeomFromText('POINT(224 80)')),
+ ('q', 'r', 'k', GeomFromText('POINT(212 218)')),
+ ('d', 'p', 'j', GeomFromText('POINT(169 7)')),
+ ('d', 'r', 'v', GeomFromText('POINT(193 23)')),
+ ('n', 'y', 'y', GeomFromText('POINT(130 178)')),
+ ('m', 'z', 'r', GeomFromText('POINT(81 200)')),
+ ('j', 'e', 'w', GeomFromText('POINT(145 239)')),
+ ('v', 'h', 'x', GeomFromText('POINT(24 105)')),
+ ('z', 'm', 'a', GeomFromText('POINT(175 129)')),
+ ('b', 'c', 'v', GeomFromText('POINT(213 10)')),
+ ('t', 't', 'u', GeomFromText('POINT(2 129)')),
+ ('r', 's', 'v', GeomFromText('POINT(209 192)')),
+ ('x', 'p', 'g', GeomFromText('POINT(43 63)')),
+ ('t', 'e', 'u', GeomFromText('POINT(139 210)')),
+ ('l', 'e', 't', GeomFromText('POINT(245 148)')),
+ ('a', 'i', 'k', GeomFromText('POINT(167 195)')),
+ ('m', 'o', 'h', GeomFromText('POINT(206 120)')),
+ ('g', 'z', 's', GeomFromText('POINT(169 240)')),
+ ('z', 'u', 's', GeomFromText('POINT(202 120)')),
+ ('i', 'b', 'a', GeomFromText('POINT(216 18)')),
+ ('w', 'y', 'g', GeomFromText('POINT(119 236)')),
+ ('h', 'y', 'p', GeomFromText('POINT(161 24)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(33 100)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(41 46)') where c1 like 'f%';
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Bug #30286 spatial index cause corruption and server crash!
+#
+
+create table t1 (a geometry not null, spatial index(a)) transactional=1 row_format=page;
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072)));
+insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0)));
+insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241)));
+insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231)));
+insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260)));
+insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125)));
+insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29)));
+insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86)));
+insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130)));
+insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34)));
+insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183)));
+insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178)));
+drop table t1;
+
+# End of 4.1 tests
+
+#
+# bug #21790 (UNKNOWN ERROR on NULLs in RTree)
+#
+CREATE TABLE t1(foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=1 row_format=page;
+--error 1048
+INSERT INTO t1(foo) VALUES (NULL);
+--error 1416
+INSERT INTO t1() VALUES ();
+--error 1416
+INSERT INTO t1(foo) VALUES ('');
+DROP TABLE t1;
+
+#
+# Bug #23578: Corruption prevents Optimize table from working properly with a
+# spatial index
+#
+
+CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)) transactional=1 row_format=page;
+
+INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)'));
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+
+OPTIMIZE TABLE t1;
+DROP TABLE t1;
+
+
+#
+# Bug #29070: Error in spatial index
+#
+
+CREATE TABLE t1 (a INT, b GEOMETRY NOT NULL, SPATIAL KEY b(b)) transactional=1 row_format=page;
+INSERT INTO t1 VALUES (1, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+INSERT INTO t1 VALUES (2, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+
+# must return the same number as the next select
+SELECT COUNT(*) FROM t1 WHERE
+ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE
+ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+
+DROP TABLE t1;
+
+--echo End of 5.0 tests.
diff --git a/mysql-test/suite/maria/t/maria-gis-rtree.test b/mysql-test/suite/maria/t/maria-gis-rtree.test
new file mode 100644
index 00000000000..7a3e5634388
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-gis-rtree.test
@@ -0,0 +1,888 @@
+-- source include/have_maria.inc
+-- source include/have_geometry.inc
+
+set storage_engine=maria;
+
+#
+# test of rtree (using with spatial data)
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+CREATE TABLE t1 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL,
+ SPATIAL KEY(g)
+) transactional=0 row_format=page;
+
+SHOW CREATE TABLE t1;
+
+let $1=150;
+let $2=150;
+while ($1)
+{
+ eval INSERT INTO t1 (g) VALUES (GeomFromText('LineString($1 $1, $2 $2)'));
+ dec $1;
+ inc $2;
+}
+
+SELECT count(*) FROM t1;
+EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
+
+DROP TABLE t1;
+
+CREATE TABLE t2 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL
+) transactional=0 row_format=page;
+
+let $1=10;
+while ($1)
+{
+ let $2=10;
+ while ($2)
+ {
+ eval INSERT INTO t2 (g) VALUES (GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10))));
+ dec $2;
+ }
+ dec $1;
+}
+
+ALTER TABLE t2 ADD SPATIAL KEY(g);
+SHOW CREATE TABLE t2;
+SELECT count(*) FROM t2;
+EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+ GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+SELECT fid, AsText(g) FROM t2 WHERE Within(g,
+ GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
+
+let $1=10;
+while ($1)
+{
+ let $2=10;
+ while ($2)
+ {
+ eval DELETE FROM t2 WHERE Within(g, Envelope(GeometryFromWKB(LineString(Point($1 * 10 - 9, $2 * 10 - 9), Point($1 * 10, $2 * 10)))));
+ SELECT count(*) FROM t2;
+ dec $2;
+ }
+ dec $1;
+}
+
+DROP TABLE t2;
+
+drop table if exists t1;
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a)) transactional=0 row_format=page;
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+analyze table t1;
+drop table t1;
+
+#
+# The following crashed gis
+#
+
+CREATE TABLE t1 (
+ fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ g GEOMETRY NOT NULL,
+ SPATIAL KEY(g)
+) transactional=0 row_format=page;
+
+INSERT INTO t1 (g) VALUES (GeomFromText('LineString(1 2, 2 3)')),(GeomFromText('LineString(1 2, 2 4)'));
+#select * from t1 where g<GeomFromText('LineString(1 2, 2 3)');
+drop table t1;
+
+CREATE TABLE t1 (
+ line LINESTRING NOT NULL,
+ kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+ name VARCHAR(32),
+
+ SPATIAL KEY (line)
+
+
+) transactional=0 row_format=page;
+
+ALTER TABLE t1 DISABLE KEYS;
+
+INSERT INTO t1 (name, kind, line) VALUES
+ ("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+ ("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+ ("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+ ("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+ ("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+ ("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+ ("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+ ("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+ ("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+ ("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+ ("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+ ("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+ ("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+ ("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+ ("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+ ("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+ ("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+ ("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+ ("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+ ("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+ ("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+ ("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+ ("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+
+ALTER TABLE t1 ENABLE KEYS;
+INSERT INTO t1 (name, kind, line) VALUES ("austria", "pp", GeomFromText('LINESTRING(14.9906 48.9887,14.9946 48.9904,14.9947 48.9916)'));
+drop table t1;
+
+CREATE TABLE t1 (st varchar(100));
+INSERT INTO t1 VALUES ("Fake string");
+CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)) transactional=0 row_format=page;
+--error 1416
+INSERT INTO t2 SELECT GeomFromText(st) FROM t1;
+drop table t1, t2;
+
+CREATE TABLE t1 (`geometry` geometry NOT NULL default '',SPATIAL KEY `gndx` (`geometry`)) transactional=0 row_format=page DEFAULT CHARSET=latin1;
+
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-18.6086111000 -66.9327777000, -18.6055555000
+-66.8158332999, -18.7186111000 -66.8102777000, -18.7211111000 -66.9269443999,
+-18.6086111000 -66.9327777000))'));
+
+INSERT INTO t1 (geometry) VALUES
+(PolygonFromText('POLYGON((-65.7402776999 -96.6686111000, -65.7372222000
+-96.5516666000, -65.8502777000 -96.5461111000, -65.8527777000 -96.6627777000,
+-65.7402776999 -96.6686111000))'));
+check table t1 extended;
+
+drop table t1;
+
+#
+# Bug#17877 - Corrupted spatial index
+#
+CREATE TABLE t1 (
+ c1 geometry NOT NULL default '',
+ SPATIAL KEY i1 (c1)
+) transactional=0 row_format=page DEFAULT CHARSET=latin1;
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+# This showed a missing key.
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+#
+CREATE TABLE t1 (
+ c1 geometry NOT NULL default '',
+ SPATIAL KEY i1 (c1)
+) transactional=0 row_format=page DEFAULT CHARSET=latin1;
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-65.7402776999 -96.6686111000,
+ -65.7372222000 -96.5516666000,
+ -65.8502777000 -96.5461111000,
+ -65.8527777000 -96.6627777000,
+ -65.7402776999 -96.6686111000))'));
+# This is the same as the first insert to get a non-unique key.
+INSERT INTO t1 (c1) VALUES (
+ PolygonFromText('POLYGON((-18.6086111000 -66.9327777000,
+ -18.6055555000 -66.8158332999,
+ -18.7186111000 -66.8102777000,
+ -18.7211111000 -66.9269443999,
+ -18.6086111000 -66.9327777000))'));
+# This showed (and still shows) OK.
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Bug #21888: Query on GEOMETRY field using PointFromWKB() results in lost connection
+#
+CREATE TABLE t1 (foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=0 row_format=page;
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(1,0)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,1)));
+INSERT INTO t1 (foo) VALUES (PointFromWKB(POINT(0,0)));
+SELECT 1 FROM t1 WHERE foo != PointFromWKB(POINT(0,0));
+DROP TABLE t1;
+
+#
+# Bug#25673 - spatial index corruption, error 126 incorrect key file for table
+#
+CREATE TABLE t1 (id bigint(12) unsigned NOT NULL auto_increment,
+ c2 varchar(15) collate utf8_bin default NULL,
+ c1 varchar(15) collate utf8_bin default NULL,
+ c3 varchar(10) collate utf8_bin default NULL,
+ spatial_point point NOT NULL,
+ PRIMARY KEY(id),
+ SPATIAL KEY (spatial_point)
+ )transactional=0 row_format=page DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+#
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('y', 's', 'j', GeomFromText('POINT(167 74)')),
+ ('r', 'n', 'd', GeomFromText('POINT(215 118)')),
+ ('g', 'n', 'e', GeomFromText('POINT(203 98)')),
+ ('h', 'd', 'd', GeomFromText('POINT(54 193)')),
+ ('r', 'x', 'y', GeomFromText('POINT(47 69)')),
+ ('t', 'q', 'r', GeomFromText('POINT(109 42)')),
+ ('a', 'z', 'd', GeomFromText('POINT(0 154)')),
+ ('x', 'v', 'o', GeomFromText('POINT(174 131)')),
+ ('b', 'r', 'a', GeomFromText('POINT(114 253)')),
+ ('x', 'z', 'i', GeomFromText('POINT(163 21)')),
+ ('w', 'p', 'i', GeomFromText('POINT(42 102)')),
+ ('g', 'j', 'j', GeomFromText('POINT(170 133)')),
+ ('m', 'g', 'n', GeomFromText('POINT(28 22)')),
+ ('b', 'z', 'h', GeomFromText('POINT(174 28)')),
+ ('q', 'k', 'f', GeomFromText('POINT(233 73)')),
+ ('w', 'w', 'a', GeomFromText('POINT(124 200)')),
+ ('t', 'j', 'w', GeomFromText('POINT(252 101)')),
+ ('d', 'r', 'd', GeomFromText('POINT(98 18)')),
+ ('w', 'o', 'y', GeomFromText('POINT(165 31)')),
+ ('y', 'h', 't', GeomFromText('POINT(14 220)')),
+ ('d', 'p', 'u', GeomFromText('POINT(223 196)')),
+ ('g', 'y', 'g', GeomFromText('POINT(207 96)')),
+ ('x', 'm', 'n', GeomFromText('POINT(214 3)')),
+ ('g', 'v', 'e', GeomFromText('POINT(140 205)')),
+ ('g', 'm', 'm', GeomFromText('POINT(10 236)')),
+ ('i', 'r', 'j', GeomFromText('POINT(137 228)')),
+ ('w', 's', 'p', GeomFromText('POINT(115 6)')),
+ ('o', 'n', 'k', GeomFromText('POINT(158 129)')),
+ ('j', 'h', 'l', GeomFromText('POINT(129 72)')),
+ ('f', 'x', 'l', GeomFromText('POINT(139 207)')),
+ ('u', 'd', 'n', GeomFromText('POINT(125 109)')),
+ ('b', 'a', 'z', GeomFromText('POINT(30 32)')),
+ ('m', 'h', 'o', GeomFromText('POINT(251 251)')),
+ ('f', 'r', 'd', GeomFromText('POINT(243 211)')),
+ ('b', 'd', 'r', GeomFromText('POINT(232 80)')),
+ ('g', 'k', 'v', GeomFromText('POINT(15 100)')),
+ ('i', 'f', 'c', GeomFromText('POINT(109 66)')),
+ ('r', 't', 'j', GeomFromText('POINT(178 6)')),
+ ('y', 'n', 'f', GeomFromText('POINT(233 211)')),
+ ('f', 'y', 'm', GeomFromText('POINT(99 16)')),
+ ('z', 'q', 'l', GeomFromText('POINT(39 49)')),
+ ('j', 'c', 'r', GeomFromText('POINT(75 187)')),
+ ('c', 'y', 'y', GeomFromText('POINT(246 253)')),
+ ('w', 'u', 'd', GeomFromText('POINT(56 190)')),
+ ('n', 'q', 'm', GeomFromText('POINT(73 149)')),
+ ('d', 'y', 'a', GeomFromText('POINT(134 6)')),
+ ('z', 's', 'w', GeomFromText('POINT(216 225)')),
+ ('d', 'u', 'k', GeomFromText('POINT(132 70)')),
+ ('f', 'v', 't', GeomFromText('POINT(187 141)')),
+ ('r', 'r', 'a', GeomFromText('POINT(152 39)')),
+ ('y', 'p', 'o', GeomFromText('POINT(45 27)')),
+ ('p', 'n', 'm', GeomFromText('POINT(228 148)')),
+ ('e', 'g', 'e', GeomFromText('POINT(88 81)')),
+ ('m', 'a', 'h', GeomFromText('POINT(35 29)')),
+ ('m', 'h', 'f', GeomFromText('POINT(30 71)')),
+ ('h', 'k', 'i', GeomFromText('POINT(244 78)')),
+ ('z', 'v', 'd', GeomFromText('POINT(241 38)')),
+ ('q', 'l', 'j', GeomFromText('POINT(13 71)')),
+ ('s', 'p', 'g', GeomFromText('POINT(108 38)')),
+ ('q', 's', 'j', GeomFromText('POINT(92 101)')),
+ ('l', 'h', 'g', GeomFromText('POINT(120 78)')),
+ ('w', 't', 'b', GeomFromText('POINT(193 109)')),
+ ('b', 's', 's', GeomFromText('POINT(223 211)')),
+ ('w', 'w', 'y', GeomFromText('POINT(122 42)')),
+ ('q', 'c', 'c', GeomFromText('POINT(104 102)')),
+ ('w', 'g', 'n', GeomFromText('POINT(213 120)')),
+ ('p', 'q', 'a', GeomFromText('POINT(247 148)')),
+ ('c', 'z', 'e', GeomFromText('POINT(18 106)')),
+ ('z', 'u', 'n', GeomFromText('POINT(70 133)')),
+ ('j', 'n', 'x', GeomFromText('POINT(232 13)')),
+ ('e', 'h', 'f', GeomFromText('POINT(22 135)')),
+ ('w', 'l', 'f', GeomFromText('POINT(9 180)')),
+ ('a', 'v', 'q', GeomFromText('POINT(163 228)')),
+ ('i', 'z', 'o', GeomFromText('POINT(180 100)')),
+ ('e', 'c', 'l', GeomFromText('POINT(182 231)')),
+ ('c', 'k', 'o', GeomFromText('POINT(19 60)')),
+ ('q', 'f', 'p', GeomFromText('POINT(79 95)')),
+ ('m', 'd', 'r', GeomFromText('POINT(3 127)')),
+ ('m', 'e', 't', GeomFromText('POINT(136 154)')),
+ ('w', 'w', 'w', GeomFromText('POINT(102 15)')),
+ ('l', 'n', 'q', GeomFromText('POINT(71 196)')),
+ ('p', 'k', 'c', GeomFromText('POINT(47 139)')),
+ ('j', 'o', 'r', GeomFromText('POINT(177 128)')),
+ ('j', 'q', 'a', GeomFromText('POINT(170 6)')),
+ ('b', 'a', 'o', GeomFromText('POINT(63 211)')),
+ ('g', 's', 'o', GeomFromText('POINT(144 251)')),
+ ('w', 'u', 'w', GeomFromText('POINT(221 214)')),
+ ('g', 'a', 'm', GeomFromText('POINT(14 102)')),
+ ('u', 'q', 'z', GeomFromText('POINT(86 200)')),
+ ('k', 'a', 'm', GeomFromText('POINT(144 222)')),
+ ('j', 'u', 'r', GeomFromText('POINT(216 142)')),
+ ('q', 'k', 'v', GeomFromText('POINT(121 236)')),
+ ('p', 'o', 'r', GeomFromText('POINT(108 102)')),
+ ('b', 'd', 'x', GeomFromText('POINT(127 198)')),
+ ('k', 's', 'a', GeomFromText('POINT(2 150)')),
+ ('f', 'm', 'f', GeomFromText('POINT(160 191)')),
+ ('q', 'y', 'x', GeomFromText('POINT(98 111)')),
+ ('o', 'f', 'm', GeomFromText('POINT(232 218)')),
+ ('c', 'w', 'j', GeomFromText('POINT(156 165)')),
+ ('s', 'q', 'v', GeomFromText('POINT(98 161)'));
+SET @@RAND_SEED1=692635050, @@RAND_SEED2=297339954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=159925977, @@RAND_SEED2=942570618;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=328169745, @@RAND_SEED2=410451954;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=178507359, @@RAND_SEED2=332493072;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1034033013, @@RAND_SEED2=558966507;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(230 9)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 35)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(93 99)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(19 81)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(20 177)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(221 193)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(195 205)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(15 213)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(214 63)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(243 171)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(198 82)') where c1 like 'y%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('f', 'y', 'p', GeomFromText('POINT(109 235)')),
+ ('b', 'e', 'v', GeomFromText('POINT(20 48)')),
+ ('i', 'u', 'f', GeomFromText('POINT(15 55)')),
+ ('o', 'r', 'z', GeomFromText('POINT(105 64)')),
+ ('a', 'p', 'a', GeomFromText('POINT(142 236)')),
+ ('g', 'i', 'k', GeomFromText('POINT(10 49)')),
+ ('x', 'z', 'x', GeomFromText('POINT(192 200)')),
+ ('c', 'v', 'r', GeomFromText('POINT(94 168)')),
+ ('y', 'z', 'e', GeomFromText('POINT(141 51)')),
+ ('h', 'm', 'd', GeomFromText('POINT(35 251)')),
+ ('v', 'm', 'q', GeomFromText('POINT(44 90)')),
+ ('j', 'l', 'z', GeomFromText('POINT(67 237)')),
+ ('i', 'v', 'a', GeomFromText('POINT(75 14)')),
+ ('b', 'q', 't', GeomFromText('POINT(153 33)')),
+ ('e', 'm', 'a', GeomFromText('POINT(247 49)')),
+ ('l', 'y', 'g', GeomFromText('POINT(56 203)')),
+ ('v', 'o', 'r', GeomFromText('POINT(90 54)')),
+ ('r', 'n', 'd', GeomFromText('POINT(135 83)')),
+ ('j', 't', 'u', GeomFromText('POINT(174 239)')),
+ ('u', 'n', 'g', GeomFromText('POINT(104 191)')),
+ ('p', 'q', 'y', GeomFromText('POINT(63 171)')),
+ ('o', 'q', 'p', GeomFromText('POINT(192 103)')),
+ ('f', 'x', 'e', GeomFromText('POINT(244 30)')),
+ ('n', 'x', 'c', GeomFromText('POINT(92 103)')),
+ ('r', 'q', 'z', GeomFromText('POINT(166 20)')),
+ ('s', 'a', 'j', GeomFromText('POINT(137 205)')),
+ ('z', 't', 't', GeomFromText('POINT(99 134)')),
+ ('o', 'm', 'j', GeomFromText('POINT(217 3)')),
+ ('n', 'h', 'j', GeomFromText('POINT(211 17)')),
+ ('v', 'v', 'a', GeomFromText('POINT(41 137)')),
+ ('q', 'o', 'j', GeomFromText('POINT(5 92)')),
+ ('z', 'y', 'e', GeomFromText('POINT(175 212)')),
+ ('j', 'z', 'h', GeomFromText('POINT(224 194)')),
+ ('a', 'g', 'm', GeomFromText('POINT(31 119)')),
+ ('p', 'c', 'f', GeomFromText('POINT(17 221)')),
+ ('t', 'h', 'k', GeomFromText('POINT(26 203)')),
+ ('u', 'w', 'p', GeomFromText('POINT(47 185)')),
+ ('z', 'a', 'c', GeomFromText('POINT(61 133)')),
+ ('u', 'k', 'a', GeomFromText('POINT(210 115)')),
+ ('k', 'f', 'h', GeomFromText('POINT(125 113)')),
+ ('t', 'v', 'y', GeomFromText('POINT(12 239)')),
+ ('u', 'v', 'd', GeomFromText('POINT(90 24)')),
+ ('m', 'y', 'w', GeomFromText('POINT(25 243)')),
+ ('d', 'n', 'g', GeomFromText('POINT(122 92)')),
+ ('z', 'm', 'f', GeomFromText('POINT(235 110)')),
+ ('q', 'd', 'f', GeomFromText('POINT(233 217)')),
+ ('a', 'v', 'u', GeomFromText('POINT(69 59)')),
+ ('x', 'k', 'p', GeomFromText('POINT(240 14)')),
+ ('i', 'v', 'r', GeomFromText('POINT(154 42)')),
+ ('w', 'h', 'l', GeomFromText('POINT(178 156)')),
+ ('d', 'h', 'n', GeomFromText('POINT(65 157)')),
+ ('c', 'k', 'z', GeomFromText('POINT(62 33)')),
+ ('e', 'l', 'w', GeomFromText('POINT(162 1)')),
+ ('r', 'f', 'i', GeomFromText('POINT(127 71)')),
+ ('q', 'm', 'c', GeomFromText('POINT(63 118)')),
+ ('c', 'h', 'u', GeomFromText('POINT(205 203)')),
+ ('d', 't', 'p', GeomFromText('POINT(234 87)')),
+ ('s', 'g', 'h', GeomFromText('POINT(149 34)')),
+ ('o', 'b', 'q', GeomFromText('POINT(159 179)')),
+ ('k', 'u', 'f', GeomFromText('POINT(202 254)')),
+ ('u', 'f', 'g', GeomFromText('POINT(70 15)')),
+ ('x', 's', 'b', GeomFromText('POINT(25 181)')),
+ ('s', 'c', 'g', GeomFromText('POINT(252 17)')),
+ ('a', 'c', 'f', GeomFromText('POINT(89 67)')),
+ ('r', 'e', 'q', GeomFromText('POINT(55 54)')),
+ ('f', 'i', 'k', GeomFromText('POINT(178 230)')),
+ ('p', 'e', 'l', GeomFromText('POINT(198 28)')),
+ ('w', 'o', 'd', GeomFromText('POINT(204 189)')),
+ ('c', 'a', 'g', GeomFromText('POINT(230 178)')),
+ ('r', 'o', 'e', GeomFromText('POINT(61 116)')),
+ ('w', 'a', 'a', GeomFromText('POINT(178 237)')),
+ ('v', 'd', 'e', GeomFromText('POINT(70 85)')),
+ ('k', 'c', 'e', GeomFromText('POINT(147 118)')),
+ ('d', 'q', 't', GeomFromText('POINT(218 77)')),
+ ('k', 'g', 'f', GeomFromText('POINT(192 113)')),
+ ('w', 'n', 'e', GeomFromText('POINT(92 124)')),
+ ('r', 'm', 'q', GeomFromText('POINT(130 65)')),
+ ('o', 'r', 'r', GeomFromText('POINT(174 233)')),
+ ('k', 'n', 't', GeomFromText('POINT(175 147)')),
+ ('q', 'm', 'r', GeomFromText('POINT(18 208)')),
+ ('l', 'd', 'i', GeomFromText('POINT(13 104)')),
+ ('w', 'o', 'y', GeomFromText('POINT(207 39)')),
+ ('p', 'u', 'o', GeomFromText('POINT(114 31)')),
+ ('y', 'a', 'p', GeomFromText('POINT(106 59)')),
+ ('a', 'x', 'z', GeomFromText('POINT(17 57)')),
+ ('v', 'h', 'x', GeomFromText('POINT(170 13)')),
+ ('t', 's', 'u', GeomFromText('POINT(84 18)')),
+ ('z', 'z', 'f', GeomFromText('POINT(250 197)')),
+ ('l', 'z', 't', GeomFromText('POINT(59 80)')),
+ ('j', 'g', 's', GeomFromText('POINT(54 26)')),
+ ('g', 'v', 'm', GeomFromText('POINT(89 98)')),
+ ('q', 'v', 'b', GeomFromText('POINT(39 240)')),
+ ('x', 'k', 'v', GeomFromText('POINT(246 207)')),
+ ('k', 'u', 'i', GeomFromText('POINT(105 111)')),
+ ('w', 'z', 's', GeomFromText('POINT(235 8)')),
+ ('d', 'd', 'd', GeomFromText('POINT(105 4)')),
+ ('c', 'z', 'q', GeomFromText('POINT(13 140)')),
+ ('m', 'k', 'i', GeomFromText('POINT(208 120)')),
+ ('g', 'a', 'g', GeomFromText('POINT(9 182)')),
+ ('z', 'j', 'r', GeomFromText('POINT(149 153)')),
+ ('h', 'f', 'g', GeomFromText('POINT(81 236)')),
+ ('m', 'e', 'q', GeomFromText('POINT(209 215)')),
+ ('c', 'h', 'y', GeomFromText('POINT(235 70)')),
+ ('i', 'e', 'g', GeomFromText('POINT(138 26)')),
+ ('m', 't', 'u', GeomFromText('POINT(119 237)')),
+ ('o', 'w', 's', GeomFromText('POINT(193 166)')),
+ ('f', 'm', 'q', GeomFromText('POINT(85 96)')),
+ ('x', 'l', 'x', GeomFromText('POINT(58 115)')),
+ ('x', 'q', 'u', GeomFromText('POINT(108 210)')),
+ ('b', 'h', 'i', GeomFromText('POINT(250 139)')),
+ ('y', 'd', 'x', GeomFromText('POINT(199 135)')),
+ ('w', 'h', 'p', GeomFromText('POINT(247 233)')),
+ ('p', 'z', 't', GeomFromText('POINT(148 249)')),
+ ('q', 'a', 'u', GeomFromText('POINT(174 78)')),
+ ('v', 't', 'm', GeomFromText('POINT(70 228)')),
+ ('t', 'n', 'f', GeomFromText('POINT(123 2)')),
+ ('x', 't', 'b', GeomFromText('POINT(35 50)')),
+ ('r', 'j', 'f', GeomFromText('POINT(200 51)')),
+ ('s', 'q', 'o', GeomFromText('POINT(23 184)')),
+ ('u', 'v', 'z', GeomFromText('POINT(7 113)')),
+ ('v', 'u', 'l', GeomFromText('POINT(145 190)')),
+ ('o', 'k', 'i', GeomFromText('POINT(161 122)')),
+ ('l', 'y', 'e', GeomFromText('POINT(17 232)')),
+ ('t', 'b', 'e', GeomFromText('POINT(120 50)')),
+ ('e', 's', 'u', GeomFromText('POINT(254 1)')),
+ ('d', 'd', 'u', GeomFromText('POINT(167 140)')),
+ ('o', 'b', 'x', GeomFromText('POINT(186 237)')),
+ ('m', 's', 's', GeomFromText('POINT(172 149)')),
+ ('t', 'y', 'a', GeomFromText('POINT(149 85)')),
+ ('x', 't', 'r', GeomFromText('POINT(10 165)')),
+ ('g', 'c', 'e', GeomFromText('POINT(95 165)')),
+ ('e', 'e', 'z', GeomFromText('POINT(98 65)')),
+ ('f', 'v', 'i', GeomFromText('POINT(149 144)')),
+ ('o', 'p', 'm', GeomFromText('POINT(233 67)')),
+ ('t', 'u', 'b', GeomFromText('POINT(109 215)')),
+ ('o', 'o', 'b', GeomFromText('POINT(130 48)')),
+ ('e', 'm', 'h', GeomFromText('POINT(88 189)')),
+ ('e', 'v', 'y', GeomFromText('POINT(55 29)')),
+ ('e', 't', 'm', GeomFromText('POINT(129 55)')),
+ ('p', 'p', 'i', GeomFromText('POINT(126 222)')),
+ ('c', 'i', 'c', GeomFromText('POINT(19 158)')),
+ ('c', 'b', 's', GeomFromText('POINT(13 19)')),
+ ('u', 'y', 'a', GeomFromText('POINT(114 5)')),
+ ('a', 'o', 'f', GeomFromText('POINT(227 232)')),
+ ('t', 'c', 'z', GeomFromText('POINT(63 62)')),
+ ('d', 'o', 'k', GeomFromText('POINT(48 228)')),
+ ('x', 'c', 'e', GeomFromText('POINT(204 2)')),
+ ('e', 'e', 'g', GeomFromText('POINT(125 43)')),
+ ('o', 'r', 'f', GeomFromText('POINT(171 140)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(163 157)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(53 151)') where c1 like 'd%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(96 183)') where c1 like 'r%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(57 91)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 110)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(120 137)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(207 147)') where c1 like 'c%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(31 125)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(27 36)') where c1 like 'r%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('b', 'c', 'e', GeomFromText('POINT(41 137)')),
+ ('p', 'y', 'k', GeomFromText('POINT(50 22)')),
+ ('s', 'c', 'h', GeomFromText('POINT(208 173)')),
+ ('x', 'u', 'l', GeomFromText('POINT(199 175)')),
+ ('s', 'r', 'h', GeomFromText('POINT(85 192)')),
+ ('j', 'k', 'u', GeomFromText('POINT(18 25)')),
+ ('p', 'w', 'h', GeomFromText('POINT(152 197)')),
+ ('e', 'd', 'c', GeomFromText('POINT(229 3)')),
+ ('o', 'x', 'k', GeomFromText('POINT(187 155)')),
+ ('o', 'b', 'k', GeomFromText('POINT(208 150)')),
+ ('d', 'a', 'j', GeomFromText('POINT(70 87)')),
+ ('f', 'e', 'k', GeomFromText('POINT(156 96)')),
+ ('u', 'y', 'p', GeomFromText('POINT(239 193)')),
+ ('n', 'v', 'p', GeomFromText('POINT(223 98)')),
+ ('z', 'j', 'r', GeomFromText('POINT(87 89)')),
+ ('h', 'x', 'x', GeomFromText('POINT(92 0)')),
+ ('r', 'v', 'r', GeomFromText('POINT(159 139)')),
+ ('v', 'g', 'g', GeomFromText('POINT(16 229)')),
+ ('z', 'k', 'u', GeomFromText('POINT(99 52)')),
+ ('p', 'p', 'o', GeomFromText('POINT(105 125)')),
+ ('w', 'h', 'y', GeomFromText('POINT(105 154)')),
+ ('v', 'y', 'z', GeomFromText('POINT(134 238)')),
+ ('x', 'o', 'o', GeomFromText('POINT(178 88)')),
+ ('z', 'w', 'd', GeomFromText('POINT(123 60)')),
+ ('q', 'f', 'u', GeomFromText('POINT(64 90)')),
+ ('s', 'n', 't', GeomFromText('POINT(50 138)')),
+ ('v', 'p', 't', GeomFromText('POINT(114 91)')),
+ ('a', 'o', 'n', GeomFromText('POINT(78 43)')),
+ ('k', 'u', 'd', GeomFromText('POINT(185 161)')),
+ ('w', 'd', 'n', GeomFromText('POINT(25 92)')),
+ ('k', 'w', 'a', GeomFromText('POINT(59 238)')),
+ ('t', 'c', 'f', GeomFromText('POINT(65 87)')),
+ ('g', 's', 'p', GeomFromText('POINT(238 126)')),
+ ('d', 'n', 'y', GeomFromText('POINT(107 173)')),
+ ('l', 'a', 'w', GeomFromText('POINT(125 152)')),
+ ('m', 'd', 'j', GeomFromText('POINT(146 53)')),
+ ('q', 'm', 'c', GeomFromText('POINT(217 187)')),
+ ('i', 'r', 'r', GeomFromText('POINT(6 113)')),
+ ('e', 'j', 'b', GeomFromText('POINT(37 83)')),
+ ('w', 'w', 'h', GeomFromText('POINT(83 199)')),
+ ('k', 'b', 's', GeomFromText('POINT(170 64)')),
+ ('s', 'b', 'c', GeomFromText('POINT(163 130)')),
+ ('c', 'h', 'a', GeomFromText('POINT(141 3)')),
+ ('k', 'j', 'u', GeomFromText('POINT(143 76)')),
+ ('r', 'h', 'o', GeomFromText('POINT(243 92)')),
+ ('i', 'd', 'b', GeomFromText('POINT(205 13)')),
+ ('r', 'y', 'q', GeomFromText('POINT(138 8)')),
+ ('m', 'o', 'i', GeomFromText('POINT(36 45)')),
+ ('v', 'g', 'm', GeomFromText('POINT(0 40)')),
+ ('f', 'e', 'i', GeomFromText('POINT(76 6)')),
+ ('c', 'q', 'q', GeomFromText('POINT(115 248)')),
+ ('x', 'c', 'i', GeomFromText('POINT(29 74)')),
+ ('l', 's', 't', GeomFromText('POINT(83 18)')),
+ ('t', 't', 'a', GeomFromText('POINT(26 168)')),
+ ('u', 'n', 'x', GeomFromText('POINT(200 110)')),
+ ('j', 'b', 'd', GeomFromText('POINT(216 136)')),
+ ('s', 'p', 'w', GeomFromText('POINT(38 156)')),
+ ('f', 'b', 'v', GeomFromText('POINT(29 186)')),
+ ('v', 'e', 'r', GeomFromText('POINT(149 40)')),
+ ('v', 't', 'm', GeomFromText('POINT(184 24)')),
+ ('y', 'g', 'a', GeomFromText('POINT(219 105)')),
+ ('s', 'f', 'i', GeomFromText('POINT(114 130)')),
+ ('e', 'q', 'h', GeomFromText('POINT(203 135)')),
+ ('h', 'g', 'b', GeomFromText('POINT(9 208)')),
+ ('o', 'l', 'r', GeomFromText('POINT(245 79)')),
+ ('s', 's', 'v', GeomFromText('POINT(238 198)')),
+ ('w', 'w', 'z', GeomFromText('POINT(209 232)')),
+ ('v', 'd', 'n', GeomFromText('POINT(30 193)')),
+ ('q', 'w', 'k', GeomFromText('POINT(133 18)')),
+ ('o', 'h', 'o', GeomFromText('POINT(42 140)')),
+ ('f', 'f', 'h', GeomFromText('POINT(145 1)')),
+ ('u', 's', 'r', GeomFromText('POINT(70 62)')),
+ ('x', 'n', 'q', GeomFromText('POINT(33 86)')),
+ ('u', 'p', 'v', GeomFromText('POINT(232 220)')),
+ ('z', 'e', 'a', GeomFromText('POINT(130 69)')),
+ ('r', 'u', 'z', GeomFromText('POINT(243 241)')),
+ ('b', 'n', 't', GeomFromText('POINT(120 12)')),
+ ('u', 'f', 's', GeomFromText('POINT(190 212)')),
+ ('a', 'd', 'q', GeomFromText('POINT(235 191)')),
+ ('f', 'q', 'm', GeomFromText('POINT(176 2)')),
+ ('n', 'c', 's', GeomFromText('POINT(218 163)')),
+ ('e', 'm', 'h', GeomFromText('POINT(163 108)')),
+ ('c', 'f', 'l', GeomFromText('POINT(220 115)')),
+ ('c', 'v', 'q', GeomFromText('POINT(66 45)')),
+ ('w', 'v', 'x', GeomFromText('POINT(251 220)')),
+ ('f', 'w', 'z', GeomFromText('POINT(146 149)')),
+ ('h', 'n', 'h', GeomFromText('POINT(148 128)')),
+ ('y', 'k', 'v', GeomFromText('POINT(28 110)')),
+ ('c', 'x', 'q', GeomFromText('POINT(13 13)')),
+ ('e', 'd', 's', GeomFromText('POINT(91 190)')),
+ ('c', 'w', 'c', GeomFromText('POINT(10 231)')),
+ ('u', 'j', 'n', GeomFromText('POINT(250 21)')),
+ ('w', 'n', 'x', GeomFromText('POINT(141 69)')),
+ ('f', 'p', 'y', GeomFromText('POINT(228 246)')),
+ ('d', 'q', 'f', GeomFromText('POINT(194 22)')),
+ ('d', 'z', 'l', GeomFromText('POINT(233 181)')),
+ ('c', 'a', 'q', GeomFromText('POINT(183 96)')),
+ ('m', 'i', 'd', GeomFromText('POINT(117 226)')),
+ ('z', 'y', 'y', GeomFromText('POINT(62 81)')),
+ ('g', 'v', 'm', GeomFromText('POINT(66 158)'));
+SET @@RAND_SEED1=481064922, @@RAND_SEED2=438133497;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=280535103, @@RAND_SEED2=444518646;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=1072017234, @@RAND_SEED2=484203885;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=358851897, @@RAND_SEED2=358495224;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+SET @@RAND_SEED1=509031459, @@RAND_SEED2=675962925;
+DELETE FROM t1 ORDER BY RAND() LIMIT 10;
+UPDATE t1 set spatial_point=GeomFromText('POINT(61 203)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(202 194)') where c1 like 'f%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(228 18)') where c1 like 'h%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 18)') where c1 like 'l%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(176 94)') where c1 like 'e%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(44 47)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(95 191)') where c1 like 'b%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(179 218)') where c1 like 'y%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(239 40)') where c1 like 'g%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(248 41)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(167 82)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(13 104)') where c1 like 'u%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(139 84)') where c1 like 'a%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(145 108)') where c1 like 'p%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(147 57)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(217 144)') where c1 like 'n%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(160 224)') where c1 like 'w%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(38 28)') where c1 like 'j%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(104 114)') where c1 like 'q%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(88 19)') where c1 like 'c%';
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('f', 'x', 'p', GeomFromText('POINT(92 181)')),
+ ('s', 'i', 'c', GeomFromText('POINT(49 60)')),
+ ('c', 'c', 'i', GeomFromText('POINT(7 57)')),
+ ('n', 'g', 'k', GeomFromText('POINT(252 105)')),
+ ('g', 'b', 'm', GeomFromText('POINT(180 11)')),
+ ('u', 'l', 'r', GeomFromText('POINT(32 90)')),
+ ('c', 'x', 'e', GeomFromText('POINT(143 24)')),
+ ('x', 'u', 'a', GeomFromText('POINT(123 92)')),
+ ('s', 'b', 'h', GeomFromText('POINT(190 108)')),
+ ('c', 'x', 'b', GeomFromText('POINT(104 100)')),
+ ('i', 'd', 't', GeomFromText('POINT(214 104)')),
+ ('r', 'w', 'g', GeomFromText('POINT(29 67)')),
+ ('b', 'f', 'g', GeomFromText('POINT(149 46)')),
+ ('r', 'r', 'd', GeomFromText('POINT(242 196)')),
+ ('j', 'l', 'a', GeomFromText('POINT(90 196)')),
+ ('e', 't', 'b', GeomFromText('POINT(190 64)')),
+ ('l', 'x', 'w', GeomFromText('POINT(250 73)')),
+ ('q', 'y', 'r', GeomFromText('POINT(120 182)')),
+ ('s', 'j', 'a', GeomFromText('POINT(180 175)')),
+ ('n', 'i', 'y', GeomFromText('POINT(124 136)')),
+ ('s', 'x', 's', GeomFromText('POINT(176 209)')),
+ ('u', 'f', 's', GeomFromText('POINT(215 173)')),
+ ('m', 'j', 'x', GeomFromText('POINT(44 140)')),
+ ('v', 'g', 'x', GeomFromText('POINT(177 233)')),
+ ('u', 't', 'b', GeomFromText('POINT(136 197)')),
+ ('f', 'g', 'b', GeomFromText('POINT(10 8)')),
+ ('v', 'c', 'j', GeomFromText('POINT(13 81)')),
+ ('d', 's', 'q', GeomFromText('POINT(200 100)')),
+ ('a', 'p', 'j', GeomFromText('POINT(33 40)')),
+ ('i', 'c', 'g', GeomFromText('POINT(168 204)')),
+ ('k', 'h', 'i', GeomFromText('POINT(93 243)')),
+ ('s', 'b', 's', GeomFromText('POINT(157 13)')),
+ ('v', 'l', 'l', GeomFromText('POINT(103 6)')),
+ ('r', 'b', 'k', GeomFromText('POINT(244 137)')),
+ ('l', 'd', 'r', GeomFromText('POINT(162 254)')),
+ ('q', 'b', 'z', GeomFromText('POINT(136 246)')),
+ ('x', 'x', 'p', GeomFromText('POINT(120 37)')),
+ ('m', 'e', 'z', GeomFromText('POINT(203 167)')),
+ ('q', 'n', 'p', GeomFromText('POINT(94 119)')),
+ ('b', 'g', 'u', GeomFromText('POINT(93 248)')),
+ ('r', 'v', 'v', GeomFromText('POINT(53 88)')),
+ ('y', 'a', 'i', GeomFromText('POINT(98 219)')),
+ ('a', 's', 'g', GeomFromText('POINT(173 138)')),
+ ('c', 'a', 't', GeomFromText('POINT(235 135)')),
+ ('q', 'm', 'd', GeomFromText('POINT(224 208)')),
+ ('e', 'p', 'k', GeomFromText('POINT(161 238)')),
+ ('n', 'g', 'q', GeomFromText('POINT(35 204)')),
+ ('t', 't', 'x', GeomFromText('POINT(230 178)')),
+ ('w', 'f', 'a', GeomFromText('POINT(150 221)')),
+ ('z', 'm', 'z', GeomFromText('POINT(119 42)')),
+ ('l', 'j', 's', GeomFromText('POINT(97 96)')),
+ ('f', 'z', 'x', GeomFromText('POINT(208 65)')),
+ ('i', 'v', 'c', GeomFromText('POINT(145 79)')),
+ ('l', 'f', 'k', GeomFromText('POINT(83 234)')),
+ ('u', 'a', 's', GeomFromText('POINT(250 49)')),
+ ('o', 'k', 'p', GeomFromText('POINT(46 50)')),
+ ('d', 'e', 'z', GeomFromText('POINT(30 198)')),
+ ('r', 'r', 'l', GeomFromText('POINT(78 189)')),
+ ('y', 'l', 'f', GeomFromText('POINT(188 132)')),
+ ('d', 'q', 'm', GeomFromText('POINT(247 107)')),
+ ('p', 'j', 'n', GeomFromText('POINT(148 227)')),
+ ('b', 'o', 'i', GeomFromText('POINT(172 25)')),
+ ('e', 'v', 'd', GeomFromText('POINT(94 248)')),
+ ('q', 'd', 'f', GeomFromText('POINT(15 29)')),
+ ('w', 'b', 'b', GeomFromText('POINT(74 111)')),
+ ('g', 'q', 'f', GeomFromText('POINT(107 215)')),
+ ('o', 'h', 'r', GeomFromText('POINT(25 168)')),
+ ('u', 't', 'w', GeomFromText('POINT(251 188)')),
+ ('h', 's', 'w', GeomFromText('POINT(254 247)')),
+ ('f', 'f', 'b', GeomFromText('POINT(166 103)'));
+SET @@RAND_SEED1=866613816, @@RAND_SEED2=92289615;
+INSERT INTO t1 (c2, c1, c3, spatial_point) VALUES
+ ('l', 'c', 'l', GeomFromText('POINT(202 98)')),
+ ('k', 'c', 'b', GeomFromText('POINT(46 206)')),
+ ('r', 'y', 'm', GeomFromText('POINT(74 140)')),
+ ('y', 'z', 'd', GeomFromText('POINT(200 160)')),
+ ('s', 'y', 's', GeomFromText('POINT(156 205)')),
+ ('u', 'v', 'p', GeomFromText('POINT(86 82)')),
+ ('j', 's', 's', GeomFromText('POINT(91 233)')),
+ ('x', 'j', 'f', GeomFromText('POINT(3 14)')),
+ ('l', 'z', 'v', GeomFromText('POINT(123 156)')),
+ ('h', 'i', 'o', GeomFromText('POINT(145 229)')),
+ ('o', 'r', 'd', GeomFromText('POINT(15 22)')),
+ ('f', 'x', 't', GeomFromText('POINT(21 60)')),
+ ('t', 'g', 'h', GeomFromText('POINT(50 153)')),
+ ('g', 'u', 'b', GeomFromText('POINT(82 85)')),
+ ('v', 'a', 'p', GeomFromText('POINT(231 178)')),
+ ('n', 'v', 'o', GeomFromText('POINT(183 25)')),
+ ('j', 'n', 'm', GeomFromText('POINT(50 144)')),
+ ('e', 'f', 'i', GeomFromText('POINT(46 16)')),
+ ('d', 'w', 'a', GeomFromText('POINT(66 6)')),
+ ('f', 'x', 'a', GeomFromText('POINT(107 197)')),
+ ('m', 'o', 'a', GeomFromText('POINT(142 80)')),
+ ('q', 'l', 'g', GeomFromText('POINT(251 23)')),
+ ('c', 's', 's', GeomFromText('POINT(158 43)')),
+ ('y', 'd', 'o', GeomFromText('POINT(196 228)')),
+ ('d', 'p', 'l', GeomFromText('POINT(107 5)')),
+ ('h', 'a', 'b', GeomFromText('POINT(183 166)')),
+ ('m', 'w', 'p', GeomFromText('POINT(19 59)')),
+ ('b', 'y', 'o', GeomFromText('POINT(178 30)')),
+ ('x', 'w', 'i', GeomFromText('POINT(168 94)')),
+ ('t', 'k', 'z', GeomFromText('POINT(171 5)')),
+ ('r', 'm', 'a', GeomFromText('POINT(222 19)')),
+ ('u', 'v', 'e', GeomFromText('POINT(224 80)')),
+ ('q', 'r', 'k', GeomFromText('POINT(212 218)')),
+ ('d', 'p', 'j', GeomFromText('POINT(169 7)')),
+ ('d', 'r', 'v', GeomFromText('POINT(193 23)')),
+ ('n', 'y', 'y', GeomFromText('POINT(130 178)')),
+ ('m', 'z', 'r', GeomFromText('POINT(81 200)')),
+ ('j', 'e', 'w', GeomFromText('POINT(145 239)')),
+ ('v', 'h', 'x', GeomFromText('POINT(24 105)')),
+ ('z', 'm', 'a', GeomFromText('POINT(175 129)')),
+ ('b', 'c', 'v', GeomFromText('POINT(213 10)')),
+ ('t', 't', 'u', GeomFromText('POINT(2 129)')),
+ ('r', 's', 'v', GeomFromText('POINT(209 192)')),
+ ('x', 'p', 'g', GeomFromText('POINT(43 63)')),
+ ('t', 'e', 'u', GeomFromText('POINT(139 210)')),
+ ('l', 'e', 't', GeomFromText('POINT(245 148)')),
+ ('a', 'i', 'k', GeomFromText('POINT(167 195)')),
+ ('m', 'o', 'h', GeomFromText('POINT(206 120)')),
+ ('g', 'z', 's', GeomFromText('POINT(169 240)')),
+ ('z', 'u', 's', GeomFromText('POINT(202 120)')),
+ ('i', 'b', 'a', GeomFromText('POINT(216 18)')),
+ ('w', 'y', 'g', GeomFromText('POINT(119 236)')),
+ ('h', 'y', 'p', GeomFromText('POINT(161 24)'));
+UPDATE t1 set spatial_point=GeomFromText('POINT(33 100)') where c1 like 't%';
+UPDATE t1 set spatial_point=GeomFromText('POINT(41 46)') where c1 like 'f%';
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Bug #30286 spatial index cause corruption and server crash!
+#
+
+create table t1 (a geometry not null, spatial index(a)) transactional=0 row_format=page;
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 131072)));
+insert into t1 values (PointFromWKB(POINT(9.1248812352444e+192, 2.9740338169556e+284)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, -0)));
+insert into t1 values (PointFromWKB(POINT(1.49166814624e-154, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(4.0917382598702e+149, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 2.9993936277913e-241)));
+insert into t1 values (PointFromWKB(POINT(2.5243548967072e-29, 1.2024538023802e+111)));
+insert into t1 values (PointFromWKB(POINT(0, 6.9835074892995e-251)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 3.1050361846014e+231)));
+insert into t1 values (PointFromWKB(POINT(2.8728483499323e-188, 2.4600631144627e+260)));
+insert into t1 values (PointFromWKB(POINT(3.0517578125e-05, 2.0349165139404e+236)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 1.1818212630766e-125)));
+insert into t1 values (PointFromWKB(POINT(2.481040258324e-265, 5.7766220027675e-275)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 2.5243548967072e-29)));
+insert into t1 values (PointFromWKB(POINT(5.7766220027675e-275, 9.9464647281957e+86)));
+insert into t1 values (PointFromWKB(POINT(2.2181357552967e+130, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.6893488147419e+19)));
+insert into t1 values (PointFromWKB(POINT(4.5767114681874e-246, 3.7537584144024e+255)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 1.8033161362863e-130)));
+insert into t1 values (PointFromWKB(POINT(0, 5.8774717541114e-39)));
+insert into t1 values (PointFromWKB(POINT(1.1517219314031e+164, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(6.243497100632e+144, 3.7857669957337e-270)));
+insert into t1 values (PointFromWKB(POINT(3.7857669957337e-270, 2.6355494858076e-82)));
+insert into t1 values (PointFromWKB(POINT(2.0349165139404e+236, 3.8518598887745e-34)));
+insert into t1 values (PointFromWKB(POINT(4.6566128730774e-10, 2.0880974297595e-53)));
+insert into t1 values (PointFromWKB(POINT(2.0880974297595e-53, 1.8827498946116e-183)));
+insert into t1 values (PointFromWKB(POINT(1.8033161362863e-130, 9.1248812352444e+192)));
+insert into t1 values (PointFromWKB(POINT(4.7783097267365e-299, 2.2761049594727e-159)));
+insert into t1 values (PointFromWKB(POINT(1.94906280228e+289, 1.2338789709327e-178)));
+drop table t1;
+
+# End of 4.1 tests
+
+#
+# bug #21790 (UNKNOWN ERROR on NULLs in RTree)
+#
+CREATE TABLE t1(foo GEOMETRY NOT NULL, SPATIAL INDEX(foo) ) transactional=0 row_format=page;
+--error 1048
+INSERT INTO t1(foo) VALUES (NULL);
+--error 1416
+INSERT INTO t1() VALUES ();
+--error 1416
+INSERT INTO t1(foo) VALUES ('');
+DROP TABLE t1;
+
+#
+# Bug #23578: Corruption prevents Optimize table from working properly with a
+# spatial index
+#
+
+CREATE TABLE t1 (a INT AUTO_INCREMENT, b POINT NOT NULL, KEY (a), SPATIAL KEY (b)) transactional=0 row_format=page;
+
+INSERT INTO t1 (b) VALUES (GeomFromText('POINT(1 2)'));
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+INSERT INTO t1 (b) SELECT b FROM t1;
+
+OPTIMIZE TABLE t1;
+DROP TABLE t1;
+
+
+#
+# Bug #29070: Error in spatial index
+#
+
+CREATE TABLE t1 (a INT, b GEOMETRY NOT NULL, SPATIAL KEY b(b)) transactional=0 row_format=page;
+INSERT INTO t1 VALUES (1, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+INSERT INTO t1 VALUES (2, GEOMFROMTEXT('LINESTRING(1102218.456 1,2000000 2)'));
+
+# must return the same number as the next select
+SELECT COUNT(*) FROM t1 WHERE
+ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE
+ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') );
+
+DROP TABLE t1;
+
+--echo End of 5.0 tests.
diff --git a/mysql-test/suite/maria/t/maria-mvcc.test b/mysql-test/suite/maria/t/maria-mvcc.test
new file mode 100644
index 00000000000..4b6f8a3996d
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-mvcc.test
@@ -0,0 +1,108 @@
+#
+# Testing insert and select on a table with two threads
+# using locking
+#
+
+-- source include/have_maria.inc
+set global maria_page_checksum=1;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+connect (con1,localhost,root,,);
+connection con1;
+
+create table t1 (i int) engine=maria;
+show create table t1;
+
+# versioning is disabled when table is empty, so insert a row
+insert into t1 values (0);
+
+lock tables t1 write concurrent;
+insert into t1 values (1);
+insert into t1 values (2);
+/* should see 0, 1 and 2 */
+select i from t1;
+select count(*) from t1;
+
+connect (con2,localhost,root,,);
+connection con2;
+/* should see 0 */
+select i from t1;
+select count(*) from t1;
+lock tables t1 write concurrent;
+insert into t1 values (3);
+insert into t1 values (4);
+/* should see 0, 3 and 4 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+lock tables t1 write concurrent;
+insert into t1 values (5);
+/* should see 0, 3, 4 and 5 */
+select i from t1;
+select count(*) from t1;
+
+connect (con3,localhost,root,,);
+connection con3;
+lock tables t1 write concurrent;
+/* should see 0, 3, 4 */
+select i from t1;
+select count(*) from t1;
+
+connection con1;
+insert into t1 values (6);
+/* Should see 0, 1, 2, 6 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+lock tables t1 write concurrent;
+/* Should see 0, 1, 2, 3, 4 and 6 */
+select i from t1;
+select count(*) from t1;
+
+connection con2;
+/* should see 0, 3, 4, 5 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+/* should see 0, 1, 2, 3, 4, 5, 6 */
+select i from t1;
+select count(*) from t1;
+
+connection con1;
+unlock tables;
+/* should see 0, 1, 2, 3, 4, 5, 6 */
+select i from t1;
+select count(*) from t1;
+
+connection con3;
+insert into t1 values (7);
+/* should see 0, 3, 4, 7 */
+select i from t1;
+select count(*) from t1;
+unlock tables;
+/* should see 0, 1, 2, 3, 4, 5, 6, 7 */
+select i from t1;
+select count(*) from t1;
+
+connection default;
+drop table t1;
+
+#
+# Test count(*) for not versioned tables
+#
+
+CREATE TABLE t1 (fid INT NOT NULL AUTO_INCREMENT PRIMARY KEY, g GEOMETRY NOT NULL, SPATIAL KEY(g) ) transactional=1 row_format=page engine=maria;
+
+lock tables t1 write concurrent, t1 as t2 write concurrent;
+insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
+select fid from t1 as t2;
+select count(*) from t1 as t2;
+insert into t1 (fid,g) values (NULL,GeomFromText('LineString(0 0,1 1)'));
+select fid from t1 as t2;
+select count(*) from t1 as t2;
+unlock tables;
+drop table t1;
+
diff --git a/mysql-test/suite/maria/t/maria-no-logging.test b/mysql-test/suite/maria/t/maria-no-logging.test
new file mode 100644
index 00000000000..bca99848250
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-no-logging.test
@@ -0,0 +1,83 @@
+# test of cases where we can safely disable logging
+
+--source include/have_maria.inc
+# can't restart server in embedded
+--source include/not_embedded.inc
+
+set global maria_log_file_size=4294967295;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+
+connect (admin, localhost, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+# checkpoints can make log unrepeatable
+let $def_checkinterval=`select @@global.maria_checkpoint_interval`;
+set global maria_checkpoint_interval=0;
+
+# Prepare table to help for big load
+create table t2 (a varchar(100)) engine=myisam;
+insert into t2 select repeat('z',100);
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+
+# INSERT SELECT
+
+# no optimization because table not empty
+
+# SHOW ENGINE MARIA LOGS could be influenced by older logs
+-- source include/maria_empty_logs.inc
+create table t1 (a varchar(100)) engine=maria transactional=1;
+show create table t1;
+--replace_regex /; .+maria_log/maria_log/
+show engine maria logs;
+
+insert into t1 values('a');
+insert into t1 select * from t2;
+--replace_regex /; .+maria_log/maria_log/
+show engine maria logs;
+
+# optimization because table is empty
+-- source include/maria_empty_logs.inc
+truncate table t1;
+insert into t1 select * from t2;
+--replace_regex /; .+maria_log/maria_log/
+show engine maria logs;
+
+drop table t1;
+
+# same for CREATE SELECT
+
+# no optimization because table not empty
+-- source include/maria_empty_logs.inc
+create table t1 (a varchar(100)) engine=maria transactional=1;
+insert into t1 values('a');
+create table if not exists t1 select * from t2;
+--replace_regex /; .+maria_log/maria_log/
+show engine maria logs;
+
+# optimization because table is empty
+-- source include/maria_empty_logs.inc
+drop table t1;
+create table t1 engine=maria transactional=1 select * from t2;
+--replace_regex /; .+maria_log/maria_log/
+show engine maria logs;
+
+drop database mysqltest;
+
+--disable_result_log
+--disable_query_log
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria-page-checksum.test b/mysql-test/suite/maria/t/maria-page-checksum.test
new file mode 100644
index 00000000000..7ab66851d0d
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-page-checksum.test
@@ -0,0 +1,1559 @@
+# Tests for two bugs related to ALTER TABLE and maria-specific alter
+# options (PAGE_CHECKSUM and TRANSACTIONAL).
+
+-- source include/have_maria.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+#
+# Test for BUG#35441 "Cannot change PAGE_CHECKSUM table option"
+#
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+select @@global.maria_page_checksum;
+
+# we scan through combinations in the cartesian product of
+# (first value of maria_page_checksum) x (clauses in CREATE TABLE) x
+# (second value of maria_page_checksum) x (clauses in ALTER TABLE).
+
+--echo # iteration 1
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 2
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 3
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 4
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 5
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 6
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 7
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 8
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 9
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 10
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 11
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 12
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 13
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 14
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 15
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 16
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 17
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 18
+set global maria_page_checksum = 0 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 19
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 20
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 21
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 22
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 23
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 24
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 25
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 26
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 27
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 28
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 29
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 30
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 31
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 32
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 33
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 0 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 34
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 engine=maria ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 35
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=0 ;
+show create table t1 /* expecting PAGE_CHECKSUM=0 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+--echo # iteration 36
+set global maria_page_checksum = 1 ;
+create table t1(a int) engine=maria PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+set global maria_page_checksum = 1 ;
+alter table t1 PAGE_CHECKSUM=1 ;
+show create table t1 /* expecting PAGE_CHECKSUM=1 */ ;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ my @content= grep(/Page checksums are used/, <FILE>);
+ print @content ? $content[0] : "Page checksums are not used\n";
+ close FILE;
+EOF
+drop table t1;
+
+#
+# Test for BUG#37005
+# "Maria: ALTER TABLE TRANSACTIONAL=0 leaves table transactional inside Maria"
+#
+
+# we scan through combinations in the cartesian product of
+# (clauses in CREATE TABLE) x (clauses in ALTER TABLE).
+
+--echo # iteration 1
+create table t1(a int) engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 modify a bigint ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 2
+create table t1(a int) engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 3
+create table t1(a int) engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 4
+create table t1(a int) engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 5
+create table t1(a int) engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 6
+create table t1(a int) engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 7
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 modify a bigint ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 8
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 9
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 10
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 11
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 12
+create table t1(a int) engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 13
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 modify a bigint ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 14
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 15
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 16
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 17
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria transactional=0 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
+--echo # iteration 18
+create table t1(a int) engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+
+alter table t1 engine=maria transactional=1 ;
+show create table t1;
+--exec $MARIA_CHK -dv $MYSQLD_DATADIR/test/t1 >$MYSQLTEST_VARDIR/tmp/mariachk.txt
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLTEST_VARDIR'}/tmp/mariachk.txt";
+ open(FILE, "<", $fname) or die;
+ print grep(/Crashsafe/, <FILE>);
+ close FILE;
+EOF
+drop table t1;
+
+
diff --git a/mysql-test/suite/maria/t/maria-preload-master.opt b/mysql-test/suite/maria/t/maria-preload-master.opt
new file mode 100644
index 00000000000..959cf74c816
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-preload-master.opt
@@ -0,0 +1 @@
+--skip-safemalloc
diff --git a/mysql-test/suite/maria/t/maria-preload.test b/mysql-test/suite/maria/t/maria-preload.test
new file mode 100644
index 00000000000..49829a686e3
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-preload.test
@@ -0,0 +1,124 @@
+#
+# Testing of PRELOAD
+#
+
+-- source include/have_maria.inc
+
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+
+# Background dirty pages flushing may influence page cache stats:
+let $def_checkinterval=`select @@global.maria_checkpoint_interval`;
+set global maria_checkpoint_interval=0;
+
+# Work around BUG#34911 "FLUSH STATUS doesn't flush what it should":
+# compute differences in status variables before and after relevant
+# queries. Maria_pagecache_read_requests varies accross machines.
+create temporary table initial
+select variable_name,variable_value from
+information_schema.global_status where variable_name like "Maria_pagecache_reads";
+
+# we don't use block-format because we want page cache stats
+# about indices and not data pages.
+
+create table t1 (
+ a int not null auto_increment,
+ b char(16) not null,
+ primary key (a),
+ key (b)
+) engine=maria row_format=dynamic;
+
+create table t2(
+ a int not null auto_increment,
+ b char(16) not null,
+ primary key (a),
+ key (b)
+) engine=maria row_format=dynamic;
+
+insert into t1(b) values
+ ('test0'),
+ ('test1'),
+ ('test2'),
+ ('test3'),
+ ('test4'),
+ ('test5'),
+ ('test6'),
+ ('test7');
+
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+insert into t2(b) select b from t1;
+insert into t1(b) select b from t2;
+
+select count(*) from t1;
+select count(*) from t2;
+
+flush tables; flush status;
+let $show_stat=select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
+eval $show_stat;
+select count(*) from t1 where b = 'test1';
+eval $show_stat;
+select count(*) from t1 where b = 'test1';
+eval $show_stat;
+
+flush tables; flush status;
+select @@preload_buffer_size;
+load index into cache t1;
+eval $show_stat;
+select count(*) from t1 where b = 'test1';
+eval $show_stat;
+
+flush tables; flush status;
+eval $show_stat;
+set session preload_buffer_size=256*1024;
+select @@preload_buffer_size;
+load index into cache t1 ignore leaves;
+eval $show_stat;
+select count(*) from t1 where b = 'test1';
+eval $show_stat;
+
+flush tables; flush status;
+eval $show_stat;
+set session preload_buffer_size=1*1024;
+select @@preload_buffer_size;
+load index into cache t1, t2 key (primary,b) ignore leaves;
+eval $show_stat;
+select count(*) from t1 where b = 'test1';
+select count(*) from t2 where b = 'test1';
+eval $show_stat;
+
+flush tables; flush status;
+eval $show_stat;
+load index into cache t3, t2 key (primary,b) ;
+eval $show_stat;
+flush tables; flush status;
+eval $show_stat;
+load index into cache t3 key (b), t2 key (c) ;
+eval $show_stat;
+
+drop table t1, t2;
+drop temporary table initial;
+
+# check that Maria didn't use key cache
+show status like "key_read%";
+
+--disable_result_log
+--disable_query_log
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria-purge.test b/mysql-test/suite/maria/t/maria-purge.test
new file mode 100644
index 00000000000..0aa720543f6
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-purge.test
@@ -0,0 +1,118 @@
+-- source include/have_maria.inc
+-- source include/big_test.inc
+-- source include/not_embedded.inc
+
+# pre-requisites for maria_empty_logs
+connect (admin, localhost, root,,test,,);
+#
+--enable_reconnect
+connection default;
+--enable_reconnect
+# end of pre-requisites
+
+# SHOW ENGINE MARIA LOGS could be influenced by older logs
+# Also, possibly automatic checkpoints (see if that happens in
+# practice)
+-- source include/maria_empty_logs.inc
+
+let $default=`select @@global.storage_engine`;
+set global storage_engine=maria;
+set session storage_engine=maria;
+let $def_logsize=`select @@global.maria_log_file_size`;
+let $def_checkinterval=`select @@global.maria_checkpoint_interval`;
+
+set global maria_log_file_size=4294967295;
+# Initialise
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+SET SQL_WARNINGS=1;
+
+CREATE TABLE t1 (
+ STRING_DATA char(255) default NULL
+);
+CREATE TABLE t2 (
+ STRING_DATA char(255) default NULL
+);
+
+
+INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
+INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD');
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+
+set global maria_log_file_size=16777216;
+# force a checkpoint to allow log purge
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+
+insert into t2 select * from t1;
+insert into t1 select * from t2;
+
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+set global maria_log_file_size=16777216;
+select @@global.maria_log_file_size;
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+set global maria_log_file_size=8388608;
+select @@global.maria_log_file_size;
+
+set global maria_log_purge_type=at_flush;
+insert into t1 select * from t2;
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+flush logs;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+
+set global maria_log_file_size=16777216;
+set global maria_log_purge_type=external;
+insert into t1 select * from t2;
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+flush logs;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+
+set global maria_log_purge_type=immediate;
+insert into t1 select * from t2;
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--replace_regex /Size +[0-9]+ ; .+maria_log/maria_log/
+SHOW ENGINE maria logs;
+
+drop table t1, t2;
+
+--disable_result_log
+--disable_query_log
+set global maria_log_purge_type=immediate;
+eval set global storage_engine=$default;
+eval set global maria_log_file_size=$def_logsize;
+eval set global maria_checkpoint_interval=$def_checkinterval;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria-recover-master.opt b/mysql-test/suite/maria/t/maria-recover-master.opt
new file mode 100644
index 00000000000..0cdefeadf3d
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recover-master.opt
@@ -0,0 +1 @@
+--loose-maria-recover=backup --loose-maria-log-dir-path=$MYSQLTEST_VARDIR/tmp
diff --git a/mysql-test/suite/maria/t/maria-recover.test b/mysql-test/suite/maria/t/maria-recover.test
new file mode 100644
index 00000000000..b9cec2eadf1
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recover.test
@@ -0,0 +1,65 @@
+# Test of the --maria-recover option.
+
+--source include/have_maria.inc
+
+call mtr.add_suppression("Checking table: '.\/mysqltest\/t_corrupted2'");
+call mtr.add_suppression("Recovering table: '.\/mysqltest\/t_corrupted2'");
+call mtr.add_suppression("Table '.\/mysqltest\/t_corrupted2' is marked as crashed and should be repaired");
+
+# Note: we're setting an environment variable (not prefixing it by $),
+# so that the perl code below can access it.
+let MYSQLD_DATADIR= `select @@datadir`;
+
+select @@global.maria_recover;
+set global maria_recover=off;
+select @@global.maria_recover;
+set global maria_recover=default;
+select @@global.maria_recover;
+set global maria_recover=normal;
+select @@global.maria_recover;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+
+use mysqltest;
+
+create table t1 (a varchar(1000), index(a)) engine=maria;
+insert into t1 values("ThursdayMorningsMarket");
+
+flush table t1; # put index page on disk
+insert into t1 select concat(a,'b') from t1 limit 1;
+# now t1 has its open_count>0 and so will t2_corrupted.
+# It is not named t2 because the corruption messages which will be put
+# in the error log need to be detected in mtr_process.pl, and we want
+# a specific name to do specific detection (don't want to ignore
+# any corruption messages of other tests using "t2" as table).
+
+copy_file $MYSQLD_DATADIR/mysqltest/t1.frm $MYSQLD_DATADIR/mysqltest/t_corrupted2.frm;
+copy_file $MYSQLD_DATADIR/mysqltest/t1.MAD $MYSQLD_DATADIR/mysqltest/t_corrupted2.MAD;
+copy_file $MYSQLD_DATADIR/mysqltest/t1.MAI $MYSQLD_DATADIR/mysqltest/t_corrupted2.MAI;
+
+# Ruin the index file.
+# If maria-block-size is smaller than the default, the corruption
+# messages will differ.
+perl;
+ use strict;
+ use warnings;
+ my $fname= "$ENV{'MYSQLD_DATADIR'}/mysqltest/t_corrupted2.MAI";
+ open(FILE, "+<", $fname) or die;
+ my $whatever= ("\xAB" x 100);
+ sysseek (FILE, 8192, 0) or die;
+ syswrite (FILE, $whatever) or die;
+ close FILE;
+EOF
+
+# line below will be removed
+disable_ps_protocol;
+replace_regex /Table.*t_corrupted2/t_corrupted2/ ;
+select * from t_corrupted2; # should show corruption and repair messages
+enable_ps_protocol;
+select * from t_corrupted2; # should show just rows
+
+drop database mysqltest;
+set global maria_recover=backup;
diff --git a/mysql-test/suite/maria/t/maria-recovery-big-master.opt b/mysql-test/suite/maria/t/maria-recovery-big-master.opt
new file mode 100644
index 00000000000..d24a11c924f
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery-big-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file --max_allowed_packet=32000000
diff --git a/mysql-test/suite/maria/t/maria-recovery-big.test b/mysql-test/suite/maria/t/maria-recovery-big.test
new file mode 100644
index 00000000000..4de8f934ec1
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery-big.test
@@ -0,0 +1,69 @@
+# Maria recovery test which cannot run in shared memory
+# because it generates too much data, or which takes a lot of time.
+
+--source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur as we crash
+--source include/not_valgrind.inc
+# Binary must be compiled with debug for crash to occur
+--source include/have_debug.inc
+--source include/have_maria.inc
+--source include/big_test.inc
+
+set global maria_log_file_size=4294967295;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+# Include scripts can perform SQL. For it to not influence the main test
+# they use a separate connection. This way if they use a DDL it would
+# not autocommit in the main test.
+connect (admin, localhost, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+#
+# Test with big blobs
+#
+
+--echo * TEST of recovery with blobs
+-- source include/maria_empty_logs.inc
+create table t1 (a int, b longtext) engine=maria table_checksum=1;
+let $mms_tables=1;
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+insert into t1 values (1,"123456789012345678901234567890"),(2,"09876543210987654321");
+-- source include/maria_make_snapshot_for_comparison.inc
+lock table t1 write;
+let $loop=20;
+while ($loop)
+{
+ update t1 set b=CONCAT(b,b);
+ dec $loop;
+}
+select a,length(b) from t1;
+let $loop=22;
+while ($loop)
+{
+ update t1 set b=mid(b,1,length(b)/2);
+ dec $loop;
+}
+select a,length(b) from t1;
+# we want recovery to run on the first snapshot made above
+let $mvr_restore_old_snapshot=1;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
+# clean up everything
+let $mms_purpose=feeding_recovery;
+eval drop database mysqltest_for_$mms_purpose;
+let $mms_purpose=comparison;
+eval drop database mysqltest_for_$mms_purpose;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria-recovery-bitmap-master.opt b/mysql-test/suite/maria/t/maria-recovery-bitmap-master.opt
new file mode 100644
index 00000000000..425fda95086
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery-bitmap-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file
diff --git a/mysql-test/suite/maria/t/maria-recovery-bitmap.test b/mysql-test/suite/maria/t/maria-recovery-bitmap.test
new file mode 100644
index 00000000000..286d44b4ff8
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery-bitmap.test
@@ -0,0 +1,75 @@
+# Tests of Maria's recovery of the bitmap pages
+
+--source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur as we crash
+--source include/not_valgrind.inc
+# Binary must be compiled with debug for crash to occur
+--source include/have_debug.inc
+--source include/have_maria.inc
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+# Include scripts can perform SQL. For it to not influence the main test
+# they use a separate connection. This way if they use a DDL it would
+# not autocommit in the main test.
+connect (admin, localhost, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+-- source include/maria_empty_logs.inc
+let $mms_tables=1;
+create table t1 (a varchar(10000)) engine=maria;
+
+# we want recovery to use the tables as they were at time of crash
+let $mvr_restore_old_snapshot=0;
+# UNDO phase prevents physical comparison, normally,
+# so we'll only use checksums to compare.
+let $mms_compare_physically=0;
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+
+--echo * TEST of over-allocated bitmap not flushed by checkpoint
+let $mvr_debug_option="+d,maria_crash";
+insert into t1 values ("bbbbbbb");
+-- source include/maria_make_snapshot_for_comparison.inc
+# make_snapshot_for_comparison closed the table, which lost its id.
+# So we make a null operation just to give a short id to the table so
+# that checkpoint includes table in checkpoint (otherwise nothing to
+# test).
+insert into t1 values ("bbbbbbb");
+delete from t1 limit 1;
+set session debug="+d,info,enter,exit,maria_over_alloc_bitmap";
+send insert into t1 values ("aaaaaaaaa");
+connection admin;
+# Leave time for INSERT to block after modifying bitmap;
+# in the future we should not use sleep but something like
+# debug_sync_point().
+sleep 5;
+# force a checkpoint, which could, if buggy, flush over-allocated
+# bitmap page; as REDO-UNDO was not written, bitmap and data page
+# would be inconsistent. Correct checkpoint will wait until UNDO is
+# written.
+set global maria_checkpoint_interval=1;
+-- source include/maria_verify_recovery.inc
+
+--echo * TEST of bitmap flushed without REDO-UNDO in the log (WAL violation)
+# before crashing we'll flush the bitmap page
+let $mvr_debug_option="+d,maria_flush_bitmap,maria_crash";
+-- source include/maria_make_snapshot_for_comparison.inc
+lock tables t1 write;
+insert into t1 values (REPEAT('a', 6000));
+# bitmap of after-INSERT will be on disk, but data pages will not; if
+# log is not flushed the bitmap is inconsistent with the data.
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
+# clean up everything
+let $mms_purpose=comparison;
+eval drop database mysqltest_for_$mms_purpose;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria-recovery-master.opt b/mysql-test/suite/maria/t/maria-recovery-master.opt
new file mode 100644
index 00000000000..9023fb74e8b
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file --loose-maria-log-dir-path=$MYSQLTEST_VARDIR/tmp
diff --git a/mysql-test/suite/maria/t/maria-recovery-rtree-ft-master.opt b/mysql-test/suite/maria/t/maria-recovery-rtree-ft-master.opt
new file mode 100644
index 00000000000..425fda95086
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery-rtree-ft-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file
diff --git a/mysql-test/suite/maria/t/maria-recovery-rtree-ft.test b/mysql-test/suite/maria/t/maria-recovery-rtree-ft.test
new file mode 100644
index 00000000000..3ede5002b72
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery-rtree-ft.test
@@ -0,0 +1,217 @@
+# Test of Recovery of R-tree (table t1) and fulltext (table t2) indices
+
+--source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur as we crash
+--source include/not_valgrind.inc
+# Binary must be compiled with debug for crash to occur
+--source include/have_debug.inc
+--source include/have_maria.inc
+
+set global maria_log_file_size=4294967295;
+let $MARIA_LOG=.;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+# Include scripts can perform SQL. For it to not influence the main test
+# they use a separate connection. This way if they use a DDL it would
+# not autocommit in the main test.
+connect (admin, localhost, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+-- source include/maria_empty_logs.inc
+let $mms_tables=2;
+
+CREATE TABLE t1 (
+ line LINESTRING NOT NULL,
+ kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+ name VARCHAR(32)
+ ,SPATIAL key (line)
+) transactional=1 row_format=page engine=maria;
+SHOW INDEX FROM t1;
+CREATE TABLE t2 (a VARCHAR(200), b TEXT, FULLTEXT (a,b)
+) transactional=1 row_format=page engine=maria;
+SHOW INDEX FROM t2;
+
+let $query1= INSERT INTO t1 (name, kind, line) VALUES
+ ("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+ ("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+ ("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+ ("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+ ("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+ ("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+ ("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+ ("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+ ("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+ ("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+ ("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+ ("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+ ("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+ ("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+ ("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+ ("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+ ("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+ ("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+ ("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+ ("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+ ("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+ ("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+ ("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+
+let $query2= INSERT INTO t2 VALUES
+ ('MySQL has now support', 'for full-text search'),
+ ('Full-text indexes', 'are called collections'),
+ ('Only MyISAM tables','support collections'),
+ ('Function MATCH ... AGAINST()','is used to do a search'),
+ ('Full-text search in MySQL', 'implements vector space model'),
+ ('We want to see', 'if this is recoverable'),
+ ('Or rather leaves a bad corrupted table', 'after a crash'),
+ ('Test of REDOs', 'and then UNDOs'),
+ ('Recovery is interesting', 'but sometimes complicated'),
+ ('But what if it was simple', 'and boring?'),
+ ('I wish I knew more', 'about how fulltext works'),
+ ('Maybe I should read about it', 'on the Internet');
+
+--echo * TEST of REDO: see if recovery can reconstruct if we give it an old table
+
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+
+--disable_query_log
+let $1=120; # 8 is smallest value to cause root split; 12 for child split
+while($1)
+{
+ eval $query1;
+ eval $query2;
+ dec $1;
+}
+let $1=120;
+while($1)
+{
+ delete from t1 limit 1;
+ delete from t1 limit 10;
+ delete from t1 limit 7;
+ delete from t1 limit 2;
+ delete from t2 limit 6;
+ dec $1;
+}
+--enable_query_log
+-- source include/maria_make_snapshot_for_comparison.inc
+# we want recovery to run on the first snapshot made above
+let $mvr_restore_old_snapshot=1;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+# the script below will trigger recovery and compare checksums
+-- source include/maria_verify_recovery.inc
+
+# Test of REDO + UNDO
+--echo * TEST of INSERT and DELETE's rollback
+
+# different types of crash => a loop; here are loop control variables
+let $crash_no_flush=1;
+let $crash_flush_whole_page_cache=0;
+let $crash_flush_states=0;
+let $crash_flush_whole_log=0;
+let $crash_loop=1;
+
+# we want recovery to use the tables as they were at time of crash
+let $mvr_restore_old_snapshot=0;
+# UNDO phase prevents physical comparison, normally,
+# so we'll only use checksums to compare.
+let $mms_compare_physically=0;
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+
+# Note that we don't remove logs between iterations. Test is
+# cumulative (each new recovery processes more log records than the previous).
+
+while ($crash_loop)
+{
+ if ($crash_flush_whole_log)
+ {
+ let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+ # set up what next iteration should do:
+ let $crash_flush_whole_log=0;
+ let $crash_loop=0;
+ }
+ if ($crash_flush_states)
+ {
+ let $mvr_debug_option="+d,maria_flush_states,maria_flush_whole_log,maria_crash";
+ let $crash_flush_states=0;
+ let $crash_flush_whole_log=1;
+ }
+ if ($crash_flush_whole_page_cache)
+ {
+ let $mvr_debug_option="+d,maria_flush_whole_page_cache,maria_crash";
+ let $crash_flush_whole_page_cache=0;
+ let $crash_flush_states=1;
+ }
+ if ($crash_no_flush)
+ {
+ let $mvr_debug_option="+d,maria_crash";
+ let $crash_no_flush=0;
+ let $crash_flush_whole_page_cache=1;
+ }
+ # Your committed statements here
+ -- source include/maria_make_snapshot_for_comparison.inc
+ # Your statements which we expect to be rolled back
+ lock tables t1 write, t2 write;
+
+ --disable_query_log
+ let $1=120;
+ while($1)
+ {
+ eval $query1;
+ eval $query2;
+ dec $1;
+ }
+ let $1=120;
+ while($1)
+ {
+ delete from t1 limit 1;
+ delete from t1 limit 10;
+ delete from t1 limit 7;
+ delete from t1 limit 2;
+ delete from t2 limit 6;
+ dec $1;
+ }
+ --enable_query_log
+
+ -- source include/maria_verify_recovery.inc
+}
+
+# Finally check when we make the table empty
+# This is currently hitting BUG#36319 so is disabled
+
+if (0)
+{
+-- source include/maria_make_snapshot_for_comparison.inc
+lock tables t1 write, t2 write;
+select count(*) from t1;
+delete from t1;
+select count(*) from t1;
+select count(*) from t2;
+delete from t2;
+select count(*) from t2;
+}
+
+-- source include/maria_verify_recovery.inc
+
+# clean up everything
+let $mms_purpose=feeding_recovery;
+eval drop database mysqltest_for_$mms_purpose;
+let $mms_purpose=comparison;
+eval drop database mysqltest_for_$mms_purpose;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria-recovery.test b/mysql-test/suite/maria/t/maria-recovery.test
new file mode 100644
index 00000000000..6ba8e65e658
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery.test
@@ -0,0 +1,203 @@
+--source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur as we crash
+--source include/not_valgrind.inc
+# Binary must be compiled with debug for crash to occur
+--source include/have_debug.inc
+--source include/have_maria.inc
+
+set global maria_log_file_size=4294967295;
+let $MARIA_LOG=../../tmp;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+# Include scripts can perform SQL. For it to not influence the main test
+# they use a separate connection. This way if they use a DDL it would
+# not autocommit in the main test.
+connect (admin, localhost, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+# A sample test
+-- source include/maria_empty_logs.inc
+let $mms_tables=1;
+create table t1 (a varchar(1000)) engine=maria;
+
+--echo * TEST of REDO: see if recovery can reconstruct if we give it an old table
+
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+# Your committed statements here, which we expect to
+# be reconstructed from the log
+insert into t1 values ("00000000");
+-- source include/maria_make_snapshot_for_comparison.inc
+# we want recovery to run on the first snapshot made above
+let $mvr_restore_old_snapshot=1;
+# As we did only committed work, we test REDO applying, which could
+# produce a physically identical table.
+let $mms_compare_physically=1;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+# the script below will trigger recovery and compare checksums
+-- source include/maria_verify_recovery.inc
+let $mms_compare_physically=0;
+# so a SELECT like this is pure visual effect, brings nothing.
+select * from t1;
+
+--echo * TEST of REDO+UNDO: normal recovery test (no moving tables under its feet)
+
+# different types of crash => a loop; here are loop control variables
+let $crash_no_flush=1;
+let $crash_flush_whole_page_cache=0;
+let $crash_flush_states=0;
+let $crash_flush_whole_log=0;
+let $crash_loop=1;
+
+# we want recovery to use the tables as they were at time of crash
+let $mvr_restore_old_snapshot=0;
+# UNDO phase prevents physical comparison, normally,
+# so we'll only use checksums to compare.
+let $mms_compare_physically=0;
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+
+# Note that we don't remove logs between iterations. Test is
+# cumulative (each new recovery processes more log records than the previous).
+
+while ($crash_loop)
+{
+ if ($crash_flush_whole_log)
+ {
+ let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+ # set up what next iteration should do:
+ let $crash_flush_whole_log=0;
+ let $crash_loop=0;
+ }
+ if ($crash_flush_states)
+ {
+ let $mvr_debug_option="+d,maria_flush_states,maria_flush_whole_log,maria_crash";
+ let $crash_flush_states=0;
+ let $crash_flush_whole_log=1;
+ }
+ if ($crash_flush_whole_page_cache)
+ {
+ let $mvr_debug_option="+d,maria_flush_whole_page_cache,maria_crash";
+ let $crash_flush_whole_page_cache=0;
+ let $crash_flush_states=1;
+ }
+ if ($crash_no_flush)
+ {
+ let $mvr_debug_option="+d,maria_crash";
+ let $crash_no_flush=0;
+ let $crash_flush_whole_page_cache=1;
+ }
+ # Your committed statements here
+ insert into t1 values ("00000000");
+ -- source include/maria_make_snapshot_for_comparison.inc
+ # Your statements which we expect to be rolled back
+ lock tables t1 write;
+ insert into t1 values ("aaaaaaaaa");
+ -- source include/maria_verify_recovery.inc
+ select * from t1;
+}
+
+drop table t1;
+
+# what did we compare above:
+# - checksum: tells that the tables contain the same amount of rows
+# and same data in rows
+# - index: no, neither state nor pages were compared
+# - bitmap pages: the REPAIR QUICK done above very probably checks
+# that bitmap reflects page occupation; do we need to do physical
+# compare?
+# - page LSN: not compared; we should compare that page's LSN in new
+# table is >= page's LSN in old table (it can be >, due to UNDO phase)
+# we had a bug where new page's LSN was 0... todo.
+
+#
+# Test for this bug: an UPDATE purges and rewrites a tail page, and
+# recovery applied the purge, stamped page with UNDO's LSN, thus
+# the rewrite was ignored.
+#
+
+--echo * TEST of two REDOs for same page in one REDO group
+-- source include/maria_empty_logs.inc
+let $mms_tables=1;
+CREATE TABLE t1 (
+ i int,
+ b blob default NULL,
+ c varchar(6000) default NULL
+) ENGINE=MARIA CHECKSUM=1;
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+INSERT INTO t1 VALUES (1, REPEAT('a', 5000), REPEAT('b', 5000));
+UPDATE t1 SET i=3, b=CONCAT(b,'c') WHERE i=1;
+SELECT LENGTH(b) FROM t1 WHERE i=3;
+-- source include/maria_make_snapshot_for_comparison.inc
+# we want recovery to run on the first snapshot made above
+let $mvr_restore_old_snapshot=1;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+-- source include/maria_verify_recovery.inc
+SELECT LENGTH(b) FROM t1 WHERE i=3;
+drop table t1;
+
+# Test that INSERT's effect on auto-increment is recovered
+--echo * TEST of INSERT vs state.auto_increment
+-- source include/maria_empty_logs.inc
+let $mms_tables=1;
+CREATE TABLE t1 (
+ i int auto_increment primary key,
+ c varchar(6),
+ key(c)
+) ENGINE=MARIA;
+insert into t1 values(null,"b");
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+insert into t1 values(null,"a"), (null,"c"), (null,"d");
+# With this DELETE we also verify that Recovery cares only about INSERTs
+delete from t1 where c="d";
+-- source include/maria_make_snapshot_for_comparison.inc
+let $mvr_restore_old_snapshot=1;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+-- source include/maria_verify_recovery.inc
+show create table t1;
+
+# Test that UPDATE's effect on auto-increment is recovered
+--echo * TEST of UPDATE vs state.auto_increment
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+update t1 set i=15 where c="a";
+-- source include/maria_make_snapshot_for_comparison.inc
+let $mvr_restore_old_snapshot=1;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+-- source include/maria_verify_recovery.inc
+show create table t1;
+
+# Test that INSERT's rollback does not set auto-increment counter to 1
+# (BUG#34106)
+--echo * TEST of INSERT's rollback vs state.auto_increment
+-- source include/maria_make_snapshot_for_comparison.inc
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+lock tables t1 write;
+insert into t1 values(null, "e");
+-- source include/maria_verify_recovery.inc
+show create table t1;
+insert into t1 values(null, "f");
+drop table t1;
+
+# clean up everything
+let $mms_purpose=feeding_recovery;
+eval drop database mysqltest_for_$mms_purpose;
+let $mms_purpose=comparison;
+eval drop database mysqltest_for_$mms_purpose;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria-recovery2-master.opt b/mysql-test/suite/maria/t/maria-recovery2-master.opt
new file mode 100644
index 00000000000..9023fb74e8b
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery2-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file --loose-maria-log-dir-path=$MYSQLTEST_VARDIR/tmp
diff --git a/mysql-test/suite/maria/t/maria-recovery2.test b/mysql-test/suite/maria/t/maria-recovery2.test
new file mode 100644
index 00000000000..017256a5ec8
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery2.test
@@ -0,0 +1,162 @@
+--source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur as we crash
+--source include/not_valgrind.inc
+# Binary must be compiled with debug for crash to occur
+--source include/have_debug.inc
+--source include/have_maria.inc
+
+call mtr.add_suppression("File '.*maria_log.000.*' not found \\(Errcode: 2\\)");
+call mtr.add_suppression("Table '.\/mysqltest\/t_corrupted1' is crashed, skipping it. Please repair it with maria_chk -r");
+
+set global maria_log_file_size=4294967295;
+let $MARIA_LOG=../../tmp;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+# Include scripts can perform SQL. For it to not influence the main test
+# they use a separate connection. This way if they use a DDL it would
+# not autocommit in the main test.
+connect (admin, 127.0.0.1, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+let $mms_tables=1;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+
+# Test of removing logs manually
+--echo * TEST of removing logs manually
+let $mel_keep_control_file=1;
+# this will shut mysqld down cleanly (so, take a checkpoint) and
+# remove only logs; at restart Maria will create a new log with a high
+# number
+-- source include/maria_empty_logs.inc
+let $mel_keep_control_file=0;
+# next test will help us verify that a next recovery is ok
+
+--echo * TEST of UNDO_ROW_DELETE preserving rowid
+# we want recovery to use the tables as they were at time of crash
+let $mvr_restore_old_snapshot=0;
+# UNDO phase prevents physical comparison, normally,
+# so we'll only use checksums to compare.
+let $mms_compare_physically=0;
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+create table t1(a int) engine=maria;
+insert into t1 values(1),(2);
+-- source include/maria_make_snapshot_for_comparison.inc
+lock tables t1 write;
+insert into t1 values(3);
+delete from t1 where a in (1,2,3);
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
+# A basic checkpoint test
+--echo * TEST of checkpoint
+# Don't take a full checkpoints, we want to test checkpoint vs dirty pages
+set global debug="+d,info,query,enter,exit,loop,maria_checkpoint_indirect";
+# restart checkpoint thread for it to notice the above
+set global maria_checkpoint_interval=10000;
+create table t1(a int, b varchar(10), index(a,b)) engine=maria;
+insert into t1 values(1,"a"),(2,"b"),(3,"c");
+delete from t1 where b="b";
+update t1 set b="d" where a=1;
+-- source include/maria_make_snapshot_for_comparison.inc
+lock tables t1 write;
+insert into t1 values(4,"e"),(5,"f"),(6,"g");
+update t1 set b="h" where a=5;
+delete from t1 where b="g";
+show status like "Maria_pagecache_blocks_not_flushed";
+# force a checkpoint; there should be dirty pages and an open transaction
+set global maria_checkpoint_interval=10000;
+# do some more work
+update t1 set b="i" where a=5;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+# Now we have a recovery, which should use the checkpoint record
+# and its dirty pages list.
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
+--echo Test of REPAIR's implicit commit
+let $mms_tables=1;
+create table t1 (a varchar(100), key(a)) engine=maria;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash";
+insert into t1 values(3);
+-- source include/maria_make_snapshot_for_comparison.inc
+lock tables t1 write;
+insert into t1 values (1);
+repair table t1;
+insert into t1 values(2);
+select * from t1;
+
+# checksum comparison failure is expected, SELECT output matters
+-- source include/maria_verify_recovery.inc
+# 2 should be missing (rolled back) but 1 should be committed
+select * from t1;
+drop table t1;
+
+--echo * TEST of recovery when crash before bulk-insert-with-repair is committed
+create table t1 (a varchar(100), key(a)) engine=maria;
+create table t2 (a varchar(100)) engine=myisam;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash";
+set rand_seed1=12, rand_seed2=254; # repeatable
+insert into t2 values (rand());
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t2 select (rand()) from t2;
+insert into t1 values(30);
+-- source include/maria_make_snapshot_for_comparison.inc
+lock tables t1 write, t2 read;
+delete from t1 limit 1;
+# 127 rows in t2, >100, so this will use repair-at-end
+insert into t1 select * from t2;
+-- source include/maria_verify_recovery.inc
+show keys from t1; # should be enabled
+drop table t1;
+
+--echo * TEST of recovery when OPTIMIZE has replaced the index file and crash
+create table t_corrupted1 (a varchar(100), key(a)) engine=maria;
+# we use a special name because this test portion will generate
+# corruption warnings, which we tell mtr_report.pl to ignore by
+# putting the message in mtr_report.pl, but we don't want to it ignore
+# corruption messages of other tests, hence the special name
+# 't_corrupted' and not just 't'.
+let $mms_tname=t_corrupted;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_crash_statement= optimize table t_corrupted1;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash_sort_index";
+insert into t_corrupted1 select (rand()) from t2;
+-- source include/maria_make_snapshot_for_comparison.inc
+# Recovery will not fix the table, but we expect to see it marked
+# "crashed on repair".
+# Because crash is mild, the table is actually not corrupted, so the
+# "check table extended" done below fixes the table.
+-- source include/maria_verify_recovery.inc
+drop table t_corrupted1, t2;
+
+# clean up everything
+let $mms_purpose=comparison;
+eval drop database mysqltest_for_$mms_purpose;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria-recovery3-master.opt b/mysql-test/suite/maria/t/maria-recovery3-master.opt
new file mode 100644
index 00000000000..9023fb74e8b
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery3-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file --loose-maria-log-dir-path=$MYSQLTEST_VARDIR/tmp
diff --git a/mysql-test/suite/maria/t/maria-recovery3.test b/mysql-test/suite/maria/t/maria-recovery3.test
new file mode 100644
index 00000000000..a5515839991
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery3.test
@@ -0,0 +1,118 @@
+--source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur as we crash
+--source include/not_valgrind.inc
+# Binary must be compiled with debug for crash to occur
+--source include/have_debug.inc
+--source include/have_maria.inc
+
+set global maria_log_file_size=4294967295;
+let $MARIA_LOG=../../tmp;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+# Include scripts can perform SQL. For it to not influence the main test
+# they use a separate connection. This way if they use a DDL it would
+# not autocommit in the main test.
+connect (admin, 127.0.0.1, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+let $mms_tables=1;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+
+-- source include/maria_empty_logs.inc
+
+# Test for BUG#41037 (recovery failure)
+--echo * TEST of Checkpoint between writing the commit log record and committing in trnman
+# we want recovery to use the tables as they were at time of crash
+let $mvr_restore_old_snapshot=0;
+# UNDO phase prevents physical comparison, normally,
+# so we'll only use checksums to compare.
+let $mms_compare_physically=0;
+create table t1(a int primary key) engine=maria;
+insert into t1 values(1);
+-- source include/maria_make_snapshot_for_comparison.inc
+set session debug="+d,maria_sleep_in_commit";
+send insert into t1 values(2);
+sleep 1;
+# Now the INSERT of 2 has written a commit record
+# but not yet called trnman_commit(), so for checkpoint it's not
+# committed.
+connection admin;
+set global maria_checkpoint_interval=1000; # force a checkpoint
+connection default;
+reap; # end of INSERT
+delete from t1 where a=2;
+# Bug was that: Recovery starts REDO scanning from too far: from
+# Checkpoint record which says INSERT is not committed, so
+# Recovery executes the INSERT's UNDO and finds no key to delete
+# (as DELETE already deleted it), fails.
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
+# Note that even if machine is loaded and thus INSERT is committed
+# before checkpoint happens, test should still pass (though it won't
+# reproduce the conditions of the bug).
+
+# Test for BUG#41493 Maria: two recovery failures (wrong logging of BLOB pages)
+--echo * TEST of logging of BLOBs
+let $mvr_restore_old_snapshot=1;
+let $mms_compare_physically=1;
+CREATE TABLE `t1` (
+`blob` blob,
+`blob_key` blob
+) ENGINE=maria ROW_FORMAT=page
+;
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+set global maria_checkpoint_interval=0; # no checkpoints
+INSERT INTO `t1` VALUES (NULL,repeat('A',5198));
+INSERT INTO `t1` VALUES (NULL,repeat('B',65535));
+INSERT INTO `t1` VALUES (repeat('K',5198),repeat('L',2325));
+INSERT INTO `t1` VALUES (repeat('C',65535),NULL);
+INSERT INTO `t1` VALUES (NULL,repeat('D',65535));
+INSERT INTO `t1` VALUES (repeat('E',65535),repeat('F',16111));
+INSERT INTO `t1` VALUES (repeat('G',65535),repeat('H',65535));
+INSERT INTO `t1` VALUES (repeat('I',5198),repeat('J',65535));
+check table t1 extended;
+-- source include/maria_make_snapshot_for_comparison.inc
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
+# Test for BUG#42112 "Maria: recovery failure (pushbuild2) Assertion
+# `rownr == 0 && new_page' failed"
+
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+create table t1 engine=maria select 1;
+-- source include/maria_make_snapshot_for_feeding_recovery.inc
+set global maria_checkpoint_interval=0; # no checkpoints
+insert into t1 values(2);
+truncate table t1;
+-- source include/maria_make_snapshot_for_comparison.inc
+let $mvr_crash_statement= truncate table t1;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash_create_table";
+truncate table t1;
+-- source include/maria_verify_recovery.inc
+# Table is bad but at least Recovery didn't crash and a new truncate
+# can succeed:
+truncate table t1;
+check table t1 extended;
+drop table t1;
+
+
+# clean up everything
+let $mms_purpose=feeding_recovery;
+eval drop database mysqltest_for_$mms_purpose;
+let $mms_purpose=comparison;
+eval drop database mysqltest_for_$mms_purpose;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria.test b/mysql-test/suite/maria/t/maria.test
new file mode 100644
index 00000000000..f57b5946401
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria.test
@@ -0,0 +1,1872 @@
+#
+# Testing of potential problems in Maria
+# This code was initially taken from myisam.test
+#
+
+-- source include/have_maria.inc
+
+select * from INFORMATION_SCHEMA.ENGINES where ENGINE="MARIA";
+
+let $default_engine=`select @@global.storage_engine`;
+let $default_checksum=`select @@global.maria_page_checksum`;
+set global storage_engine=maria;
+set session storage_engine=maria;
+set global maria_page_checksum=0;
+let $default_log_file_size=`select @@global.maria_log_file_size`;
+set global maria_log_file_size=4294967295;
+
+# Initialise
+--disable_warnings
+drop table if exists t1,t2;
+drop view if exists v1;
+--enable_warnings
+SET SQL_WARNINGS=1;
+
+#
+# Test problem with CHECK TABLE;
+#
+
+CREATE TABLE t1 (
+ STRING_DATA char(255) default NULL,
+ KEY string_data (STRING_DATA)
+);
+
+INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
+INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD');
+INSERT INTO t1 VALUES ('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF');
+INSERT INTO t1 VALUES ('FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG');
+INSERT INTO t1 VALUES ('HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH');
+INSERT INTO t1 VALUES ('WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW');
+CHECK TABLE t1;
+drop table t1;
+
+#
+# Test problem with rows that are 65517-65520 bytes long
+#
+
+create table t1 (a tinyint not null auto_increment, b blob not null, primary key (a));
+
+let $1=100;
+disable_query_log;
+--disable_warnings
+SET SQL_WARNINGS=0;
+while ($1)
+{
+ eval insert into t1 (b) values(repeat(char(65+$1),65550-$1));
+ dec $1;
+}
+SET SQL_WARNINGS=1;
+--enable_warnings
+--enable_query_log
+check table t1;
+repair table t1;
+delete from t1 where (a & 1);
+check table t1;
+repair table t1;
+check table t1;
+
+# FLUSH + REPAIR used to cause assertion failure in page cache
+flush table t1;
+repair table t1;
+drop table t1;
+
+#
+# Test bug: Two optimize in a row reset index cardinality
+#
+
+create table t1 (a int not null auto_increment, b int not null, primary key (a), index(b));
+insert into t1 (b) values (1),(2),(2),(2),(2);
+optimize table t1;
+show index from t1;
+optimize table t1;
+show index from t1;
+drop table t1;
+
+#
+# Test of how ORDER BY works when doing it on the whole table
+#
+
+create table t1 (a int not null, b int not null, c int not null, primary key (a),key(b));
+insert into t1 values (3,3,3),(1,1,1),(2,2,2),(4,4,4);
+explain select * from t1 order by a;
+explain select * from t1 order by b;
+explain select * from t1 order by c;
+explain select a from t1 order by a;
+explain select b from t1 order by b;
+explain select a,b from t1 order by b;
+explain select a,b from t1;
+explain select a,b,c from t1;
+drop table t1;
+
+#
+# Test of OPTIMIZE of locked and modified tables
+#
+set autocommit=0;
+begin;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2), (3);
+LOCK TABLES t1 WRITE;
+INSERT INTO t1 VALUES (1), (2), (3);
+commit;
+set autocommit=1;
+UNLOCK TABLES;
+OPTIMIZE TABLE t1;
+DROP TABLE t1;
+
+#
+# Test of optimize, when only mi_sort_index (but not mi_repair*) is done
+# in ha_maria::repair, and index size is changed (decreased).
+#
+
+create table t1 ( t1 char(255), key(t1(250)));
+insert t1 values ('137513751375137513751375137513751375137569516951695169516951695169516951695169');
+insert t1 values ('178417841784178417841784178417841784178403420342034203420342034203420342034203');
+insert t1 values ('213872387238723872387238723872387238723867376737673767376737673767376737673767');
+insert t1 values ('242624262426242624262426242624262426242607890789078907890789078907890789078907');
+insert t1 values ('256025602560256025602560256025602560256011701170117011701170117011701170117011');
+insert t1 values ('276027602760276027602760276027602760276001610161016101610161016101610161016101');
+insert t1 values ('281528152815281528152815281528152815281564956495649564956495649564956495649564');
+insert t1 values ('292129212921292129212921292129212921292102100210021002100210021002100210021002');
+insert t1 values ('380638063806380638063806380638063806380634483448344834483448344834483448344834');
+insert t1 values ('411641164116411641164116411641164116411616301630163016301630163016301630163016');
+insert t1 values ('420842084208420842084208420842084208420899889988998899889988998899889988998899');
+insert t1 values ('438443844384438443844384438443844384438482448244824482448244824482448244824482');
+insert t1 values ('443244324432443244324432443244324432443239613961396139613961396139613961396139');
+insert t1 values ('485448544854485448544854485448544854485477847784778477847784778477847784778477');
+insert t1 values ('494549454945494549454945494549454945494555275527552755275527552755275527552755');
+insert t1 values ('538647864786478647864786478647864786478688918891889188918891889188918891889188');
+insert t1 values ('565556555655565556555655565556555655565554845484548454845484548454845484548454');
+insert t1 values ('607860786078607860786078607860786078607856665666566656665666566656665666566656');
+insert t1 values ('640164016401640164016401640164016401640141274127412741274127412741274127412741');
+insert t1 values ('719471947194719471947194719471947194719478717871787178717871787178717871787178');
+insert t1 values ('742574257425742574257425742574257425742549604960496049604960496049604960496049');
+insert t1 values ('887088708870887088708870887088708870887035963596359635963596359635963596359635');
+insert t1 values ('917791779177917791779177917791779177917773857385738573857385738573857385738573');
+insert t1 values ('933293329332933293329332933293329332933278987898789878987898789878987898789878');
+insert t1 values ('963896389638963896389638963896389638963877807780778077807780778077807780778077');
+delete from t1 where t1>'2';
+insert t1 values ('70'), ('84'), ('60'), ('20'), ('76'), ('89'), ('49'), ('50'),
+('88'), ('61'), ('42'), ('98'), ('39'), ('30'), ('25'), ('66'), ('61'), ('48'),
+('80'), ('84'), ('98'), ('19'), ('91'), ('42'), ('47');
+optimize table t1;
+check table t1;
+drop table t1;
+
+#
+# test of maria with huge number of packed fields
+#
+
+create table t1 (i1 int, i2 int, i3 int, i4 int, i5 int, i6 int, i7 int, i8
+int, i9 int, i10 int, i11 int, i12 int, i13 int, i14 int, i15 int, i16 int, i17
+int, i18 int, i19 int, i20 int, i21 int, i22 int, i23 int, i24 int, i25 int,
+i26 int, i27 int, i28 int, i29 int, i30 int, i31 int, i32 int, i33 int, i34
+int, i35 int, i36 int, i37 int, i38 int, i39 int, i40 int, i41 int, i42 int,
+i43 int, i44 int, i45 int, i46 int, i47 int, i48 int, i49 int, i50 int, i51
+int, i52 int, i53 int, i54 int, i55 int, i56 int, i57 int, i58 int, i59 int,
+i60 int, i61 int, i62 int, i63 int, i64 int, i65 int, i66 int, i67 int, i68
+int, i69 int, i70 int, i71 int, i72 int, i73 int, i74 int, i75 int, i76 int,
+i77 int, i78 int, i79 int, i80 int, i81 int, i82 int, i83 int, i84 int, i85
+int, i86 int, i87 int, i88 int, i89 int, i90 int, i91 int, i92 int, i93 int,
+i94 int, i95 int, i96 int, i97 int, i98 int, i99 int, i100 int, i101 int, i102
+int, i103 int, i104 int, i105 int, i106 int, i107 int, i108 int, i109 int, i110
+int, i111 int, i112 int, i113 int, i114 int, i115 int, i116 int, i117 int, i118
+int, i119 int, i120 int, i121 int, i122 int, i123 int, i124 int, i125 int, i126
+int, i127 int, i128 int, i129 int, i130 int, i131 int, i132 int, i133 int, i134
+int, i135 int, i136 int, i137 int, i138 int, i139 int, i140 int, i141 int, i142
+int, i143 int, i144 int, i145 int, i146 int, i147 int, i148 int, i149 int, i150
+int, i151 int, i152 int, i153 int, i154 int, i155 int, i156 int, i157 int, i158
+int, i159 int, i160 int, i161 int, i162 int, i163 int, i164 int, i165 int, i166
+int, i167 int, i168 int, i169 int, i170 int, i171 int, i172 int, i173 int, i174
+int, i175 int, i176 int, i177 int, i178 int, i179 int, i180 int, i181 int, i182
+int, i183 int, i184 int, i185 int, i186 int, i187 int, i188 int, i189 int, i190
+int, i191 int, i192 int, i193 int, i194 int, i195 int, i196 int, i197 int, i198
+int, i199 int, i200 int, i201 int, i202 int, i203 int, i204 int, i205 int, i206
+int, i207 int, i208 int, i209 int, i210 int, i211 int, i212 int, i213 int, i214
+int, i215 int, i216 int, i217 int, i218 int, i219 int, i220 int, i221 int, i222
+int, i223 int, i224 int, i225 int, i226 int, i227 int, i228 int, i229 int, i230
+int, i231 int, i232 int, i233 int, i234 int, i235 int, i236 int, i237 int, i238
+int, i239 int, i240 int, i241 int, i242 int, i243 int, i244 int, i245 int, i246
+int, i247 int, i248 int, i249 int, i250 int, i251 int, i252 int, i253 int, i254
+int, i255 int, i256 int, i257 int, i258 int, i259 int, i260 int, i261 int, i262
+int, i263 int, i264 int, i265 int, i266 int, i267 int, i268 int, i269 int, i270
+int, i271 int, i272 int, i273 int, i274 int, i275 int, i276 int, i277 int, i278
+int, i279 int, i280 int, i281 int, i282 int, i283 int, i284 int, i285 int, i286
+int, i287 int, i288 int, i289 int, i290 int, i291 int, i292 int, i293 int, i294
+int, i295 int, i296 int, i297 int, i298 int, i299 int, i300 int, i301 int, i302
+int, i303 int, i304 int, i305 int, i306 int, i307 int, i308 int, i309 int, i310
+int, i311 int, i312 int, i313 int, i314 int, i315 int, i316 int, i317 int, i318
+int, i319 int, i320 int, i321 int, i322 int, i323 int, i324 int, i325 int, i326
+int, i327 int, i328 int, i329 int, i330 int, i331 int, i332 int, i333 int, i334
+int, i335 int, i336 int, i337 int, i338 int, i339 int, i340 int, i341 int, i342
+int, i343 int, i344 int, i345 int, i346 int, i347 int, i348 int, i349 int, i350
+int, i351 int, i352 int, i353 int, i354 int, i355 int, i356 int, i357 int, i358
+int, i359 int, i360 int, i361 int, i362 int, i363 int, i364 int, i365 int, i366
+int, i367 int, i368 int, i369 int, i370 int, i371 int, i372 int, i373 int, i374
+int, i375 int, i376 int, i377 int, i378 int, i379 int, i380 int, i381 int, i382
+int, i383 int, i384 int, i385 int, i386 int, i387 int, i388 int, i389 int, i390
+int, i391 int, i392 int, i393 int, i394 int, i395 int, i396 int, i397 int, i398
+int, i399 int, i400 int, i401 int, i402 int, i403 int, i404 int, i405 int, i406
+int, i407 int, i408 int, i409 int, i410 int, i411 int, i412 int, i413 int, i414
+int, i415 int, i416 int, i417 int, i418 int, i419 int, i420 int, i421 int, i422
+int, i423 int, i424 int, i425 int, i426 int, i427 int, i428 int, i429 int, i430
+int, i431 int, i432 int, i433 int, i434 int, i435 int, i436 int, i437 int, i438
+int, i439 int, i440 int, i441 int, i442 int, i443 int, i444 int, i445 int, i446
+int, i447 int, i448 int, i449 int, i450 int, i451 int, i452 int, i453 int, i454
+int, i455 int, i456 int, i457 int, i458 int, i459 int, i460 int, i461 int, i462
+int, i463 int, i464 int, i465 int, i466 int, i467 int, i468 int, i469 int, i470
+int, i471 int, i472 int, i473 int, i474 int, i475 int, i476 int, i477 int, i478
+int, i479 int, i480 int, i481 int, i482 int, i483 int, i484 int, i485 int, i486
+int, i487 int, i488 int, i489 int, i490 int, i491 int, i492 int, i493 int, i494
+int, i495 int, i496 int, i497 int, i498 int, i499 int, i500 int, i501 int, i502
+int, i503 int, i504 int, i505 int, i506 int, i507 int, i508 int, i509 int, i510
+int, i511 int, i512 int, i513 int, i514 int, i515 int, i516 int, i517 int, i518
+int, i519 int, i520 int, i521 int, i522 int, i523 int, i524 int, i525 int, i526
+int, i527 int, i528 int, i529 int, i530 int, i531 int, i532 int, i533 int, i534
+int, i535 int, i536 int, i537 int, i538 int, i539 int, i540 int, i541 int, i542
+int, i543 int, i544 int, i545 int, i546 int, i547 int, i548 int, i549 int, i550
+int, i551 int, i552 int, i553 int, i554 int, i555 int, i556 int, i557 int, i558
+int, i559 int, i560 int, i561 int, i562 int, i563 int, i564 int, i565 int, i566
+int, i567 int, i568 int, i569 int, i570 int, i571 int, i572 int, i573 int, i574
+int, i575 int, i576 int, i577 int, i578 int, i579 int, i580 int, i581 int, i582
+int, i583 int, i584 int, i585 int, i586 int, i587 int, i588 int, i589 int, i590
+int, i591 int, i592 int, i593 int, i594 int, i595 int, i596 int, i597 int, i598
+int, i599 int, i600 int, i601 int, i602 int, i603 int, i604 int, i605 int, i606
+int, i607 int, i608 int, i609 int, i610 int, i611 int, i612 int, i613 int, i614
+int, i615 int, i616 int, i617 int, i618 int, i619 int, i620 int, i621 int, i622
+int, i623 int, i624 int, i625 int, i626 int, i627 int, i628 int, i629 int, i630
+int, i631 int, i632 int, i633 int, i634 int, i635 int, i636 int, i637 int, i638
+int, i639 int, i640 int, i641 int, i642 int, i643 int, i644 int, i645 int, i646
+int, i647 int, i648 int, i649 int, i650 int, i651 int, i652 int, i653 int, i654
+int, i655 int, i656 int, i657 int, i658 int, i659 int, i660 int, i661 int, i662
+int, i663 int, i664 int, i665 int, i666 int, i667 int, i668 int, i669 int, i670
+int, i671 int, i672 int, i673 int, i674 int, i675 int, i676 int, i677 int, i678
+int, i679 int, i680 int, i681 int, i682 int, i683 int, i684 int, i685 int, i686
+int, i687 int, i688 int, i689 int, i690 int, i691 int, i692 int, i693 int, i694
+int, i695 int, i696 int, i697 int, i698 int, i699 int, i700 int, i701 int, i702
+int, i703 int, i704 int, i705 int, i706 int, i707 int, i708 int, i709 int, i710
+int, i711 int, i712 int, i713 int, i714 int, i715 int, i716 int, i717 int, i718
+int, i719 int, i720 int, i721 int, i722 int, i723 int, i724 int, i725 int, i726
+int, i727 int, i728 int, i729 int, i730 int, i731 int, i732 int, i733 int, i734
+int, i735 int, i736 int, i737 int, i738 int, i739 int, i740 int, i741 int, i742
+int, i743 int, i744 int, i745 int, i746 int, i747 int, i748 int, i749 int, i750
+int, i751 int, i752 int, i753 int, i754 int, i755 int, i756 int, i757 int, i758
+int, i759 int, i760 int, i761 int, i762 int, i763 int, i764 int, i765 int, i766
+int, i767 int, i768 int, i769 int, i770 int, i771 int, i772 int, i773 int, i774
+int, i775 int, i776 int, i777 int, i778 int, i779 int, i780 int, i781 int, i782
+int, i783 int, i784 int, i785 int, i786 int, i787 int, i788 int, i789 int, i790
+int, i791 int, i792 int, i793 int, i794 int, i795 int, i796 int, i797 int, i798
+int, i799 int, i800 int, i801 int, i802 int, i803 int, i804 int, i805 int, i806
+int, i807 int, i808 int, i809 int, i810 int, i811 int, i812 int, i813 int, i814
+int, i815 int, i816 int, i817 int, i818 int, i819 int, i820 int, i821 int, i822
+int, i823 int, i824 int, i825 int, i826 int, i827 int, i828 int, i829 int, i830
+int, i831 int, i832 int, i833 int, i834 int, i835 int, i836 int, i837 int, i838
+int, i839 int, i840 int, i841 int, i842 int, i843 int, i844 int, i845 int, i846
+int, i847 int, i848 int, i849 int, i850 int, i851 int, i852 int, i853 int, i854
+int, i855 int, i856 int, i857 int, i858 int, i859 int, i860 int, i861 int, i862
+int, i863 int, i864 int, i865 int, i866 int, i867 int, i868 int, i869 int, i870
+int, i871 int, i872 int, i873 int, i874 int, i875 int, i876 int, i877 int, i878
+int, i879 int, i880 int, i881 int, i882 int, i883 int, i884 int, i885 int, i886
+int, i887 int, i888 int, i889 int, i890 int, i891 int, i892 int, i893 int, i894
+int, i895 int, i896 int, i897 int, i898 int, i899 int, i900 int, i901 int, i902
+int, i903 int, i904 int, i905 int, i906 int, i907 int, i908 int, i909 int, i910
+int, i911 int, i912 int, i913 int, i914 int, i915 int, i916 int, i917 int, i918
+int, i919 int, i920 int, i921 int, i922 int, i923 int, i924 int, i925 int, i926
+int, i927 int, i928 int, i929 int, i930 int, i931 int, i932 int, i933 int, i934
+int, i935 int, i936 int, i937 int, i938 int, i939 int, i940 int, i941 int, i942
+int, i943 int, i944 int, i945 int, i946 int, i947 int, i948 int, i949 int, i950
+int, i951 int, i952 int, i953 int, i954 int, i955 int, i956 int, i957 int, i958
+int, i959 int, i960 int, i961 int, i962 int, i963 int, i964 int, i965 int, i966
+int, i967 int, i968 int, i969 int, i970 int, i971 int, i972 int, i973 int, i974
+int, i975 int, i976 int, i977 int, i978 int, i979 int, i980 int, i981 int, i982
+int, i983 int, i984 int, i985 int, i986 int, i987 int, i988 int, i989 int, i990
+int, i991 int, i992 int, i993 int, i994 int, i995 int, i996 int, i997 int, i998
+int, i999 int, i1000 int, b blob) row_format=dynamic;
+insert into t1 values (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, "Sergei");
+update t1 set b=repeat('a',256);
+update t1 set i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0;
+check table t1;
+delete from t1 where i8=1;
+select i1,i2 from t1;
+check table t1;
+drop table t1;
+
+#
+# Test of REPAIR that once failed
+#
+CREATE TABLE `t1` (
+ `post_id` mediumint(8) unsigned NOT NULL auto_increment,
+ `topic_id` mediumint(8) unsigned NOT NULL default '0',
+ `post_time` datetime NOT NULL default '0000-00-00 00:00:00',
+ `post_text` text NOT NULL,
+ `icon_url` varchar(10) NOT NULL default '',
+ `sign` tinyint(1) unsigned NOT NULL default '0',
+ `post_edit` varchar(150) NOT NULL default '',
+ `poster_login` varchar(35) NOT NULL default '',
+ `ip` varchar(15) NOT NULL default '',
+ PRIMARY KEY (`post_id`),
+ KEY `post_time` (`post_time`),
+ KEY `ip` (`ip`),
+ KEY `poster_login` (`poster_login`),
+ KEY `topic_id` (`topic_id`),
+ FULLTEXT KEY `post_text` (`post_text`)
+) TRANSACTIONAL=0;
+
+INSERT INTO t1 (post_text) VALUES ('ceci est un test'),('ceci est un test'),('ceci est un test'),('ceci est un test'),('ceci est un test');
+
+REPAIR TABLE t1;
+CHECK TABLE t1;
+drop table t1;
+
+#
+# Test of creating table with too long key
+#
+
+--error 1071
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255), KEY t1 (a, b, c, d, e));
+--error 1071
+CREATE TABLE t1 (a varchar(32000), unique key(a));
+--error 1070
+CREATE TABLE t1 (a varchar(1), b varchar(1), key (a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b));
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255));
+--error 1071
+ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e);
+DROP TABLE t1;
+
+#
+# Test of cardinality of keys with NULL
+#
+
+CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a));
+INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4);
+create table t2 (a int not null, b int, c int, key(b), key(c), key(a));
+INSERT into t2 values (1,1,1), (2,2,2);
+optimize table t1;
+check table t1;
+show index from t1;
+explain select * from t1,t2 where t1.a=t2.a;
+explain select * from t1,t2 force index(a) where t1.a=t2.a;
+explain select * from t1 force index(a),t2 force index(a) where t1.a=t2.a;
+explain select * from t1,t2 where t1.b=t2.b;
+explain select * from t1,t2 force index(c) where t1.a=t2.a;
+explain select * from t1 where a=0 or a=2;
+explain select * from t1 force index (a) where a=0 or a=2;
+explain select * from t1 where c=1;
+explain select * from t1 use index() where c=1;
+drop table t1,t2;
+
+#
+# Test bug when updating a split dynamic row where keys are not changed
+#
+
+create table t1 (a int not null auto_increment primary key, b varchar(255));
+insert into t1 (b) values (repeat('a',100)),(repeat('b',100)),(repeat('c',100));
+update t1 set b=repeat(left(b,1),200) where a=1;
+delete from t1 where (a & 1)= 0;
+update t1 set b=repeat('e',200) where a=1;
+flush tables;
+check table t1;
+
+#
+# check updating with keys
+#
+
+disable_query_log;
+let $1 = 100;
+while ($1)
+{
+ eval insert into t1 (b) values (repeat(char(($1 & 32)+65), $1));
+ dec $1;
+}
+enable_query_log;
+update t1 set b=repeat(left(b,1),255) where a between 1 and 5;
+update t1 set b=repeat(left(b,1),10) where a between 32 and 43;
+update t1 set b=repeat(left(b,1),2) where a between 64 and 66;
+update t1 set b=repeat(left(b,1),65) where a between 67 and 70;
+check table t1;
+insert into t1 (b) values (repeat('z',100));
+update t1 set b="test" where left(b,1) > 'n';
+check table t1;
+drop table t1;
+
+#
+# Test space-stripping features
+#
+create table t1 ( a text not null, key a (a(20)));
+insert into t1 values ('aaa '),('aaa'),('aa');
+check table t1;
+repair table t1;
+select concat(a,'.') from t1 where a='aaa';
+select concat(a,'.') from t1 where binary a='aaa';
+update t1 set a='bbb' where a='aaa';
+select concat(a,'.') from t1;
+drop table t1;
+
+#
+# Test again but with dynamic format
+#
+create table t1 ( a text not null, key a (a(20))) row_format=dynamic;
+insert into t1 values ('aaa '),('aaa'),('aa');
+check table t1;
+repair table t1;
+select concat(a,'.') from t1 where a='aaa';
+select concat(a,'.') from t1 where binary a='aaa';
+update t1 set a='bbb' where a='aaa';
+select concat(a,'.') from t1;
+drop table t1;
+
+#
+# More space testing
+#
+
+create table t1(a text not null, b text not null, c text not null, index (a(10),b(10),c(10)));
+insert into t1 values('807780', '477', '165');
+insert into t1 values('807780', '477', '162');
+insert into t1 values('807780', '472', '162');
+select * from t1 where a='807780' and b='477' and c='165';
+drop table t1;
+
+#
+# Space-stripping in prefix_search
+#
+
+CREATE TABLE t1 (a varchar(150) NOT NULL, KEY (a));
+INSERT t1 VALUES ("can \tcan");
+INSERT t1 VALUES ("can can");
+INSERT t1 VALUES ("can");
+SELECT * FROM t1;
+CHECK TABLE t1;
+DROP TABLE t1;
+
+#
+# Verify blob handling
+#
+
+create table t1 (a blob);
+insert into t1 values('a '),('a');
+select concat(a,'.') from t1 where a='a';
+select concat(a,'.') from t1 where a='a ';
+alter table t1 add key(a(2));
+select concat(a,'.') from t1 where a='a';
+select concat(a,'.') from t1 where a='a ';
+drop table t1;
+
+#
+# Test text and unique
+#
+create table t1 (a int not null auto_increment primary key, b text not null, unique b (b(20)));
+insert into t1 (b) values ('a'),('b'),('c');
+select concat(b,'.') from t1;
+update t1 set b='b ' where a=2;
+--error ER_DUP_ENTRY
+update t1 set b='b ' where a > 1;
+--error ER_DUP_ENTRY
+insert into t1 (b) values ('b');
+select * from t1;
+delete from t1 where b='b';
+select a,concat(b,'.') from t1;
+drop table t1;
+
+#
+# Test keys with 0 segments
+#
+create table t1 (a int not null);
+create table t2 (a int not null, primary key (a));
+insert into t1 values (1);
+insert into t2 values (1),(2);
+select sql_big_result distinct t1.a from t1,t2 order by t2.a;
+select distinct t1.a from t1,t2 order by t2.a;
+select sql_big_result distinct t1.a from t1,t2;
+explain select sql_big_result distinct t1.a from t1,t2 order by t2.a;
+explain select distinct t1.a from t1,t2 order by t2.a;
+drop table t1,t2;
+
+#
+# Test freshly imported table and LIMIT
+#
+create table t1 (
+ c1 varchar(32),
+ key (c1)
+);
+alter table t1 disable keys;
+insert into t1 values ('a'), ('b');
+select c1 from t1 order by c1 limit 1;
+drop table t1;
+
+#
+# Test join that could miss concurrently inserted row
+# Note that for the moment Maria only supports multiple writers if we have
+# static or dynamic row format
+#
+# Partial key.
+create table t1 (a int not null, primary key(a)) ROW_FORMAT=FIXED;
+create table t2 (a int not null, b int not null, primary key(a,b)) ROW_FORMAT=FIXED;
+insert into t1 values (1),(2),(3),(4),(5),(6);
+insert into t2 values (1,1),(2,1);
+set autocommit=0;
+begin;
+lock tables t1 read local, t2 read local;
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
+insert into t2 values(2,0);
+commit;
+disconnect root;
+connection default;
+select straight_join * from t1,t2 force index (primary) where t1.a=t2.a;
+drop table t1,t2;
+set autocommit=1;
+#
+# Full key.
+CREATE TABLE t1 (c1 varchar(250) NOT NULL) ROW_FORMAT=DYNAMIC;
+CREATE TABLE t2 (c1 varchar(250) NOT NULL, PRIMARY KEY (c1)) ROW_FORMAT=DYNAMIC;
+INSERT INTO t1 VALUES ('test000001'), ('test000002'), ('test000003');
+INSERT INTO t2 VALUES ('test000002'), ('test000003'), ('test000004');
+LOCK TABLES t1 READ LOCAL, t2 READ LOCAL;
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+ WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+connect (con1,localhost,root,,);
+connection con1;
+INSERT INTO t2 VALUES ('test000001'), ('test000005');
+disconnect con1;
+connection default;
+SELECT t1.c1 AS t1c1, t2.c1 AS t2c1 FROM t1, t2
+ WHERE t1.c1 = t2.c1 HAVING t1c1 != t2c1;
+DROP TABLE t1,t2;
+
+#
+# Test RTREE index
+#
+--error 1235, 1289
+CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`));
+# INSERT INTO t1 VALUES (1,1),(1,1);
+# DELETE FROM rt WHERE a<1;
+# DROP TABLE IF EXISTS t1;
+
+create table t1 (a int, b varchar(200), c text not null) checksum=1;
+create table t2 (a int, b varchar(200), c text not null) checksum=0;
+insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
+insert t2 select * from t1;
+checksum table t1, t2, t3 quick;
+checksum table t1, t2, t3;
+checksum table t1, t2, t3 extended;
+#show table status;
+drop table t1,t2;
+
+create table t1 (a int, key (a));
+show keys from t1;
+alter table t1 disable keys;
+show keys from t1;
+create table t2 (a int);
+let $i=1000;
+set @@rand_seed1=31415926,@@rand_seed2=2718281828;
+--disable_query_log
+while ($i)
+{
+ dec $i;
+ insert t2 values (rand()*100000);
+}
+--enable_query_log
+insert t1 select * from t2;
+show keys from t1;
+alter table t1 enable keys;
+show keys from t1;
+alter table t1 engine=heap;
+alter table t1 disable keys;
+show keys from t1;
+drop table t1,t2;
+
+#
+# Index search for NULL in blob
+#
+create table t1 ( a tinytext, b char(1), index idx (a(1),b) );
+insert into t1 values (null,''), (null,'');
+explain select count(*) from t1 where a is null;
+select count(*) from t1 where a is null;
+drop table t1;
+
+#
+# Test corruption Can't open file: 'table.MYI' (errno: 145)
+#
+create table t1 (c1 int, c2 varchar(4) not null default '',
+ key(c2(3))) default charset=utf8;
+insert into t1 values (1,'A'), (2, 'B'), (3, 'A');
+update t1 set c2='A B' where c1=2;
+check table t1;
+drop table t1;
+
+#
+# Test CHECKSUM TABLE
+#
+
+create table t1 (c1 int);
+insert into t1 values (1),(2),(3),(4);
+checksum table t1;
+delete from t1 where c1 = 1;
+create table t2 as select * from t1;
+# The following returns 0 with the bug in place.
+checksum table t1;
+# The above should give the same number as the following.
+checksum table t2;
+drop table t1, t2;
+
+CREATE TABLE t1 (
+ twenty int(4),
+ hundred int(4) NOT NULL
+) CHECKSUM=1;
+INSERT INTO t1 VALUES (11,91);
+check table t1 extended;
+checksum table t1;
+checksum table t1 extended;
+alter table t1 row_format=fixed;
+checksum table t1;
+alter table t1 row_format=dynamic;
+checksum table t1;
+alter table t1 engine=myisam;
+checksum table t1;
+drop table t1;
+
+#
+# maria_stats_method variable.
+#
+
+show variables like 'maria_stats_method';
+
+create table t1 (a int, key(a));
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t1 select NULL from t1;
+
+# default: NULLs considered inequal
+analyze table t1;
+show index from t1;
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+show index from t1;
+
+# Set nulls to be equal:
+set maria_stats_method=nulls_equal;
+show variables like 'maria_stats_method';
+insert into t1 values (11);
+delete from t1 where a=11;
+
+analyze table t1;
+show index from t1;
+
+insert into t1 values (11);
+delete from t1 where a=11;
+
+check table t1;
+show index from t1;
+
+# Set nulls back to be equal
+set maria_stats_method=DEFAULT;
+show variables like 'maria_stats_method';
+insert into t1 values (11);
+delete from t1 where a=11;
+
+analyze table t1;
+show index from t1;
+
+insert into t1 values (11);
+delete from t1 where a=11;
+
+check table t1;
+show index from t1;
+
+drop table t1;
+
+# WL#2609, CSC#XXXX: MARIA
+set maria_stats_method=nulls_ignored;
+show variables like 'maria_stats_method';
+
+create table t1 (
+ a char(3), b char(4), c char(5), d char(6),
+ key(a,b,c,d)
+);
+insert into t1 values ('bcd','def1', NULL, 'zz');
+insert into t1 values ('bcd','def2', NULL, 'zz');
+insert into t1 values ('bce','def1', 'yuu', NULL);
+insert into t1 values ('bce','def2', NULL, 'quux');
+analyze table t1;
+show index from t1;
+delete from t1;
+# This will give you different messages depending on if we are using
+# row base or stmt based replication as stmt base replication will use
+# truncate and row based will delete things row by row.
+--replace_result "Table is already up to date" "OK"
+analyze table t1;
+show index from t1;
+
+set maria_stats_method=DEFAULT;
+
+drop table t1;
+
+#
+# Test key value packing for TINYBLOBs
+#
+
+create table t1(
+ cip INT NOT NULL,
+ time TIME NOT NULL,
+ score INT NOT NULL DEFAULT 0,
+ bob TINYBLOB
+);
+
+insert into t1 (cip, time) VALUES (1, '00:01'), (2, '00:02'), (3,'00:03');
+insert into t1 (cip, bob, time) VALUES (4, 'a', '00:04'), (5, 'b', '00:05'),
+ (6, 'c', '00:06');
+select * from t1 where bob is null and cip=1;
+create index bug on t1 (bob(22), cip, time);
+select * from t1 where bob is null and cip=1;
+drop table t1;
+
+#
+# Test COUNT(*) table with different INDEX
+#
+
+create table t1 (
+ id1 int not null auto_increment,
+ id2 int not null default '0',
+ t text not null,
+ primary key (id1),
+ key x (id2, t(32))
+) engine=maria; # engine clause is redundant but it's to test its parsing
+insert into t1 (id2, t) values
+(10, 'abc'), (10, 'abc'), (10, 'abc'),
+(20, 'abc'), (20, 'abc'), (20, 'def'),
+(10, 'abc'), (10, 'abc');
+select count(*) from t1 where id2 = 10;
+select count(id1) from t1 where id2 = 10;
+drop table t1;
+
+#
+# Test MIN and MAX functions in queries
+#
+
+CREATE TABLE t1(a TINYINT, KEY(a));
+INSERT INTO t1 VALUES(1);
+SELECT MAX(a) FROM t1 IGNORE INDEX(a);
+ALTER TABLE t1 DISABLE KEYS;
+SELECT MAX(a) FROM t1;
+SELECT MAX(a) FROM t1 IGNORE INDEX(a);
+DROP TABLE t1;
+
+#
+# Test update of table joined to self
+#
+CREATE TABLE t1(a CHAR(9), b VARCHAR(7));
+INSERT INTO t1(a) VALUES('xxxxxxxxx'),('xxxxxxxxx');
+UPDATE t1 AS ta1,t1 AS ta2 SET ta1.b='aaaaaa',ta2.b='bbbbbb';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# OPTIMIZE TABLE with multiple threads
+#
+SET @@maria_repair_threads=2;
+SHOW VARIABLES LIKE 'maria_repair%';
+#
+# Test OPTIMIZE. This creates a new data file.
+CREATE TABLE t1 (
+ `_id` int(11) NOT NULL default '0',
+ `url` text,
+ `email` text,
+ `description` text,
+ `loverlap` int(11) default NULL,
+ `roverlap` int(11) default NULL,
+ `lneighbor_id` int(11) default NULL,
+ `rneighbor_id` int(11) default NULL,
+ `length_` int(11) default NULL,
+ `sequence` mediumtext,
+ `name` text,
+ `_obj_class` text NOT NULL,
+ PRIMARY KEY (`_id`),
+ UNIQUE KEY `sequence_name_index` (`name`(50)),
+ KEY (`length_`)
+) DEFAULT CHARSET=latin1;
+#
+INSERT INTO t1 VALUES
+ (1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
+ (2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
+ (3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
+ (4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
+ (5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
+ (6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
+ (7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
+ (8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
+ (9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
+#
+SELECT _id FROM t1;
+DELETE FROM t1 WHERE _id < 8;
+--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+CHECK TABLE t1 EXTENDED;
+OPTIMIZE TABLE t1;
+CHECK TABLE t1 EXTENDED;
+--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+SELECT _id FROM t1;
+DROP TABLE t1;
+#
+# Test REPAIR QUICK. This retains the old data file.
+CREATE TABLE t1 (
+ `_id` int(11) NOT NULL default '0',
+ `url` text,
+ `email` text,
+ `description` text,
+ `loverlap` int(11) default NULL,
+ `roverlap` int(11) default NULL,
+ `lneighbor_id` int(11) default NULL,
+ `rneighbor_id` int(11) default NULL,
+ `length_` int(11) default NULL,
+ `sequence` mediumtext,
+ `name` text,
+ `_obj_class` text NOT NULL,
+ PRIMARY KEY (`_id`),
+ UNIQUE KEY `sequence_name_index` (`name`(50)),
+ KEY (`length_`)
+) DEFAULT CHARSET=latin1;
+#
+INSERT INTO t1 VALUES
+ (1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample1',''),
+ (2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample2',''),
+ (3,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample3',''),
+ (4,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample4',''),
+ (5,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample5',''),
+ (6,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample6',''),
+ (7,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample7',''),
+ (8,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample8',''),
+ (9,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sample9','');
+#
+SELECT _id FROM t1;
+DELETE FROM t1 WHERE _id < 8;
+--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+CHECK TABLE t1 EXTENDED;
+REPAIR TABLE t1 QUICK;
+CHECK TABLE t1 EXTENDED;
+--replace_column 6 # 7 # 8 # 9 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+SELECT _id FROM t1;
+DROP TABLE t1;
+#
+SET @@maria_repair_threads=1;
+SHOW VARIABLES LIKE 'maria_repair%';
+
+#
+# Test varchar
+#
+
+source include/varchar.inc;
+
+#
+# Some errors/warnings on create
+#
+
+create table t1 (v varchar(65530), key(v));
+drop table if exists t1;
+create table t1 (v varchar(65536));
+show create table t1;
+drop table t1;
+create table t1 (v varchar(65530) character set utf8);
+show create table t1;
+drop table t1;
+
+# MARIA specific varchar tests
+--error 1118
+create table t1 (v varchar(65535));
+
+#
+# Test concurrent insert
+# First with static record length
+#
+set @save_concurrent_insert=@@concurrent_insert;
+set global concurrent_insert=1;
+create table t1 (a int) ROW_FORMAT=FIXED;
+insert into t1 values (1),(2),(3),(4),(5);
+lock table t1 read local;
+connect (con1,localhost,root,,);
+connection con1;
+# Insert in table without hole
+insert into t1 values(6),(7);
+connection default;
+unlock tables;
+delete from t1 where a>=3 and a<=4;
+lock table t1 read local;
+connection con1;
+set global concurrent_insert=2;
+# Insert in table with hole -> Should insert at end
+insert into t1 values (8),(9);
+connection default;
+unlock tables;
+# Insert into hole
+insert into t1 values (10),(11),(12);
+select * from t1;
+check table t1;
+drop table t1;
+disconnect con1;
+
+# Same test with dynamic record length
+create table t1 (a int, b varchar(30) default "hello") ROW_FORMAT=DYNAMIC;
+insert into t1 (a) values (1),(2),(3),(4),(5);
+lock table t1 read local;
+connect (con1,localhost,root,,);
+connection con1;
+# Insert in table without hole
+insert into t1 (a) values(6),(7);
+connection default;
+unlock tables;
+delete from t1 where a>=3 and a<=4;
+lock table t1 read local;
+connection con1;
+set global concurrent_insert=2;
+# Insert in table with hole -> Should insert at end
+insert into t1 (a) values (8),(9);
+connection default;
+unlock tables;
+# Insert into hole
+insert into t1 (a) values (10),(11),(12);
+select a from t1;
+check table t1;
+drop table t1;
+disconnect con1;
+set global concurrent_insert=@save_concurrent_insert;
+
+#
+# ANALYZE TABLE and ALTER TABLE .. ENABLE INDEX
+#
+
+create table t1 (a int, key(a));
+
+insert into t1 values (1),(2),(3),(4),(NULL),(NULL),(NULL),(NULL);
+analyze table t1;
+analyze table t1;
+show keys from t1;
+
+alter table t1 disable keys;
+alter table t1 enable keys;
+show keys from t1;
+
+drop table t1;
+
+#
+# Test temporary table with data directory option
+#
+connect (session1,localhost,root,,);
+connect (session2,localhost,root,,);
+
+connection session1;
+disable_query_log;
+disable_warnings;
+eval create temporary table t1 (a int) data directory="$MYSQLTEST_VARDIR/tmp" select 9 a;
+enable_warnings;
+enable_query_log;
+disable_result_log;
+show create table t1;
+enable_result_log;
+
+connection session2;
+disable_query_log;
+
+disable_warnings;
+eval create temporary table t1 (a int) data directory="$MYSQLTEST_VARDIR/tmp" select 99 a;
+enable_warnings;
+enable_query_log;
+disable_result_log;
+show create table t1;
+enable_result_log;
+
+connection default;
+create table t1 (a int) select 42 a;
+
+connection session1;
+select * from t1;
+disconnect session1;
+connection session2;
+select * from t1;
+disconnect session2;
+connection default;
+select * from t1;
+drop table t1;
+
+--echo End of 4.1 tests
+
+#
+# Test if PACK_KEYS option takes values greater than 1 while creating table
+#
+create table t1 (c1 int) pack_keys=0;
+create table t2 (c1 int) pack_keys=1;
+create table t3 (c1 int) pack_keys=default;
+--error 1064
+create table t4 (c1 int) pack_keys=2;
+drop table t1, t2, t3;
+
+#
+# Bug#28476: force index on a disabled maria index gives error 124
+#
+
+CREATE TABLE t1(a INT, b INT, KEY inx (a), UNIQUE KEY uinx (b));
+INSERT INTO t1(a,b) VALUES (1,1),(2,2),(3,3),(4,4),(5,5);
+SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1;
+ALTER TABLE t1 DISABLE KEYS;
+SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1;
+SELECT a FROM t1 USE INDEX (inx) WHERE a=1;
+SELECT b FROM t1 FORCE INDEX (uinx) WHERE b=1;
+SELECT b FROM t1 USE INDEX (uinx) WHERE b=1;
+SELECT a FROM t1 FORCE INDEX (inx,uinx) WHERE a=1;
+ALTER TABLE t1 ENABLE KEYS;
+SELECT a FROM t1 FORCE INDEX (inx) WHERE a=1;
+DROP TABLE t1;
+
+#
+# Bug#4692 - DISABLE/ENABLE KEYS waste a space
+#
+CREATE TABLE t1 (c1 INT, c2 INT, UNIQUE INDEX (c1), INDEX (c2));
+--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+INSERT INTO t1 VALUES (1,1);
+--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+ALTER TABLE t1 DISABLE KEYS;
+--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+ALTER TABLE t1 ENABLE KEYS;
+--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+ALTER TABLE t1 DISABLE KEYS;
+--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+ALTER TABLE t1 ENABLE KEYS;
+--replace_column 6 # 7 # 8 # 10 # 11 # 12 # 13 # 14 # 15 # 16 #
+SHOW TABLE STATUS LIKE 't1';
+#--exec ls -log var/master-data/test/t1
+#--exec maria_chk -dvv var/master-data/test/t1
+#--exec maria_chk -iev var/master-data/test/t1
+--echo # Enable keys with parallel repair
+SET @@maria_repair_threads=2;
+ALTER TABLE t1 DISABLE KEYS;
+ALTER TABLE t1 ENABLE KEYS;
+SET @@maria_repair_threads=1;
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Test doing delete with self-join
+#
+
+CREATE TABLE t1 (id int NOT NULL, ref int NOT NULL, INDEX (id));
+CREATE TABLE t2 LIKE t1;
+
+INSERT INTO t2 (id, ref) VALUES (1,3), (2,1), (3,2), (4,5), (4,4);
+INSERT INTO t1 SELECT * FROM t2;
+
+SELECT * FROM t1 AS a INNER JOIN t1 AS b USING (id) WHERE a.ref < b.ref;
+SELECT * FROM t1;
+DELETE FROM a USING t1 AS a INNER JOIN t1 AS b USING (id) WHERE a.ref < b.ref;
+SELECT * FROM t1;
+
+DROP TABLE t1, t2;
+
+#
+# Bug#37310: 'on update CURRENT_TIMESTAMP' option crashes the table
+#
+CREATE TABLE t1 (a INT) ENGINE=MARIA CHECKSUM=1 ROW_FORMAT=DYNAMIC;
+INSERT INTO t1 VALUES (0);
+UPDATE t1 SET a=1;
+SELECT a FROM t1;
+CHECK TABLE t1;
+INSERT INTO t1 VALUES (0), (5), (4), (2);
+UPDATE t1 SET a=2;
+SELECT a FROM t1;
+CHECK TABLE t1;
+DROP TABLE t1;
+
+--echo End of 5.0 tests
+
+
+#
+# Test of key_block_size
+#
+
+create table t1 (a int not null, key `a` (a) key_block_size=1024);
+show create table t1;
+drop table t1;
+
+create table t1 (a int not null, key `a` (a) key_block_size=2048);
+show create table t1;
+drop table t1;
+
+create table t1 (a varchar(2048), key `a` (a));
+show create table t1;
+drop table t1;
+
+create table t1 (a varchar(2048), key `a` (a) key_block_size=1024);
+show create table t1;
+drop table t1;
+
+create table t1 (a int not null, b varchar(2048), key (a), key(b)) key_block_size=1024;
+show create table t1;
+alter table t1 key_block_size=2048;
+show create table t1;
+alter table t1 add c int, add key (c);
+show create table t1;
+alter table t1 key_block_size=0;
+alter table t1 add d int, add key (d);
+show create table t1;
+drop table t1;
+
+create table t1 (a int not null, b varchar(2048), key (a), key(b)) key_block_size=8192;
+show create table t1;
+drop table t1;
+
+create table t1 (a int not null, b varchar(2048), key (a) key_block_size=1024, key(b)) key_block_size=8192;
+show create table t1;
+drop table t1;
+
+create table t1 (a int not null, b int, key (a) key_block_size=1024, key(b) key_block_size=8192) key_block_size=16384;
+show create table t1;
+drop table t1;
+
+# Test limits and errors of key_block_size
+
+create table t1 (a int not null, key `a` (a) key_block_size=512);
+show create table t1;
+drop table t1;
+
+create table t1 (a varchar(2048), key `a` (a) key_block_size=1000000000000000000);
+show create table t1;
+drop table t1;
+
+create table t1 (a int not null, key `a` (a) key_block_size=1025);
+show create table t1;
+drop table t1;
+
+--error 1064
+create table t1 (a int not null, key key_block_size=1024 (a));
+--error 1064
+create table t1 (a int not null, key `a` key_block_size=1024 (a));
+
+#
+# Bug#22119 - Changing MI_KEY_BLOCK_LENGTH makes a wrong myisamchk
+#
+CREATE TABLE t1 (
+ c1 INT,
+ c2 VARCHAR(300),
+ KEY (c1) KEY_BLOCK_SIZE 1024,
+ KEY (c2) KEY_BLOCK_SIZE 8192
+ );
+INSERT INTO t1 VALUES (10, REPEAT('a', CEIL(RAND(10) * 300))),
+ (11, REPEAT('b', CEIL(RAND() * 300))),
+ (12, REPEAT('c', CEIL(RAND() * 300))),
+ (13, REPEAT('d', CEIL(RAND() * 300))),
+ (14, REPEAT('e', CEIL(RAND() * 300))),
+ (15, REPEAT('f', CEIL(RAND() * 300))),
+ (16, REPEAT('g', CEIL(RAND() * 300))),
+ (17, REPEAT('h', CEIL(RAND() * 300))),
+ (18, REPEAT('i', CEIL(RAND() * 300))),
+ (19, REPEAT('j', CEIL(RAND() * 300))),
+ (20, REPEAT('k', CEIL(RAND() * 300))),
+ (21, REPEAT('l', CEIL(RAND() * 300))),
+ (22, REPEAT('m', CEIL(RAND() * 300))),
+ (23, REPEAT('n', CEIL(RAND() * 300))),
+ (24, REPEAT('o', CEIL(RAND() * 300))),
+ (25, REPEAT('p', CEIL(RAND() * 300))),
+ (26, REPEAT('q', CEIL(RAND() * 300))),
+ (27, REPEAT('r', CEIL(RAND() * 300))),
+ (28, REPEAT('s', CEIL(RAND() * 300))),
+ (29, REPEAT('t', CEIL(RAND() * 300))),
+ (30, REPEAT('u', CEIL(RAND() * 300))),
+ (31, REPEAT('v', CEIL(RAND() * 300))),
+ (32, REPEAT('w', CEIL(RAND() * 300))),
+ (33, REPEAT('x', CEIL(RAND() * 300))),
+ (34, REPEAT('y', CEIL(RAND() * 300))),
+ (35, REPEAT('z', CEIL(RAND() * 300)));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+CHECK TABLE t1;
+REPAIR TABLE t1;
+DELETE FROM t1 WHERE c1 >= 10;
+CHECK TABLE t1;
+DROP TABLE t1;
+
+#
+# Bug#33222 - myisam-table drops rows when column is added
+# and a char-field > 128 exists
+#
+# Test #1 - CHECK TABLE sees wrong record, REPAR TABLE deletes it.
+# Using a CHAR column that can have > 127 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+CREATE TABLE t1 (
+ c1 CHAR(130),
+ c2 VARCHAR(1)
+) ENGINE=maria;
+INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1;
+REPAIR TABLE t1;
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1;
+DROP TABLE t1;
+#
+# Test #2 - same as test #1, but using EXTENDED.
+# Using a CHAR column that can have > 127 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+CREATE TABLE t1 (
+ c1 CHAR(130),
+ c2 VARCHAR(1)
+) ENGINE=maria;
+INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1 EXTENDED;
+REPAIR TABLE t1 EXTENDED;
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+#
+# Test #3 - same as test #1, but using OPTIMIZE TABLE.
+# Using a CHAR column that can have > 127 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+CREATE TABLE t1 (
+ c1 CHAR(130),
+ c2 VARCHAR(1)
+) ENGINE=maria;
+INSERT INTO t1 VALUES(REPEAT("a",128), 'b');
+# Insert more rows and delete one in the middle to force optimize.
+INSERT INTO t1 VALUES('b', 'b');
+INSERT INTO t1 VALUES('c', 'b');
+DELETE FROM t1 WHERE c1='b';
+SELECT COUNT(*) FROM t1;
+OPTIMIZE TABLE t1;
+SELECT COUNT(*) FROM t1;
+DROP TABLE t1;
+#
+# Test #4 - ALTER TABLE deletes rows.
+# Using a CHAR column that can have > 127 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+# Using an index which can be disabled during bulk insert.
+CREATE TABLE t1 (
+ c1 CHAR(130),
+ c2 VARCHAR(1),
+ KEY (c1)
+) ENGINE=maria;
+#
+# Insert 100 rows. This turns bulk insert on during the copy phase of
+# ALTER TABLE. Bulk insert disables keys before the insert and re-enables
+# them by repair after the insert.
+--disable_query_log
+let $count= 100;
+--echo # Insert $count rows. Query log disabled.
+while ($count)
+{
+ INSERT INTO t1 VALUES ('a', 'b');
+ dec $count;
+}
+--enable_query_log
+#
+# Change most of the rows into long character values with > 127 characters.
+UPDATE t1 SET c1=REPEAT("a",128) LIMIT 90;
+SELECT COUNT(*) FROM t1;
+ALTER TABLE t1 ENGINE=maria;
+#
+# With bug present, this shows that all long rows are gone.
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1;
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+#
+# Test #5 - same as test #1 but UTF-8.
+# Using a CHAR column that can have > 127 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+CREATE TABLE t1 (
+ c1 CHAR(50),
+ c2 VARCHAR(1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+# Using Tamil Letter A, Unicode U+0B85
+INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1;
+REPAIR TABLE t1;
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1;
+DROP TABLE t1;
+#
+# Test #6 - same as test #2, but UTF-8.
+# Using a CHAR column that can have > 127 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+CREATE TABLE t1 (
+ c1 CHAR(50),
+ c2 VARCHAR(1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+# Using Tamil Letter A, Unicode U+0B85
+INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1 EXTENDED;
+REPAIR TABLE t1 EXTENDED;
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+#
+# Test #7 - same as test #3, but UTF-8.
+# Using a CHAR column that can have > 127 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+CREATE TABLE t1 (
+ c1 CHAR(50),
+ c2 VARCHAR(1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+# Using Tamil Letter A, Unicode U+0B85
+INSERT INTO t1 VALUES(REPEAT(_utf8 x'e0ae85',43), 'b');
+# Insert more rows and delete one in the middle to force optimize.
+INSERT INTO t1 VALUES('b', 'b');
+INSERT INTO t1 VALUES('c', 'b');
+DELETE FROM t1 WHERE c1='b';
+SELECT COUNT(*) FROM t1;
+OPTIMIZE TABLE t1;
+SELECT COUNT(*) FROM t1;
+DROP TABLE t1;
+#
+# Test #8 - same as test #4, but UTF-8.
+# Using a CHAR column that can have > 42 UTF-8 characters.
+# Using a VARCHAR to create a table with dynamic row format.
+# Using an index which can be disabled during bulk insert.
+CREATE TABLE t1 (
+ c1 CHAR(50),
+ c2 VARCHAR(1),
+ KEY (c1)
+) ENGINE=maria DEFAULT CHARSET UTF8;
+#
+# Insert 100 rows. This turns bulk insert on during the copy phase of
+# ALTER TABLE. Bulk insert disables keys before the insert and re-enables
+# them by repair after the insert.
+--disable_query_log
+let $count= 100;
+--echo # Insert $count rows. Query log disabled.
+while ($count)
+{
+ INSERT INTO t1 VALUES ('a', 'b');
+ dec $count;
+}
+--enable_query_log
+#
+# Change most of the rows into long character values with > 42 characters.
+# Using Tamil Letter A, Unicode U+0B85
+UPDATE t1 SET c1=REPEAT(_utf8 x'e0ae85',43) LIMIT 90;
+SELECT COUNT(*) FROM t1;
+ALTER TABLE t1 ENGINE=maria;
+#
+# With bug present, this shows that all long rows are gone.
+SELECT COUNT(*) FROM t1;
+CHECK TABLE t1;
+CHECK TABLE t1 EXTENDED;
+DROP TABLE t1;
+
+#
+# Bug#29182 - MyISAMCHK reports wrong character set
+#
+CREATE TABLE t1 (
+ c1 VARCHAR(10) NOT NULL,
+ c2 CHAR(10) DEFAULT NULL,
+ c3 VARCHAR(10) NOT NULL,
+ KEY (c1),
+ KEY (c2)
+) ENGINE=maria DEFAULT CHARSET=utf8 PACK_KEYS=0;
+let $MYSQLD_DATADIR= `select @@datadir`;
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--exec $MARIA_CHK -d $MYSQLD_DATADIR/test/t1
+DROP TABLE t1;
+
+# Test warnings with transactional=1 with MyISAM
+#
+create table t1 (n int not null, c char(1)) transactional=1;
+show create table t1;
+drop table t1;
+
+#
+# Test of BUG#35570 CHECKSUM TABLE unreliable if LINESTRING field
+# (same content / differen checksum)
+#
+
+CREATE TABLE t1 (line LINESTRING NOT NULL) engine=maria;
+INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t1;
+CREATE TABLE t2 (line LINESTRING NOT NULL) engine=maria;
+INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t2;
+CREATE TABLE t3 select * from t1;
+checksum table t3;
+drop table t1,t2,t3;
+--echo End of 5.1 tests
+
+#
+# from bug37276_reduced_corruption.sql
+#
+create table t2(a varchar(255),key(a))engine=maria row_format=dynamic transactional=0;
+insert into t2 values (repeat('o',124)), (repeat('h',226)), (repeat('i',236)),
+(repeat('l',234)), (repeat('b',13)), (repeat('g',236)), (repeat('y',205)),
+(repeat('c',99)), (repeat('g',145)), (repeat('o',131)), (repeat('e',63)),
+(repeat('q',155)), (repeat('k',87)), (repeat('i',54)), (repeat('p',84)),
+(repeat('m',119)), (repeat('c',2)), (repeat('a',174)), (repeat('g',160)),
+(repeat('t',147)), (repeat('n',107));
+insert into t2 values ('nupdjlafwfvuuvruxkyjxpmupihzgspkaybijztkeukgzzkrxmd');
+insert into t2 values (repeat('g',40)), (repeat('i',173)), (repeat('q',126)),
+(repeat('i',217)), (repeat('f',161)), (repeat('i',28)), (repeat('a',35)),
+(repeat('y',27)), (repeat('o',100)), (repeat('o',175)), (repeat('f',69)),
+(repeat('k',156)), (repeat('n',220)), (repeat('q',247)), (repeat('y',180)),
+(repeat('v',209)), (repeat('m',169)), (repeat('y',170)), (repeat('r',151)),
+(repeat('d',38)), (repeat('g',64)), (repeat('k',77)), (repeat('l',150)),
+(repeat('s',150)), (repeat('u',127)), (repeat('l',15)), (repeat('m',33)),
+(repeat('r',177)), (repeat('v',197)), (repeat('k',62)), (repeat('h',219)),
+(repeat('u',161)), (repeat('y',118)), (repeat('i',184)), (repeat('z',202)),
+(repeat('j',113)), (repeat('q',95)), (repeat('q',164)), (repeat('e',54)),
+(repeat('e',60)), (repeat('l',203)), (repeat('g',77)), (repeat('y',44)),
+(repeat('j',196)), (repeat('t',45)), (repeat('l',190)), (repeat('l',89)),
+(repeat('q',45)), (repeat('e',191)), (repeat('t',38)), (repeat('f',148)),
+(repeat('c',25)), (repeat('v',97)), (repeat('i',83)), (repeat('s',166)),
+(repeat('d',96)), (repeat('v',82)), (repeat('n',127)), (repeat('i',201)),
+(repeat('x',184)), (repeat('d',76)), (repeat('u',17)), (repeat('a',178));
+insert into t2 values ('hwvfiavnmufgbulapzrolonwxufheqymvjncnczlzcjokzqlsvmomcjzgzwzquyxpunxdmotdczocwliaprpubwaeccsulvittgizcutxxb');
+insert into t2 values (repeat('x',28)), (repeat('p',21)), (repeat('k',241)),
+(repeat('i',243)), (repeat('b',172)), (repeat('z',94)), (repeat('i',218)),
+(repeat('a',177)), (repeat('g',251)), (repeat('q',161)), (repeat('x',231)),
+(repeat('p',51)), (repeat('f',141)), (repeat('m',28)), (repeat('r',77)),
+(repeat('h',56)), (repeat('k',23)), (repeat('f',198)), (repeat('o',243)),
+(repeat('d',160)), (repeat('h',82));
+
+check table t2 extended;
+drop table t2;
+
+CREATE TABLE t1 (
+col0 float DEFAULT NULL,
+col1 date DEFAULT NULL,
+col2 double DEFAULT NULL,
+col3 decimal(10,0) DEFAULT NULL,
+col4 char(218) DEFAULT NULL,
+col5 year(4) DEFAULT NULL,
+col6 datetime DEFAULT NULL,
+col7 varchar(39) DEFAULT NULL,
+col8 double DEFAULT NULL,
+col9 decimal(10,0) DEFAULT NULL,
+col10 enum('test1','test2','test3') DEFAULT NULL,
+col11 year(4) DEFAULT NULL,
+col12 tinytext,
+col13 tinyblob,
+col14 date DEFAULT NULL,
+col15 smallint(6) DEFAULT NULL,
+col16 varchar(81) DEFAULT NULL,
+col17 tinytext,
+col18 blob,
+col19 double DEFAULT NULL,
+col20 double DEFAULT NULL,
+col21 varchar(216) DEFAULT NULL,
+col22 enum('test1','test2','test3') DEFAULT NULL,
+col23 decimal(10,0) DEFAULT NULL,
+col24 text,
+col25 varchar(118) DEFAULT NULL,
+col26 tinytext,
+col27 tinyblob,
+col28 double DEFAULT NULL,
+col29 tinyint(4) DEFAULT NULL,
+col30 longtext,
+col31 tinyint(1) DEFAULT NULL,
+col32 char(212) DEFAULT NULL,
+col33 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+col34 year(4) DEFAULT NULL,
+col35 tinyint(1) DEFAULT NULL,
+col36 enum('test1','test2','test3') DEFAULT NULL,
+col37 decimal(10,0) DEFAULT NULL,
+col38 tinyint(4) DEFAULT NULL,
+col39 double DEFAULT NULL,
+col40 decimal(10,0) DEFAULT NULL,
+col41 enum('test1','test2','test3') DEFAULT NULL,
+col42 longblob,
+col43 text,
+col44 blob,
+col45 year(4) DEFAULT NULL,
+col46 longtext,
+col47 int(11) DEFAULT NULL,
+col48 set('test1','test2','test3') DEFAULT NULL,
+col49 bigint(20) DEFAULT NULL,
+col50 date DEFAULT NULL,
+col51 tinyblob,
+col52 float DEFAULT NULL,
+col53 year(4) DEFAULT NULL,
+col54 decimal(10,0) DEFAULT NULL,
+col55 tinyblob,
+col56 float DEFAULT NULL,
+col57 bigint(20) DEFAULT NULL,
+col58 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+col59 enum('test1','test2','test3') DEFAULT NULL,
+col60 bigint(20) DEFAULT NULL,
+col61 year(4) DEFAULT NULL,
+col62 year(4) DEFAULT NULL,
+col63 double DEFAULT NULL,
+col64 tinytext,
+col65 tinyint(4) DEFAULT NULL,
+col66 longtext,
+col67 time DEFAULT NULL,
+col68 bigint(20) DEFAULT NULL,
+col69 char(142) DEFAULT NULL,
+col70 longtext,
+col71 time DEFAULT NULL,
+col72 year(4) DEFAULT NULL,
+col73 longblob,
+col74 enum('test1','test2','test3') DEFAULT NULL,
+col75 decimal(10,0) DEFAULT NULL,
+col76 smallint(6) DEFAULT NULL,
+col77 tinytext,
+col78 date DEFAULT NULL,
+col79 double DEFAULT NULL,
+col80 tinyint(4) DEFAULT NULL,
+col81 float DEFAULT NULL,
+col82 bigint(20) DEFAULT NULL,
+col83 double DEFAULT NULL,
+col84 varchar(124) DEFAULT NULL,
+col85 double DEFAULT NULL,
+col86 tinyblob,
+col87 tinyblob,
+col88 double DEFAULT NULL,
+col89 date DEFAULT NULL,
+col90 decimal(10,0) DEFAULT NULL,
+col91 set('test1','test2','test3') DEFAULT NULL,
+col92 blob,
+col93 char(174) DEFAULT NULL,
+col94 double DEFAULT NULL,
+col95 tinytext,
+col96 decimal(10,0) DEFAULT NULL,
+col97 year(4) DEFAULT NULL,
+col98 tinyblob,
+col99 datetime DEFAULT NULL,
+col100 longblob,
+col101 date DEFAULT NULL,
+col102 float DEFAULT NULL,
+col103 float DEFAULT NULL,
+col104 int(11) DEFAULT NULL,
+col105 longblob,
+col106 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
+col107 float DEFAULT NULL,
+col108 text,
+col109 float DEFAULT NULL,
+col110 decimal(10,0) DEFAULT NULL,
+col111 double DEFAULT NULL,
+col112 double DEFAULT NULL,
+col113 blob,
+col114 varchar(152) DEFAULT NULL,
+col115 bigint(20) DEFAULT NULL,
+col116 decimal(10,0) DEFAULT NULL,
+col117 mediumint(9) DEFAULT NULL,
+col118 tinytext,
+col119 tinyblob,
+col120 int(11) DEFAULT NULL,
+col121 bigint(20) DEFAULT NULL,
+col122 double DEFAULT NULL,
+col123 date DEFAULT NULL,
+col124 longtext,
+col125 longtext,
+col126 double DEFAULT NULL,
+col127 varchar(84) DEFAULT NULL,
+col128 text,
+col129 double DEFAULT NULL,
+col130 enum('test1','test2','test3') DEFAULT NULL,
+col131 time DEFAULT NULL,
+col132 year(4) DEFAULT NULL,
+col133 blob,
+col134 tinytext,
+col135 double DEFAULT NULL,
+col136 tinytext,
+col137 bigint(20) DEFAULT NULL,
+col138 datetime DEFAULT NULL,
+col139 double DEFAULT NULL,
+col140 decimal(10,0) DEFAULT NULL,
+col141 longtext,
+col142 tinyint(1) DEFAULT NULL,
+col143 time DEFAULT NULL,
+col144 time DEFAULT NULL,
+col145 float DEFAULT NULL,
+col146 longblob,
+col147 float DEFAULT NULL,
+col148 text,
+col149 mediumint(9) DEFAULT NULL,
+col150 tinyblob,
+col151 tinyblob,
+col152 tinytext,
+col153 tinyblob,
+col154 tinyblob,
+col155 tinytext,
+col156 tinyint(1) DEFAULT NULL,
+col157 tinytext,
+col158 time DEFAULT NULL,
+col159 date DEFAULT NULL,
+col160 longtext,
+col161 enum('test1','test2','test3') DEFAULT NULL,
+col162 text,
+col163 decimal(10,0) DEFAULT NULL,
+col164 time DEFAULT NULL,
+col165 longblob,
+col166 tinyint(4) DEFAULT NULL,
+col167 bigint(20) DEFAULT NULL,
+col168 decimal(10,0) DEFAULT NULL,
+col169 smallint(6) DEFAULT NULL,
+col170 tinytext,
+col171 tinyint(4) DEFAULT NULL,
+col172 tinyint(1) DEFAULT NULL,
+col173 tinytext,
+col174 decimal(10,0) DEFAULT NULL,
+col175 double DEFAULT NULL
+) engine=maria;
+
+insert ignore into t1 set
+col10=abs(28449) % 2,
+col11='1973',
+col12=if(abs(-30039)%100<20,null,'forgery\'s'),
+col13=if(abs(24672)%100<20,null,'adductor\'s'),
+col16=if(abs(26872)%100<20,null,'0xf810e016ee0b78e1ce8b1c6cf8d2e82bf8507453768a3908dc20cecfc9a0ac0ac00079d0645a4c'),
+col18=if(abs(-15854)%100<20,null,'unattractiveness'),
+col19=if(abs(4287439673.9896235000)%100<20,null,25288),
+col20=if(abs(4290800136.7527390000)%100<20,null,8887),
+col21=if(abs(-26086)%100<20,null,'0x2334181c6068aab18b348ecc1e2600b81e1c5f821eee3e204824'),
+col22=abs(-21921) % 2,
+col23=if(abs(1503277.6900540178)%100<20,null,-23298),
+col25=if(abs(29674)%100<20,null,'0xc8d094f888ee20c83baef8d9380a168d40f4906e742a4dc0daeacb809e64095c71d510c7c0f83a6a0a04b8d6a0d9bea2dc3d4bd44d9c5002e440707c40ead8b3eb20a100a8524b1616a338a440ea02a25a08041810a08cac087cd47b4a79f08730946c5800600ae45e1c08f637'),
+col26=if(abs(28642)%100<20,null,'insubstantiality\'s'),
+col27=if(abs(-3188)%100<20,null,'exine\'s'),
+col29=if(abs(-47)%100<20,null,-24131),
+col32=if(abs(-3658)%100<20,null,'shortener\'s'),
+col34='1917',
+col36=abs(27782) % 2,
+col37=if(abs(4864972.0244758446)%100<20,null,32302),
+col38=if(abs(97)%100<20,null,-14079),
+col39=if(abs(3362872.0521256141)%100<20,null,27191),
+col40=if(abs(3348292.2110660113)%100<20,null,-1163),
+col41=abs(-18533) % 2,
+col42=if(abs(2094)%100<20,null,'Montparnasse'),
+col43=if(abs(-15983)%100<20,null,'Massasoit\'s'),
+col44=if(abs(2497)%100<20,null,'lags'),
+col45='2057',
+col46=if(abs(-31691)%100<20,null,'miscegenation\'s'),
+col47=if(abs(-1269564297)%100<20,null,1089),
+col49=if(abs(-1815717335)%100<20,null,-17504),
+col51=if(abs(-15263)%100<20,null,'virelay'),
+col52=if(abs(2227333.3279519030)%100<20,null,-5210),
+col53='2032',
+col54=if(abs(791647.5947447127)%100<20,null,32576),
+col55=if(abs(20293)%100<20,null,'tumblebug'),
+col56=if(abs(4288698564.2967925000)%100<20,null,17141),
+col57=if(abs(-2138460927)%100<20,null,14495),
+col59=abs(7624) % 2,
+col60=if(abs(-1500892492)%100<20,null,-68),
+col63=if(abs(4290890487.3789482000)%100<20,null,-32129),
+col65=if(abs(22)%100<20,null,15722),
+col79=if(abs(4292420489.2606282000)%100<20,null,-23891),
+col84=if(abs(-21248)%100<20,null,'0x4f9888d044435050eab83cb3dcad88b01886e434e216'),
+col85=if(abs(4294260188.6230965000)%100<20,null,16867),
+col86=if(abs(-11659)%100<20,null,'prewar'),
+col87=if(abs(-2253)%100<20,null,'Radnorshire'),
+col90=if(abs(4287254529.4026613000)%100<20,null,23506),
+col92=if(abs(6472)%100<20,null,'electroplated'),
+col93=if(abs(-13523)%100<20,null,'sparkiest'),
+col95=if(abs(23998)%100<20,null,'Crimea'),
+col96=if(abs(4287719060.2789087000)%100<20,null,20527),
+col98=if(abs(-14090)%100<20,null,'firebrat'),
+col99='19161023095430',
+col100=if(abs(-31178)%100<20,null,'clinical'),
+col102=if(abs(4407547.5205542166)%100<20,null,18226),
+col103=if(abs(4286834687.5994444000)%100<20,null,27520),
+col104=if(abs(-2105663477)%100<20,null,28591),
+col105=if(abs(1929)%100<20,null,'renascent'),
+col107=if(abs(5972348.8099917602)%100<20,null,-11408),
+col108=if(abs(-11262)%100<20,null,'aircraftmen'),
+col110=if(abs(6530491.4546037167)%100<20,null,-17672),
+col111=if(abs(4289897795.5000763000)%100<20,null,3742),
+col112=if(abs(1680557.8560441907)%100<20,null,13944),
+col113=if(abs(-27195)%100<20,null,'dekameter'),
+col115=if(abs(-2083419827)%100<20,null,-17272),
+col117=if(abs(1704826)%100<20,null,17880),
+col118=if(abs(-2848)%100<20,null,'judicatory'),
+col119=if(abs(-28087)%100<20,null,'mistitles'),
+col120=if(abs(-2100119097)%100<20,null,22465),
+col121=if(abs(-1868777891)%100<20,null,15172),
+col122=if(abs(7039857.3608508557)%100<20,null,-22154),
+col125=if(abs(70)%100<20,null,'Hong\'s'),
+col126=if(abs(3820673.5968199712)%100<20,null,-24185),
+col127=if(abs(12331)%100<20,null,'0x674e14584e88fca3fed0a0b1488a440008228aa01454a65cf09e3f0fa0511c3ce2f8688450'),
+col128=if(abs(20335)%100<20,null,'Zoroaster\'s'),
+col129=if(abs(3916577.6225165562)%100<20,null,-4088),
+col130=abs(-15003) % 2,
+col132='2016',
+col134=if(abs(-26555)%100<20,null,'Caesarea'),
+col135=if(abs(4288484655.2416148000)%100<20,null,-30073),
+col136=if(abs(-17577)%100<20,null,'upbraid'),
+col137=if(abs(-1742797945)%100<20,null,-21651),
+col138='20751113181230',
+col139=if(abs(4288997063.9889216000)%100<20,null,1816),
+col141=if(abs(-31448)%100<20,null,'threnodist'),
+col142=if(abs(88)%100<20,null,-19748),
+col143='6930607',
+col144='5760250',
+col145=if(abs(3591496.9625843074)%100<20,null,76),
+col146=if(abs(20875)%100<20,null,'rename'),
+col147=if(abs(4294789439.6773582000)%100<20,null,32314),
+col148=if(abs(7072)%100<20,null,'recesses'),
+col150=if(abs(-26540)%100<20,null,'cuckoo'),
+col152=if(abs(23553)%100<20,null,'shortened'),
+col153=if(abs(-30422)%100<20,null,'inhabitant'),
+col154=if(abs(30457)%100<20,null,'Orwellian'),
+col155=if(abs(-30263)%100<20,null,'Ptolemies'),
+col156=if(abs(-41)%100<20,null,6382),
+col157=if(abs(2557)%100<20,null,'horsewhips'),
+col158='2764427',
+col160=if(abs(-15872)%100<20,null,'girlhood'),
+col161=abs(15378) % 2,
+col163=if(abs(4286662730.9309368000)%100<20,null,-19516),
+col167=if(abs(-1881918655)%100<20,null,6927),
+col169=if(abs(-14442)%100<20,null,-6392),
+col170=if(abs(29965)%100<20,null,'resynthesis'),
+col173=if(abs(-451)%100<20,null,'Clute'),
+col174=if(abs(3262594.6284981840)%100<20,null,17846);
+
+update ignore t1 set col165=repeat('a',7000);
+check table t1;
+drop table t1;
+
+#
+# Bug#38466 maria: range query returns no data
+#
+
+create table t1 (a char(200) primary key, b int default 12345) engine=maria;
+insert t1 (a) values (repeat('0', 200));
+insert t1 (a) values (repeat('1', 200)), (repeat('2', 200)), (repeat('3', 200)),
+ (repeat('4', 200)), (repeat('5', 200)), (repeat('6', 200)), (repeat('7', 200)),
+ (repeat('8', 200)), (repeat('9', 200)), (repeat('a', 200)), (repeat('b', 200)),
+ (repeat('c', 200)), (repeat('d', 200)), (repeat('e', 200)), (repeat('f', 200)),
+ (repeat('g', 200)), (repeat('h', 200)), (repeat('i', 200)), (repeat('j', 200)),
+ (repeat('k', 200)), (repeat('l', 200)), (repeat('m', 200)), (repeat('n', 200)),
+ (repeat('o', 200)), (repeat('p', 200)), (repeat('q', 200)), (repeat('r', 200)),
+ (repeat('s', 200)), (repeat('t', 200)), (repeat('u', 200)), (repeat('v', 200)),
+ (repeat('w', 200)), (repeat('x', 200)), (repeat('y', 200)), (repeat('z', 200)),
+ (repeat('+', 200)), (repeat('-', 200)), (repeat('=', 200)), (repeat('*', 200));
+select b from t1 where a >= repeat('f', 200) and a < 'k';
+drop table t1;
+
+#
+# BUG#38606 test suite
+#
+create table t1 (a int) engine=maria transactional=1;
+insert into t1 values (1);
+lock table t1 write concurrent;
+# should be fixed with fully implemented versioning
+--error ER_CHECK_NOT_IMPLEMENTED
+delete from t1;
+drop table t1;
+
+#
+# Bug#39243 SELECT WHERE does not find row
+# (Problem with skip_row)
+#
+
+create table t1 (p int primary key, i int, a char(10), key k1(i), key k2(a))
+engine maria;
+insert into t1 values (1, 1, 'qqqq'), (2, 1, 'pppp'),
+ (3, 1, 'yyyy'), (4, 3, 'zzzz');
+insert into t1 values (5, 3, 'yyyy'), (6, 3, 'yyyy'), (7, 0, NULL),
+ (8, 0, NULL);
+select * from t1 where a='zzzz';
+select * from t1 where a='yyyy';
+select * from t1 where a is NULL;
+select * from t1;
+check table t1;
+drop table t1;
+
+#
+# Bug39248 INSERT ON DUPLICATE KEY UPDATE gives error if using a view
+# Note that this only crashes when using
+# --mysqld=--binlog-format=row --ps-protocol
+#
+
+create table t1 (f1 int unique, f2 int) engine=maria;
+create table t2 (f3 int, f4 int) engine=maria;
+create view v1 as select * from t1, t2 where f1= f3;
+insert into t1 values (1,11), (2,22);
+--error 1393
+insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
+--error 1393
+insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
+drop table t1,t2;
+drop view v1;
+
+#
+# BUG#39399 ALTER TABLE renaming column: affected_rows > 0
+#
+
+CREATE TABLE t1 (id int, c varchar(10)) engine=maria;
+INSERT INTO t1 VALUES (1,"1");
+--enable_info
+ALTER TABLE t1 CHANGE c d varchar(10);
+--disable_info
+drop table t1;
+
+#
+# Bug #39226 Maria: crash with FLUSH TABLES WITH READ LOCK after LOCK TABLES
+
+create table t1 (c1 int);
+create table t2 (c1 int);
+lock table t1 read, t2 read;
+flush tables with read lock;
+unlock tables;
+drop table t1, t2;
+
+#
+# Bug #40311
+# Crash when aborting inserting of row with 2 blobs where first is short
+#
+
+create table t1(a int primary key, b blob, c blob) engine=maria;
+insert into t1 values(1,repeat('a',100), repeat('b',657860));
+--error ER_DUP_ENTRY
+insert into t1 values(1,repeat('a',100), repeat('b',657860));
+check table t1;
+drop table t1;
+
+# Set defaults back
+--disable_result_log
+--disable_query_log
+eval set global storage_engine=$default_engine,
+maria_page_checksum=$default_checksum,
+maria_log_file_size=$default_log_file_size;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria2.test b/mysql-test/suite/maria/t/maria2.test
new file mode 100644
index 00000000000..45155ab9cae
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria2.test
@@ -0,0 +1,110 @@
+--source include/have_maria.inc
+
+# Initialise
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+
+# Test for BUG#36319
+# "Maria: table is not empty but DELETE and SELECT find no rows"
+
+CREATE TABLE t1 (
+ line BLOB,
+ kind ENUM('po', 'pp', 'rr', 'dr', 'rd', 'ts', 'cl') NOT NULL DEFAULT 'po',
+ name VARCHAR(32)
+) transactional=0 row_format=page engine=maria;
+
+let $query= INSERT INTO t1 (name, kind, line) VALUES
+ ("Aadaouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadassiye", "pp", GeomFromText("POINT(35.816667 36.216667)")),
+ ("Aadbel", "pp", GeomFromText("POINT(34.533333 36.100000)")),
+ ("Aadchit", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchite", "pp", GeomFromText("POINT(33.347222 35.423611)")),
+ ("Aadchit el Qoussair", "pp", GeomFromText("POINT(33.283333 35.483333)")),
+ ("Aaddaye", "pp", GeomFromText("POINT(36.716667 40.833333)")),
+ ("'Aadeissa", "pp", GeomFromText("POINT(32.823889 35.698889)")),
+ ("Aaderup", "pp", GeomFromText("POINT(55.216667 11.766667)")),
+ ("Qalaat Aades", "pp", GeomFromText("POINT(33.503333 35.377500)")),
+ ("A ad'ino", "pp", GeomFromText("POINT(54.812222 38.209167)")),
+ ("Aadi Noia", "pp", GeomFromText("POINT(13.800000 39.833333)")),
+ ("Aad La Macta", "pp", GeomFromText("POINT(35.779444 -0.129167)")),
+ ("Aadland", "pp", GeomFromText("POINT(60.366667 5.483333)")),
+ ("Aadliye", "pp", GeomFromText("POINT(33.366667 36.333333)")),
+ ("Aadloun", "pp", GeomFromText("POINT(33.403889 35.273889)")),
+ ("Aadma", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadma Asundus", "pp", GeomFromText("POINT(58.798333 22.663889)")),
+ ("Aadmoun", "pp", GeomFromText("POINT(34.150000 35.650000)")),
+ ("Aadneram", "pp", GeomFromText("POINT(59.016667 6.933333)")),
+ ("Aadneskaar", "pp", GeomFromText("POINT(58.083333 6.983333)")),
+ ("Aadorf", "pp", GeomFromText("POINT(47.483333 8.900000)")),
+ ("Aadorp", "pp", GeomFromText("POINT(52.366667 6.633333)")),
+ ("Aadouane", "pp", GeomFromText("POINT(32.816667 35.983333)")),
+ ("Aadoui", "pp", GeomFromText("POINT(34.450000 35.983333)")),
+ ("Aadouiye", "pp", GeomFromText("POINT(34.583333 36.183333)")),
+ ("Aadouss", "pp", GeomFromText("POINT(33.512500 35.601389)")),
+ ("Aadra", "pp", GeomFromText("POINT(33.616667 36.500000)")),
+ ("Aadzi", "pp", GeomFromText("POINT(38.100000 64.850000)"));
+
+--disable_query_log
+let $1=90;
+while($1)
+{
+ eval $query;
+ dec $1;
+}
+let $1=90;
+while($1)
+{
+ delete from t1 limit 1;
+ delete from t1 limit 10;
+ delete from t1 limit 7;
+ delete from t1 limit 2;
+ dec $1;
+}
+--enable_query_log
+
+select count(*) from t1;
+delete from t1 limit 1000;
+select count(*) from t1;
+select name from t1;
+check table t1 extended;
+drop table t1;
+
+#
+# Testing of ALTER TABLE under lock tables
+#
+
+create table t1 (i int) engine=maria;
+create table t2 (j int) engine=maria;
+lock table t1 write, t2 read;
+alter table t1 modify i int default 1;
+insert into t1 values (2);
+# This caused a core dump
+alter table t1 modify i bigint default 1;
+select count(*) from t1;
+select * from t1;
+drop table t1,t2;
+
+#
+# test INSERT ON DUPLICATE KEY UPDATE
+#
+
+create table t1(id int, s char(1), unique(s)) engine=maria;
+insert into t1 values(1,"a") on duplicate key update t1.id=t1.id+1;
+insert into t1 values(1,"a") on duplicate key update t1.id=t1.id+1;
+insert into t1 select 1,"a" on duplicate key update t1.id=t1.id+1;
+select * from t1;
+
+# test REPLACE SELECT
+replace into t1 select 1,"a";
+select * from t1;
+drop table t1;
+
+# test LOAD DATA INFILE REPLACE
+create table t1 (pk int primary key, apk int unique, data int) engine=maria;
+insert into t1 values (1, 1, 1), (4, 4, 4), (6, 6, 6);
+load data concurrent infile '../../std_data/loaddata5.dat' replace into table t1 fields terminated by '' enclosed by '' ignore 1 lines (pk, apk);
+select * from t1 order by pk;
+load data infile '../../std_data/loaddata5.dat' replace into table t1 fields terminated by '' enclosed by '' ignore 1 lines (pk, apk);
+select * from t1 order by pk;
+drop table t1;
diff --git a/mysql-test/suite/maria/t/maria3.test b/mysql-test/suite/maria/t/maria3.test
new file mode 100644
index 00000000000..992754cc11f
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria3.test
@@ -0,0 +1,491 @@
+-- source include/have_maria.inc
+
+select * from INFORMATION_SCHEMA.ENGINES where ENGINE="MARIA";
+
+let $default_engine=`select @@global.storage_engine`;
+let $default_checksum=`select @@global.maria_page_checksum`;
+set global storage_engine=maria;
+set session storage_engine=maria;
+set global maria_page_checksum=0;
+let $default_log_file_size=`select @@global.maria_log_file_size`;
+set global maria_log_file_size=4294967295;
+
+# Initialise
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+SET SQL_WARNINGS=1;
+
+# Test limits and errors of key_block_size
+
+create table t1 (a int not null, key `a` (a) key_block_size=512);
+show create table t1;
+drop table t1;
+
+create table t1 (a varchar(2048), key `a` (a) key_block_size=1000000000000000000);
+show create table t1;
+drop table t1;
+
+create table t1 (a int not null, key `a` (a) key_block_size=1025);
+show create table t1;
+drop table t1;
+
+--error 1064
+create table t1 (a int not null, key key_block_size=1024 (a));
+--error 1064
+create table t1 (a int not null, key `a` key_block_size=1024 (a));
+
+#
+# Test of changing MI_KEY_BLOCK_LENGTH
+#
+
+CREATE TABLE t1 (
+ c1 INT,
+ c2 VARCHAR(300),
+ KEY (c1) KEY_BLOCK_SIZE 1024,
+ KEY (c2) KEY_BLOCK_SIZE 8192
+ );
+INSERT INTO t1 VALUES (10, REPEAT('a', CEIL(RAND(10) * 300))),
+ (11, REPEAT('b', CEIL(RAND() * 300))),
+ (12, REPEAT('c', CEIL(RAND() * 300))),
+ (13, REPEAT('d', CEIL(RAND() * 300))),
+ (14, REPEAT('e', CEIL(RAND() * 300))),
+ (15, REPEAT('f', CEIL(RAND() * 300))),
+ (16, REPEAT('g', CEIL(RAND() * 300))),
+ (17, REPEAT('h', CEIL(RAND() * 300))),
+ (18, REPEAT('i', CEIL(RAND() * 300))),
+ (19, REPEAT('j', CEIL(RAND() * 300))),
+ (20, REPEAT('k', CEIL(RAND() * 300))),
+ (21, REPEAT('l', CEIL(RAND() * 300))),
+ (22, REPEAT('m', CEIL(RAND() * 300))),
+ (23, REPEAT('n', CEIL(RAND() * 300))),
+ (24, REPEAT('o', CEIL(RAND() * 300))),
+ (25, REPEAT('p', CEIL(RAND() * 300))),
+ (26, REPEAT('q', CEIL(RAND() * 300))),
+ (27, REPEAT('r', CEIL(RAND() * 300))),
+ (28, REPEAT('s', CEIL(RAND() * 300))),
+ (29, REPEAT('t', CEIL(RAND() * 300))),
+ (30, REPEAT('u', CEIL(RAND() * 300))),
+ (31, REPEAT('v', CEIL(RAND() * 300))),
+ (32, REPEAT('w', CEIL(RAND() * 300))),
+ (33, REPEAT('x', CEIL(RAND() * 300))),
+ (34, REPEAT('y', CEIL(RAND() * 300))),
+ (35, REPEAT('z', CEIL(RAND() * 300)));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+CHECK TABLE t1;
+REPAIR TABLE t1;
+DELETE FROM t1 WHERE c1 >= 10;
+CHECK TABLE t1;
+DROP TABLE t1;
+
+#
+# Test that TRANSACTIONAL is preserved
+#
+
+create table t1 (a int) transactional=0;
+show create table t1;
+drop table t1;
+create table t1 (a int) row_format=dynamic transactional=0;
+show create table t1;
+drop table t1;
+create table t1 (a int) row_format=dynamic transactional=1;
+show create table t1;
+alter table t1 row_format=PAGE;
+show create table t1;
+alter table t1 row_format=DYNAMIC;
+show create table t1;
+alter table t1 transactional=0;
+show create table t1;
+alter table t1 row_format=DYNAMIC;
+show create table t1;
+drop table t1;
+create table t1 (a int) row_format=PAGE;
+show create table t1;
+drop table t1;
+create table t1 (a int) row_format=PAGE TRANSACTIONAL=DEFAULT;
+show create table t1;
+alter table t1 row_format=DYNAMIC;
+show create table t1;
+drop table t1;
+
+# CHECK TABLE was reporting
+# "Size of datafile is: 0 Should be: 16384"
+#
+
+create table `t1` (
+ t1_name varchar(255) default null,
+ t1_id int(10) unsigned not null auto_increment,
+ key (t1_name),
+ primary key (t1_id)
+) engine=maria auto_increment = 1000 default charset=latin1;
+lock tables t1 write;
+INSERT INTO `t1` VALUES ('bla',1000),('bla',1001),('bla',1002);
+check table t1;
+unlock tables;
+
+#
+# Check that an empty table uses fast recreate of index when we fill it
+# with insert ... select.
+
+create table t2 like t1;
+insert into t2 select * from t1;
+
+# This should say that the table is already up to date
+analyze table t2;
+delete from t2;
+insert into t2 select * from t1;
+analyze table t2;
+
+drop table t1,t2;
+
+#
+# Test when expanding a row so that it doesn't fit into the same page
+#
+
+create table t1 (a bigint auto_increment, primary key(a), b char(255), c varchar(20000));
+
+let $1=1000;
+--disable_query_log
+--disable_warnings
+while ($1)
+{
+ insert into t1 () values();
+ dec $1;
+}
+--enable_query_log
+update t1 set b=repeat('a',100) where a between 1 and 100;
+check table t1;
+update t1 set c=repeat('a',8192*2) where a between 200 and 202;
+check table t1;
+drop table t1;
+
+#
+# Test where we shrink varchar
+#
+
+CREATE TABLE t1 (a int, b int, v varchar(60000)) checksum=1 engine=maria;
+insert into t1 values (1,1,"aaa"),(1,2,null);
+checksum table t1;
+lock table t1 write;
+insert into t1 values (1,3,repeat('c',30000)),(4,4,repeat('a',30000));
+update t1 set v="row5" where b=4;
+delete from t1 where b=3;
+select a, b, length(v) from t1;
+drop table t1;
+
+#
+# Test tail pages for blobs
+#
+
+CREATE TABLE t1 (
+ auto int(5) unsigned NOT NULL auto_increment,
+ string char(10) default "hello",
+ tiny tinyint(4) DEFAULT '0' NOT NULL ,
+ short smallint(6) DEFAULT '1' NOT NULL ,
+ medium mediumint(8) DEFAULT '0' NOT NULL,
+ long_int int(11) DEFAULT '0' NOT NULL,
+ longlong bigint(13) DEFAULT '0' NOT NULL,
+ real_float float(13,1) DEFAULT 0.0 NOT NULL,
+ real_double double(16,4),
+ utiny tinyint(3) unsigned DEFAULT '0' NOT NULL,
+ ushort smallint(5) unsigned zerofill DEFAULT '00000' NOT NULL,
+ umedium mediumint(8) unsigned DEFAULT '0' NOT NULL,
+ ulong int(11) unsigned DEFAULT '0' NOT NULL,
+ ulonglong bigint(13) unsigned DEFAULT '0' NOT NULL,
+ time_stamp timestamp,
+ date_field date,
+ time_field time,
+ date_time datetime,
+ blob_col blob,
+ tinyblob_col tinyblob,
+ mediumblob_col mediumblob not null default '',
+ longblob_col longblob not null default '',
+ options enum('one','two','tree') not null ,
+ flags set('one','two','tree') not null default '',
+ PRIMARY KEY (auto),
+ KEY (utiny),
+ KEY (tiny),
+ KEY (short),
+ KEY any_name (medium),
+ KEY (longlong),
+ KEY (real_float),
+ KEY (ushort),
+ KEY (umedium),
+ KEY (ulong),
+ KEY (ulonglong,ulong),
+ KEY (options,flags)
+) engine=maria;
+insert into t1 values (10,1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one');
+create table t2 (primary key (auto)) engine=maria row_format=page select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
+check table t1,t2;
+select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
+drop table t2;
+create table t2 (primary key (auto)) engine=maria row_format=dynamic select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1;
+check table t2;
+drop table t1,t2;
+
+# Test UPDATE with small BLOB which fits on head page
+
+CREATE TABLE t1 (seq int, s1 int, s2 blob);
+insert into t1 values (1, 1, MD5(1));
+update t1 set s1=2 where seq=1;
+check table t1 extended;
+drop table t1;
+
+# Fix if we are using safemalloc
+--replace_result 8388572 8388600
+show variables like 'maria%';
+--replace_column 2 #
+show status like 'maria%';
+
+#
+# Test creating table with no field data and index on zero length columns
+#
+
+create table t1 (b char(0));
+insert into t1 values(NULL),("");
+select length(b) from t1;
+alter table t1 add column c char(0), add key (c);
+insert into t1 values("",""),("",NULL);
+select length(b),length(c) from t1;
+select length(b),length(c) from t1 where c is null;
+select length(b),length(c) from t1 where c is not null;
+select length(b),length(c) from t1 order by c;
+--error 1167
+alter table t1 add column d char(0) not null, add key (d);
+drop table t1;
+
+CREATE TABLE t1 (a bit(3));
+insert into t1 values (NULL),(0),(1),(2),(3),(4),(5),(6),(7);
+select hex(a) from t1;
+drop table t1;
+create table t1(a bit not null);
+insert into t1 values(0),(1);
+select a+0 from t1;
+drop table t1;
+
+#
+# Test of min_key_length
+#
+
+CREATE TABLE t1 (col1 int, s1 char(16) DEFAULT NULL, s2 char(16) DEFAULT NULL, KEY (s1,s2));
+insert into t1 (col1) values(0);
+drop table t1;
+
+#
+# Show that page_checksum is remembered
+#
+set global maria_page_checksum=1;
+create table t1 (a int);
+show create table t1;
+drop table t1;
+
+#
+# Test warning on log file size truncates
+#
+
+--enable_warnings
+set global maria_log_file_size=4294967296;
+
+#
+# Test delete of all rows in autocommit and not autocommit
+#
+
+create table t1 (a int not null);
+lock tables t1 write;
+insert into t1 values (1),(2);
+delete from t1;
+unlock tables;
+select * from t1;
+insert into t1 values (1),(2);
+delete from t1;
+select * from t1;
+drop table t1;
+
+# Test for bug "ha_enable_transaction(on) not called by CREATE TABLE"
+# (originally from type_ranges.test)
+
+create table t1 (c int);
+insert into t1 values(1),(2);
+create table t2 select * from t1;
+--error 1060
+create table t3 select * from t1, t2; # Should give an error
+create table t3 select t1.c AS c1, t2.c AS c2,1 as "const" from t1, t2;
+drop table t1, t2, t3;
+
+# Test for bug "maria_repair() (OPTIMIZE) leaves wrong
+# data_file_length" (originally from type_datetime.test)
+
+create table t1 (t datetime) engine=maria;
+insert into t1 values (101),(691231),(700101),(991231),(10000101),(99991231),(101000000),(691231000000),(700101000000),(991231235959),(10000101000000),(99991231235959),(20030100000000),(20030000000000);
+select * from t1;
+optimize table t1;
+check table t1;
+delete from t1 where t > 0;
+optimize table t1;
+check table t1;
+drop table t1;
+
+#
+# Test auto-increment
+#
+
+SET SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
+CREATE TABLE t1 (id int(11) PRIMARY KEY auto_increment,f1 varchar(10) NOT NULL UNIQUE);
+INSERT IGNORE INTO t1 (f1) VALUES ("test1");
+INSERT IGNORE INTO t1 (f1) VALUES ("test1");
+INSERT IGNORE INTO t1 (f1) VALUES ("test2");
+SELECT * FROM t1;
+drop table t1;
+SET SQL_MODE = 'TRADITIONAL';
+
+create table t1 (n int not null primary key auto_increment, c char(1), unique(c));
+insert into t1 values(100, "a");
+insert into t1 values(300, "b");
+--error 1062
+insert into t1 values(50, "a");
+insert into t1 values(null, "c");
+select * from t1;
+--error 1062
+update t1 set n=400,c='a' where n=301;
+insert into t1 values(null, "d");
+select * from t1;
+drop table t1;
+
+create table t1 (n int not null primary key auto_increment, c char(1), unique(c)) transactional=0 row_format=dynamic;
+insert into t1 values(100, "a");
+insert into t1 values(300, "b");
+--error 1062
+insert into t1 values(50, "a");
+insert into t1 values(null, "c");
+select * from t1;
+--error 1062
+update t1 set n=400,c='a' where n=301;
+insert into t1 values(null, "d");
+select * from t1;
+drop table t1;
+
+#
+# Test warnings with transactional=1 with MyISAM
+#
+
+create table t1 (n int not null, c char(1)) engine=maria;
+alter table t1 engine=myisam;
+alter table t1 engine=maria;
+show create table t1;
+drop table t1;
+create table t1 (n int not null, c char(1)) engine=maria transactional=1;
+alter table t1 engine=myisam;
+alter table t1 engine=maria;
+show create table t1;
+drop table t1;
+create table t1 (n int not null, c char(1)) engine=myisam transactional=1;
+alter table t1 engine=maria;
+show create table t1;
+drop table t1;
+
+#
+# Some tests that have failed with transactional=0
+#
+
+# Testing buik insert
+create table t1 (a int, key(a)) transactional=0;
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t1 select NULL from t1;
+check table t1;
+drop table t1;
+
+#
+# Some tests with temporary tables
+#
+
+create temporary table t1 (a int, key(a)) transactional=1;
+create temporary table t2 (a int, key(a)) transactional=1;
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t2 select * from t1;
+insert into t1 select NULL from t2;
+select count(*) from t1;
+select count(*) from t1 where a >= 4;
+drop table t1, t2;
+
+#
+# Test problems with small rows and row_type=page
+# Bug 35048 "maria table corruption reported when transactional=0"
+#
+
+create table t1 (i int auto_increment not null primary key) transactional=0;
+
+let $i=510;
+--disable_query_log
+while ($i)
+{
+ dec $i;
+ insert into t1 values (null);
+}
+--enable_query_log
+check table t1 extended;
+delete from t1 where i = 10;
+check table t1 extended;
+drop table t1;
+
+create table t1 (i int auto_increment not null primary key);
+
+let $i=510;
+--disable_query_log
+while ($i)
+{
+ dec $i;
+ insert into t1 values (null);
+}
+--enable_query_log
+check table t1 extended;
+delete from t1 where i = 10;
+check table t1 extended;
+drop table t1;
+
+#
+# BUG#29445 - match ... against () never returns
+#
+CREATE TABLE t1(a VARCHAR(20), FULLTEXT(a)) transactional=0;
+INSERT INTO t1 VALUES('Offside'),('City Of God');
+SELECT a FROM t1 WHERE MATCH a AGAINST ('+city of*' IN BOOLEAN MODE);
+SELECT a FROM t1 WHERE MATCH a AGAINST ('+city (of)*' IN BOOLEAN MODE);
+DROP TABLE t1;
+
+#
+# BUG#36104 - INFORMATION_SCHEMA.TABLES shows TRANSACTIONAL=1 twice in
+# CREATE_OPTIONS
+#
+create table t1(a int) engine=maria transactional=1;
+select CREATE_OPTIONS from information_schema.TABLES where
+TABLE_SCHEMA='test' and TABLE_NAME='t1';
+drop table t1;
+
+#
+# BUG#39697 - Maria: hang when failing to insert due to UNIQUE
+#
+create table t1 (a int, unique(a)) engine=maria transactional=1;
+insert into t1 values(1);
+--error 1062
+insert into t1 values(2),(2);
+create table t2 (a int, unique(a)) engine=maria transactional=0 row_format=dynamic;
+insert into t2 values(1);
+--error 1062
+insert into t2 values(2),(2);
+connect (root,localhost,root,,test,$MASTER_MYPORT,$MASTER_MYSOCK);
+connection root;
+insert into t1 values(3);
+insert into t2 values(3);
+connection default;
+drop table t1, t2;
+
+# End of 5.1 tests
+
+--disable_result_log
+--disable_query_log
+eval set global storage_engine=$default_engine,
+maria_page_checksum=$default_checksum,
+maria_log_file_size=$default_log_file_size;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria_notembedded.test b/mysql-test/suite/maria/t/maria_notembedded.test
new file mode 100644
index 00000000000..0f27802de27
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria_notembedded.test
@@ -0,0 +1,99 @@
+# Tests which cannot be run in embedded server.
+
+-- source include/not_embedded.inc
+-- source include/have_maria.inc
+
+let $default_engine=`select @@session.storage_engine`;
+set session storage_engine=maria;
+
+# Verify that INSERT DELAYED is disabled only for transactional tables
+# ("embedded" server translates them to plain INSERT)
+
+create table t1 (a int) row_format=page;
+--error ER_DELAYED_NOT_SUPPORTED
+insert delayed into t1 values(1);
+drop table t1;
+create table t1 (a int) row_format=page transactional=0;
+insert delayed into t1 values(1);
+flush table t1;
+select * from t1;
+select count(*) from t1;
+drop table t1;
+create table t1 (a int) row_format=dynamic;
+insert delayed into t1 values(1);
+flush table t1;
+select * from t1;
+select count(*) from t1;
+drop table t1;
+
+# This cannot be run in embedded server, see BUG#40661, because
+# mysqltest runs "send" commands in separate OS thread.
+#
+# an example of a deadlock
+#
+create table t1 (a int unique) transactional=1;
+insert t1 values (1);
+
+lock table t1 write concurrent;
+insert t1 values (2);
+
+connect(con_a,localhost,root,,);
+lock table t1 write concurrent;
+insert t1 values (3);
+send insert t1 values (2);
+
+connect(con_b,localhost,root,,);
+lock table t1 write concurrent;
+insert t1 values (4);
+send insert t1 values (3);
+
+connect(con_c,localhost,root,,);
+lock table t1 write concurrent;
+insert t1 values (5);
+send insert t1 values (4);
+
+connect(con_d,localhost,root,,);
+lock table t1 write concurrent;
+insert t1 values (6);
+send insert t1 values (5);
+
+connection default;
+let $wait_condition=select count(*) = 4 from information_schema.processlist where state="waiting for a resource";
+--source include/wait_condition.inc
+--error ER_LOCK_DEADLOCK
+insert t1 values (6);
+unlock tables;
+
+connection con_a;
+--error ER_DUP_ENTRY
+reap;
+unlock tables;
+disconnect con_a;
+
+connection con_b;
+--error ER_DUP_ENTRY
+reap;
+unlock tables;
+disconnect con_b;
+
+connection con_c;
+--error ER_DUP_ENTRY
+reap;
+unlock tables;
+disconnect con_c;
+
+connection con_d;
+--error ER_DUP_ENTRY
+reap;
+unlock tables;
+disconnect con_d;
+
+connection default;
+check table t1;
+drop table t1;
+
+--disable_result_log
+--disable_query_log
+eval set session storage_engine=$default_engine;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria_partition.test b/mysql-test/suite/maria/t/maria_partition.test
new file mode 100644
index 00000000000..46381b6fa2c
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria_partition.test
@@ -0,0 +1,57 @@
+# Maria tests which require partitioning enabled
+
+--source include/have_partition.inc
+-- source include/have_maria.inc
+
+let $default_engine=`select @@global.storage_engine`;
+let $default_checksum=`select @@global.maria_page_checksum`;
+set global storage_engine=maria;
+set session storage_engine=maria;
+set global maria_page_checksum=0;
+
+# Initialise
+--disable_warnings
+drop table if exists t1,t2;
+drop view if exists v1;
+--enable_warnings
+SET SQL_WARNINGS=1;
+
+#
+# Bug #39227 Maria: crash with ALTER TABLE PARTITION
+#
+
+create table t1 (s1 int);
+insert into t1 values (1);
+--error ER_NO_PARTITION_FOR_GIVEN_VALUE
+alter table t1 partition by list (s1) (partition p1 values in (2));
+drop table t1;
+
+#
+# Test outer join const propagation
+#
+create table t2(a blob) engine=maria;
+create table t1(a int primary key) engine=maria;
+insert into t2 values ('foo'),('bar');
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+insert into t1 values (1);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+insert into t1 values (2);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+drop table t1,t2;
+
+create table t2(a blob);
+create table t1(a int primary key) PARTITION BY HASH (a) PARTITIONS 2;
+insert into t2 values ('foo'),('bar');
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+insert into t1 values (1);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+insert into t1 values (2);
+select * from t2 left join t1 on (t2.a=t1.a) where t2.a='bbb';
+drop table t1,t2;
+
+# Set defaults back
+--disable_result_log
+--disable_query_log
+eval set global storage_engine=$default_engine, maria_page_checksum=$default_checksum;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/suite/maria/t/maria_showlog_error.test b/mysql-test/suite/maria/t/maria_showlog_error.test
new file mode 100644
index 00000000000..9c4d5b8ef2c
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria_showlog_error.test
@@ -0,0 +1,30 @@
+-- source include/have_maria.inc
+# can't restart server in embedded
+--source include/not_embedded.inc
+# remove_file can't remove opened file under windows. So we can't reproduce
+# the problem there
+--source include/not_windows.inc
+#
+# BUG#41127 test suite
+#
+connect (admin, localhost, root,,test,,);
+--enable_reconnect
+
+connection default;
+--enable_reconnect
+
+# cleunup before this test
+-- source include/maria_empty_logs.inc
+
+connection default;
+
+let MYSQLD_DATADIR= `select @@datadir`;
+remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000001;
+--replace_regex /Size unknown ; .*maria_log.00000001/Size unknown ; maria_log.00000001/
+show engine maria logs;
+
+# cleunup after this test
+-- source include/maria_empty_logs.inc
+
+disconnect admin;
+connection default;
diff --git a/mysql-test/suite/maria/t/ps_maria.test b/mysql-test/suite/maria/t/ps_maria.test
new file mode 100644
index 00000000000..3bbc4791d5c
--- /dev/null
+++ b/mysql-test/suite/maria/t/ps_maria.test
@@ -0,0 +1,46 @@
+###############################################
+# #
+# Prepared Statements test on MARIA tables #
+# #
+###############################################
+
+#
+# NOTE: PLEASE SEE ps_1general.test (bottom)
+# BEFORE ADDING NEW TEST CASES HERE !!!
+
+-- source include/have_maria.inc
+
+use test;
+
+let $type= 'MARIA' ;
+-- source include/ps_create.inc
+-- source include/ps_renew.inc
+
+-- source include/ps_query.inc
+
+# parameter in SELECT ... MATCH/AGAINST
+# case derived from client_test.c: test_bug1500()
+--disable_warnings
+drop table if exists t2 ;
+--enable_warnings
+eval create table t2 (s varchar(25), fulltext(s)) TRANSACTIONAL= 0
+ENGINE = $type ;
+insert into t2 values ('Gravedigger'), ('Greed'),('Hollow Dogs') ;
+commit ;
+
+prepare stmt1 from ' select s from t2 where match (s) against (?) ' ;
+set @arg00='Dogs' ;
+execute stmt1 using @arg00 ;
+prepare stmt1 from ' SELECT s FROM t2
+where match (s) against (concat(?,''digger'')) ';
+set @arg00='Grave' ;
+execute stmt1 using @arg00 ;
+drop table t2 ;
+
+-- source include/ps_modify.inc
+-- source include/ps_modify1.inc
+-- source include/ps_conv.inc
+
+drop table t1, t9;
+
+# End of 4.1 tests
diff --git a/mysql-test/suite/ndb/r/ndb_auto_increment.result b/mysql-test/suite/ndb/r/ndb_auto_increment.result
index 78612b35113..9f16f1ae477 100644
--- a/mysql-test/suite/ndb/r/ndb_auto_increment.result
+++ b/mysql-test/suite/ndb/r/ndb_auto_increment.result
@@ -416,7 +416,7 @@ a
insert into t1 values (35);
insert into t1 values (NULL);
insert into t1 values (NULL);
-ERROR 23000: Duplicate entry '35' for key 'PRIMARY'
+Got one of the listed errors
select * from t1 order by a;
a
1
diff --git a/mysql-test/suite/ndb/r/ps_7ndb.result b/mysql-test/suite/ndb/r/ps_7ndb.result
index 7ebadfa3685..1799ac2a203 100644
--- a/mysql-test/suite/ndb/r/ps_7ndb.result
+++ b/mysql-test/suite/ndb/r/ps_7ndb.result
@@ -1738,7 +1738,7 @@ set @arg14= 'abc';
set @arg14= NULL ;
set @arg15= CAST('abc' as binary) ;
set @arg15= NULL ;
-create table t5 as select
+create table t5 engine = MyISAM as select
8 as const01, @arg01 as param01,
8.0 as const02, @arg02 as param02,
80.00000000000e-1 as const03, @arg03 as param03,
diff --git a/mysql-test/suite/ndb/t/ndb_auto_increment.test b/mysql-test/suite/ndb/t/ndb_auto_increment.test
index 14e7ae7ca7b..33021331e44 100644
--- a/mysql-test/suite/ndb/t/ndb_auto_increment.test
+++ b/mysql-test/suite/ndb/t/ndb_auto_increment.test
@@ -276,7 +276,7 @@ connection server1;
insert into t1 values (35);
insert into t1 values (NULL);
connection server2;
---error ER_DUP_ENTRY
+--error ER_DUP_ENTRY, ER_DUP_KEY
insert into t1 values (NULL);
select * from t1 order by a;
diff --git a/mysql-test/suite/parts/r/partition_alter2_1_maria.result b/mysql-test/suite/parts/r/partition_alter2_1_maria.result
new file mode 100644
index 00000000000..d072d18c76b
--- /dev/null
+++ b/mysql-test/suite/parts/r/partition_alter2_1_maria.result
@@ -0,0 +1,37434 @@
+SET @max_row = 20;
+SET @@session.storage_engine = 'MARIA';
+
+#------------------------------------------------------------------------
+# 0. Setting of auxiliary variables + Creation of an auxiliary tables
+# needed in many testcases
+#------------------------------------------------------------------------
+SELECT @max_row DIV 2 INTO @max_row_div2;
+SELECT @max_row DIV 3 INTO @max_row_div3;
+SELECT @max_row DIV 4 INTO @max_row_div4;
+SET @max_int_4 = 2147483647;
+DROP TABLE IF EXISTS t0_template;
+CREATE TABLE t0_template (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000) ,
+PRIMARY KEY(f_int1))
+ENGINE = MEMORY;
+# Logging of <max_row> INSERTs into t0_template suppressed
+DROP TABLE IF EXISTS t0_definition;
+CREATE TABLE t0_definition (
+state CHAR(3),
+create_command VARBINARY(5000),
+file_list VARBINARY(10000),
+PRIMARY KEY (state)
+) ENGINE = MEMORY;
+DROP TABLE IF EXISTS t0_aux;
+CREATE TABLE t0_aux ( f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000) )
+ENGINE = MEMORY;
+SET AUTOCOMMIT= 1;
+SET @@session.sql_mode= '';
+# End of basic preparations needed for all tests
+#-----------------------------------------------
+
+#========================================================================
+# 1 Increase the size of the column used in the partitioning
+# function and/or PRIMARY KEY and/or UNIQUE INDEX
+#========================================================================
+#------------------------------------------------------------------------
+# 1.1 ALTER column f_int2 not used in partitioning function
+#------------------------------------------------------------------------
+# 1.1.1 no PRIMARY KEY or UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+# 1.1.3 UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+#------------------------------------------------------------------------
+# 1.3 ALTER column f_int1 and f_int2
+# f_int1 or (f_int1 and f_int2) used in partitioning function
+#------------------------------------------------------------------------
+# 1.3.1 no PRIMARY KEY or UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY HASH(f_int1 + f_int2) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1 + f_int2)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY KEY(f_int1,f_int2) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1,f_int2)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE ((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY HASH(f_int2) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY HASH (f_int2)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int2) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+ PARTITION part2 VALUES IN (1),
+ PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int2)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+# 1.3.3 UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY HASH(f_int1 + f_int2) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1 + f_int2)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY KEY(f_int1,f_int2) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1,f_int2)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE ((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY HASH(f_int2) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY HASH (f_int2)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int2) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+ PARTITION part2 VALUES IN (1),
+ PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int2)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY HASH(f_int1 + f_int2) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1 + f_int2)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY KEY(f_int1,f_int2) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1,f_int2)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE ((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY HASH(f_int2) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY HASH (f_int2)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int2) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+ PARTITION part2 VALUES IN (1),
+ PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 BIGINT, MODIFY f_int2 BIGINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` bigint(20) DEFAULT NULL,
+ `f_int2` bigint(20) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int2)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP VIEW IF EXISTS v1;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t0_aux;
+DROP TABLE IF EXISTS t0_definition;
+DROP TABLE IF EXISTS t0_template;
diff --git a/mysql-test/suite/parts/r/partition_alter2_2_maria.result b/mysql-test/suite/parts/r/partition_alter2_2_maria.result
new file mode 100644
index 00000000000..f3173ac5ee2
--- /dev/null
+++ b/mysql-test/suite/parts/r/partition_alter2_2_maria.result
@@ -0,0 +1,37643 @@
+SET @max_row = 20;
+SET @@session.storage_engine = 'MARIA';
+
+#------------------------------------------------------------------------
+# 0. Setting of auxiliary variables + Creation of an auxiliary tables
+# needed in many testcases
+#------------------------------------------------------------------------
+SELECT @max_row DIV 2 INTO @max_row_div2;
+SELECT @max_row DIV 3 INTO @max_row_div3;
+SELECT @max_row DIV 4 INTO @max_row_div4;
+SET @max_int_4 = 2147483647;
+DROP TABLE IF EXISTS t0_template;
+CREATE TABLE t0_template (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000) ,
+PRIMARY KEY(f_int1))
+ENGINE = MEMORY;
+# Logging of <max_row> INSERTs into t0_template suppressed
+DROP TABLE IF EXISTS t0_definition;
+CREATE TABLE t0_definition (
+state CHAR(3),
+create_command VARBINARY(5000),
+file_list VARBINARY(10000),
+PRIMARY KEY (state)
+) ENGINE = MEMORY;
+DROP TABLE IF EXISTS t0_aux;
+CREATE TABLE t0_aux ( f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000) )
+ENGINE = MEMORY;
+SET AUTOCOMMIT= 1;
+SET @@session.sql_mode= '';
+# End of basic preparations needed for all tests
+#-----------------------------------------------
+
+#========================================================================
+# 2 Decrease the size of the column used in the partitioning
+# function and/or PRIMARY KEY and/or UNIQUE INDEX
+#========================================================================
+#------------------------------------------------------------------------
+# 2.1 ALTER column f_int2 not used in partitioning function
+#------------------------------------------------------------------------
+# 2.1.1 no PRIMARY KEY or UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+# 2.1.3 UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+ERROR HY000: Table has no partition for value 2147483647
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx1 (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` int(11) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx1` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+#------------------------------------------------------------------------
+# 2.3 ALTER column f_int1 and f_int2 used in partitioning function
+#------------------------------------------------------------------------
+# 2.3.1 no PRIMARY KEY or UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY HASH(f_int1 + f_int2) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1 + f_int2)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY KEY(f_int1,f_int2) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1,f_int2)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE ((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY HASH(f_int2) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY HASH (f_int2)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int2) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+ PARTITION part2 VALUES IN (1),
+ PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int2)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+# check prerequisites-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# INFO: Neither f_int1 nor f_int2 nor (f_int1,f_int2) is UNIQUE
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+# 2.3.3 UNIQUE INDEX exists
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY HASH(f_int1 + f_int2) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1 + f_int2)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY KEY(f_int1,f_int2) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1,f_int2)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE ((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY HASH(f_int2) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY HASH (f_int2)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int1,f_int2)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int2) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+ PARTITION part2 VALUES IN (1),
+ PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int1`,`f_int2`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int2)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY HASH(f_int1) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY KEY(f_int1) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1 DIV 2) SUBPARTITION BY HASH(f_int1) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1 DIV 2)
+SUBPARTITION BY HASH (f_int1)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int1)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int1 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int1) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+PARTITION part2 VALUES IN (1),
+PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int1)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY HASH(f_int1 + f_int2) PARTITIONS 2;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (f_int1 + f_int2)
+PARTITIONS 2 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY KEY(f_int1,f_int2) PARTITIONS 5;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY KEY (f_int1,f_int2)
+PARTITIONS 5 */
+
+unified filelist
+t1#P#p0.MAD
+t1#P#p0.MAI
+t1#P#p1.MAD
+t1#P#p1.MAI
+t1#P#p2.MAD
+t1#P#p2.MAI
+t1#P#p3.MAD
+t1#P#p3.MAI
+t1#P#p4.MAD
+t1#P#p4.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3),
+PARTITION part_2 VALUES IN (-2),
+PARTITION part_1 VALUES IN (-1),
+PARTITION part_N VALUES IN (NULL),
+PARTITION part0 VALUES IN (0),
+PARTITION part1 VALUES IN (1),
+PARTITION part2 VALUES IN (2),
+PARTITION part3 VALUES IN (3));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (MOD(f_int1 + f_int2,4))
+(PARTITION part_3 VALUES IN (-3) ENGINE = MARIA,
+ PARTITION part_2 VALUES IN (-2) ENGINE = MARIA,
+ PARTITION part_1 VALUES IN (-1) ENGINE = MARIA,
+ PARTITION part_N VALUES IN (NULL) ENGINE = MARIA,
+ PARTITION part0 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part1 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (2) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (3) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part0.MAD
+t1#P#part0.MAI
+t1#P#part1.MAD
+t1#P#part1.MAI
+t1#P#part2.MAD
+t1#P#part2.MAI
+t1#P#part3.MAD
+t1#P#part3.MAI
+t1#P#part_1.MAD
+t1#P#part_1.MAI
+t1#P#part_2.MAD
+t1#P#part_2.MAI
+t1#P#part_3.MAD
+t1#P#part_3.MAI
+t1#P#part_N.MAD
+t1#P#part_N.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (10 + 5),
+PARTITION parte VALUES LESS THAN (20),
+PARTITION partf VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE ((f_int1 + f_int2) DIV 2)
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (15) ENGINE = MARIA,
+ PARTITION parte VALUES LESS THAN (20) ENGINE = MARIA,
+ PARTITION partf VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta.MAD
+t1#P#parta.MAI
+t1#P#partb.MAD
+t1#P#partb.MAI
+t1#P#partc.MAD
+t1#P#partc.MAI
+t1#P#partd.MAD
+t1#P#partd.MAI
+t1#P#parte.MAD
+t1#P#parte.MAI
+t1#P#partf.MAD
+t1#P#partf.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY HASH(f_int2) SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0),
+PARTITION partb VALUES LESS THAN (5),
+PARTITION partc VALUES LESS THAN (10),
+PARTITION partd VALUES LESS THAN (2147483646));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY HASH (f_int2)
+SUBPARTITIONS 2
+(PARTITION parta VALUES LESS THAN (0) ENGINE = MARIA,
+ PARTITION partb VALUES LESS THAN (5) ENGINE = MARIA,
+ PARTITION partc VALUES LESS THAN (10) ENGINE = MARIA,
+ PARTITION partd VALUES LESS THAN (2147483646) ENGINE = MARIA) */
+
+unified filelist
+t1#P#parta#SP#partasp0.MAD
+t1#P#parta#SP#partasp0.MAI
+t1#P#parta#SP#partasp1.MAD
+t1#P#parta#SP#partasp1.MAI
+t1#P#partb#SP#partbsp0.MAD
+t1#P#partb#SP#partbsp0.MAI
+t1#P#partb#SP#partbsp1.MAD
+t1#P#partb#SP#partbsp1.MAI
+t1#P#partc#SP#partcsp0.MAD
+t1#P#partc#SP#partcsp0.MAI
+t1#P#partc#SP#partcsp1.MAD
+t1#P#partc#SP#partcsp1.MAI
+t1#P#partd#SP#partdsp0.MAD
+t1#P#partd#SP#partdsp0.MAI
+t1#P#partd#SP#partdsp1.MAD
+t1#P#partd#SP#partdsp1.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY RANGE(f_int1) SUBPARTITION BY KEY(f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+(SUBPARTITION subpart11, SUBPARTITION subpart12),
+PARTITION part2 VALUES LESS THAN (5)
+(SUBPARTITION subpart21, SUBPARTITION subpart22),
+PARTITION part3 VALUES LESS THAN (10)
+(SUBPARTITION subpart31, SUBPARTITION subpart32),
+PARTITION part4 VALUES LESS THAN (2147483646)
+(SUBPARTITION subpart41, SUBPARTITION subpart42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (f_int1)
+SUBPARTITION BY KEY (f_int2)
+(PARTITION part1 VALUES LESS THAN (0)
+ (SUBPARTITION subpart11 ENGINE = MARIA,
+ SUBPARTITION subpart12 ENGINE = MARIA),
+ PARTITION part2 VALUES LESS THAN (5)
+ (SUBPARTITION subpart21 ENGINE = MARIA,
+ SUBPARTITION subpart22 ENGINE = MARIA),
+ PARTITION part3 VALUES LESS THAN (10)
+ (SUBPARTITION subpart31 ENGINE = MARIA,
+ SUBPARTITION subpart32 ENGINE = MARIA),
+ PARTITION part4 VALUES LESS THAN (2147483646)
+ (SUBPARTITION subpart41 ENGINE = MARIA,
+ SUBPARTITION subpart42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#subpart11.MAD
+t1#P#part1#SP#subpart11.MAI
+t1#P#part1#SP#subpart12.MAD
+t1#P#part1#SP#subpart12.MAI
+t1#P#part2#SP#subpart21.MAD
+t1#P#part2#SP#subpart21.MAI
+t1#P#part2#SP#subpart22.MAD
+t1#P#part2#SP#subpart22.MAI
+t1#P#part3#SP#subpart31.MAD
+t1#P#part3#SP#subpart31.MAI
+t1#P#part3#SP#subpart32.MAD
+t1#P#part3#SP#subpart32.MAI
+t1#P#part4#SP#subpart41.MAD
+t1#P#part4#SP#subpart41.MAI
+t1#P#part4#SP#subpart42.MAD
+t1#P#part4#SP#subpart42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,3))) SUBPARTITION BY HASH(f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+(SUBPARTITION sp11, SUBPARTITION sp12),
+PARTITION part2 VALUES IN (1)
+(SUBPARTITION sp21, SUBPARTITION sp22),
+PARTITION part3 VALUES IN (2)
+(SUBPARTITION sp31, SUBPARTITION sp32),
+PARTITION part4 VALUES IN (NULL)
+(SUBPARTITION sp41, SUBPARTITION sp42));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,3)))
+SUBPARTITION BY HASH (f_int2 + 1)
+(PARTITION part1 VALUES IN (0)
+ (SUBPARTITION sp11 ENGINE = MARIA,
+ SUBPARTITION sp12 ENGINE = MARIA),
+ PARTITION part2 VALUES IN (1)
+ (SUBPARTITION sp21 ENGINE = MARIA,
+ SUBPARTITION sp22 ENGINE = MARIA),
+ PARTITION part3 VALUES IN (2)
+ (SUBPARTITION sp31 ENGINE = MARIA,
+ SUBPARTITION sp32 ENGINE = MARIA),
+ PARTITION part4 VALUES IN (NULL)
+ (SUBPARTITION sp41 ENGINE = MARIA,
+ SUBPARTITION sp42 ENGINE = MARIA)) */
+
+unified filelist
+t1#P#part1#SP#sp11.MAD
+t1#P#part1#SP#sp11.MAI
+t1#P#part1#SP#sp12.MAD
+t1#P#part1#SP#sp12.MAI
+t1#P#part2#SP#sp21.MAD
+t1#P#part2#SP#sp21.MAI
+t1#P#part2#SP#sp22.MAD
+t1#P#part2#SP#sp22.MAI
+t1#P#part3#SP#sp31.MAD
+t1#P#part3#SP#sp31.MAI
+t1#P#part3#SP#sp32.MAD
+t1#P#part3#SP#sp32.MAI
+t1#P#part4#SP#sp41.MAD
+t1#P#part4#SP#sp41.MAI
+t1#P#part4#SP#sp42.MAD
+t1#P#part4#SP#sp42.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+CREATE TABLE t1 (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000)
+, UNIQUE INDEX uidx (f_int2,f_int1)
+)
+PARTITION BY LIST(ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY(f_int2) SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0),
+ PARTITION part2 VALUES IN (1),
+ PARTITION part3 VALUES IN (NULL));
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN 1 AND @max_row_div2 - 1;
+ALTER TABLE t1 MODIFY f_int1 MEDIUMINT, MODIFY f_int2 MEDIUMINT;
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,f_charbig FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row;
+# Start usability test (inc/partition_check.inc)
+create_command
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_int1` mediumint(9) DEFAULT NULL,
+ `f_int2` mediumint(9) DEFAULT NULL,
+ `f_char1` char(20) DEFAULT NULL,
+ `f_char2` char(20) DEFAULT NULL,
+ `f_charbig` varchar(1000) DEFAULT NULL,
+ UNIQUE KEY `uidx` (`f_int2`,`f_int1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (ABS(MOD(f_int1,2)))
+SUBPARTITION BY KEY (f_int2)
+SUBPARTITIONS 3
+(PARTITION part1 VALUES IN (0) ENGINE = MARIA,
+ PARTITION part2 VALUES IN (1) ENGINE = MARIA,
+ PARTITION part3 VALUES IN (NULL) ENGINE = MARIA) */
+
+unified filelist
+t1#P#part1#SP#part1sp0.MAD
+t1#P#part1#SP#part1sp0.MAI
+t1#P#part1#SP#part1sp1.MAD
+t1#P#part1#SP#part1sp1.MAI
+t1#P#part1#SP#part1sp2.MAD
+t1#P#part1#SP#part1sp2.MAI
+t1#P#part2#SP#part2sp0.MAD
+t1#P#part2#SP#part2sp0.MAI
+t1#P#part2#SP#part2sp1.MAD
+t1#P#part2#SP#part2sp1.MAI
+t1#P#part2#SP#part2sp2.MAD
+t1#P#part2#SP#part2sp2.MAI
+t1#P#part3#SP#part3sp0.MAD
+t1#P#part3#SP#part3sp0.MAI
+t1#P#part3#SP#part3sp1.MAD
+t1#P#part3#SP#part3sp1.MAI
+t1#P#part3#SP#part3sp2.MAD
+t1#P#part3#SP#part3sp2.MAI
+t1.frm
+t1.par
+
+# check prerequisites-1 success: 1
+# check COUNT(*) success: 1
+# check MIN/MAX(f_int1) success: 1
+# check MIN/MAX(f_int2) success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+ERROR 23000: Can't write; duplicate key in table 't1'
+# check prerequisites-3 success: 1
+# INFO: f_int1 AND/OR f_int2 AND/OR (f_int1,f_int2) is UNIQUE
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, 2 * @max_row + f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT 2 * @max_row + f_int1, f_int1, CAST((2 * @max_row + f_int1) AS CHAR),
+CAST((2 * @max_row + f_int1) AS CHAR), 'delete me' FROM t0_template
+WHERE f_int1 IN (2,3);
+DELETE FROM t1 WHERE f_charbig = 'delete me';
+# check read via f_int1 success: 1
+# check read via f_int2 success: 1
+
+# check multiple-1 success: 1
+DELETE FROM t1 WHERE MOD(f_int1,3) = 0;
+
+# check multiple-2 success: 1
+INSERT INTO t1 SELECT * FROM t0_template
+WHERE MOD(f_int1,3) = 0;
+
+# check multiple-3 success: 1
+UPDATE t1 SET f_int1 = f_int1 + @max_row
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4
+AND @max_row_div2 + @max_row_div4;
+
+# check multiple-4 success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - @max_row_div4 + @max_row
+AND @max_row_div2 + @max_row_div4 + @max_row;
+
+# check multiple-5 success: 1
+SELECT COUNT(*) INTO @try_count FROM t0_template
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT COUNT(*) INTO @clash_count
+FROM t1 INNER JOIN t0_template USING(f_int1)
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+SELECT MIN(f_int1) - 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-1 success: 1
+SELECT MAX(f_int1) + 1 INTO @cur_value FROM t1;
+INSERT INTO t1
+SET f_int1 = @cur_value , f_int2 = @cur_value,
+f_char1 = CAST(@cur_value AS CHAR), f_char2 = CAST(@cur_value AS CHAR),
+f_charbig = '#SINGLE#';
+
+# check single-2 success: 1
+SELECT MIN(f_int1) INTO @cur_value1 FROM t1;
+SELECT MAX(f_int1) + 1 INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value2
+WHERE f_int1 = @cur_value1 AND f_charbig = '#SINGLE#';
+
+# check single-3 success: 1
+SET @cur_value1= -1;
+SELECT MAX(f_int1) INTO @cur_value2 FROM t1;
+UPDATE t1 SET f_int1 = @cur_value1
+WHERE f_int1 = @cur_value2 AND f_charbig = '#SINGLE#';
+
+# check single-4 success: 1
+SELECT MAX(f_int1) INTO @cur_value FROM t1;
+DELETE FROM t1 WHERE f_int1 = @cur_value AND f_charbig = '#SINGLE#';
+
+# check single-5 success: 1
+DELETE FROM t1 WHERE f_int1 = -1 AND f_charbig = '#SINGLE#';
+
+# check single-6 success: 1
+INSERT INTO t1 SET f_int1 = @max_int_4 , f_int2 = @max_int_4, f_charbig = '#2147483647##';
+Warnings:
+Warning 1264 Out of range value for column 'f_int1' at row 1
+Warning 1264 Out of range value for column 'f_int2' at row 1
+
+# check single-7 success: 1
+DELETE FROM t1 WHERE f_charbig = '#2147483647##';
+DELETE FROM t1 WHERE f_int1 IS NULL OR f_int1 = 0;
+INSERT t1 SET f_int1 = 0 , f_int2 = 0,
+f_char1 = CAST(0 AS CHAR), f_char2 = CAST(0 AS CHAR),
+f_charbig = '#NULL#';
+INSERT INTO t1
+SET f_int1 = NULL , f_int2 = -@max_row,
+f_char1 = CAST(-@max_row AS CHAR), f_char2 = CAST(-@max_row AS CHAR),
+f_charbig = '#NULL#';
+# check null success: 1
+
+# check null-1 success: 1
+UPDATE t1 SET f_int1 = -@max_row
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-2 success: 1
+UPDATE t1 SET f_int1 = NULL
+WHERE f_int1 = -@max_row AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-3 success: 1
+DELETE FROM t1
+WHERE f_int1 IS NULL AND f_int2 = -@max_row AND f_char1 = CAST(-@max_row AS CHAR)
+AND f_char2 = CAST(-@max_row AS CHAR) AND f_charbig = '#NULL#';
+
+# check null-4 success: 1
+DELETE FROM t1
+WHERE f_int1 = 0 AND f_int2 = 0
+AND f_char1 = CAST(0 AS CHAR) AND f_char2 = CAST(0 AS CHAR)
+AND f_charbig = '#NULL#';
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0
+AND f_int1 BETWEEN @max_row_div2 AND @max_row
+ON DUPLICATE KEY
+UPDATE f_int1 = 2 * @max_row + source_tab.f_int1,
+f_int2 = 2 * @max_row + source_tab.f_int1,
+f_charbig = 'was updated';
+
+# check unique-1-a success: 1
+
+# check unique-1-b success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===')
+WHERE f_charbig = 'was updated';
+REPLACE INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, - f_int1, '', '', 'was inserted or replaced'
+ FROM t0_template source_tab
+WHERE MOD(f_int1,3) = 0 AND f_int1 BETWEEN @max_row_div2 AND @max_row;
+
+# check replace success: 1
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 AND @max_row_div2 + @max_row_div4;
+DELETE FROM t1
+WHERE f_int1 = f_int2 AND MOD(f_int1,3) = 0 AND
+f_int1 BETWEEN @max_row_div2 + @max_row_div4 AND @max_row;
+UPDATE t1 SET f_int2 = f_int1,
+f_char1 = CAST(f_int1 AS CHAR),
+f_char2 = CAST(f_int1 AS CHAR),
+f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===')
+WHERE f_charbig = 'was inserted or replaced' AND f_int1 = - f_int2;
+SET AUTOCOMMIT= 0;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-1 success: 1
+COMMIT WORK;
+
+# check transactions-2 success: 1
+ROLLBACK WORK;
+
+# check transactions-3 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+ROLLBACK WORK;
+
+# check transactions-4 success: 1
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, '', '', 'was inserted'
+FROM t0_template source_tab
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+
+# check transactions-5 success: 1
+ROLLBACK WORK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+
+# check transactions-6 success: 1
+# INFO: Storage engine used for t1 seems to be not transactional.
+COMMIT;
+
+# check transactions-7 success: 1
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+SET @@session.sql_mode = 'traditional';
+SELECT @max_row_div2 + @max_row_div4 - @max_row_div4 + 1 INTO @exp_inserted_rows;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT IF(f_int1 = @max_row_div2,f_int1 / 0,f_int1),f_int1,
+'', '', 'was inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div4 AND @max_row_div2 + @max_row_div4;
+ERROR 22012: Division by 0
+COMMIT;
+
+# check transactions-8 success: 1
+# INFO: Storage engine used for t1 seems to be unable to revert
+# changes made by the failing statement.
+SET @@session.sql_mode = '';
+SET AUTOCOMMIT= 1;
+DELETE FROM t1 WHERE f_charbig = 'was inserted';
+COMMIT WORK;
+UPDATE t1 SET f_charbig = REPEAT('b', 1000);
+
+# check special-1 success: 1
+UPDATE t1 SET f_charbig = '';
+
+# check special-2 success: 1
+UPDATE t1 SET f_charbig = CONCAT('===',CAST(f_int1 AS CHAR),'===');
+INSERT INTO t1(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-1 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER INSERT ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT f_int1,f_int2,f_char1,f_char2,NULL FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+
+# check trigger-2 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-3 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-4 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = new.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-5 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER UPDATE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+UPDATE t0_aux SET f_int1 = - f_int1, f_int2 = - f_int2
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-6 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 BEFORE DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-7 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+INSERT INTO t0_aux(f_int1,f_int2,f_char1,f_char2,f_charbig)
+SELECT -f_int1,-f_int1,CAST(-f_int1 AS CHAR),CAST(-f_int1 AS CHAR),
+'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_1 AFTER DELETE ON t0_aux FOR EACH ROW
+BEGIN
+UPDATE t1 SET f_int1 = -f_int1, f_int2 = -f_int2,
+f_charbig = 'updated by trigger'
+ WHERE f_int1 = - old.f_int1;
+END|
+DELETE FROM t0_aux
+WHERE f_int1 IN (- (@max_row_div2 - 1),- @max_row_div2,- (@max_row_div2 + 1));
+
+# check trigger-8 success: 1
+DROP TRIGGER trg_1;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = 'just inserted'
+ WHERE f_int1 <> CAST(f_char1 AS SIGNED INT);
+DELETE FROM t0_aux
+WHERE ABS(f_int1) BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+DELETE FROM t1
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1;
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = old.f_int1 + @max_row,
+new.f_int2 = old.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-9 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_2 BEFORE UPDATE ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = new.f_int1 + @max_row,
+new.f_int2 = new.f_int2 - @max_row,
+new.f_charbig = '####updated per update trigger####';
+END|
+UPDATE t1
+SET f_int1 = f_int1 + @max_row, f_int2 = f_int2 - @max_row,
+f_charbig = '####updated per update statement itself####';
+
+# check trigger-10 success: 1
+DROP TRIGGER trg_2;
+UPDATE t1 SET f_int1 = CAST(f_char1 AS SIGNED INT),
+f_int2 = CAST(f_char1 AS SIGNED INT),
+f_charbig = CONCAT('===',f_char1,'===');
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_int1, f_int2, f_char1, f_char2, f_charbig)
+SELECT f_int1, f_int1, CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-11 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+CREATE TRIGGER trg_3 BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+SET new.f_int1 = @my_max1 + @counter,
+new.f_int2 = @my_min2 - @counter,
+new.f_charbig = '####updated per insert trigger####';
+SET @counter = @counter + 1;
+END|
+SET @counter = 1;
+SELECT MAX(f_int1), MIN(f_int2) INTO @my_max1,@my_min2 FROM t1;
+INSERT INTO t1 (f_char1, f_char2, f_charbig)
+SELECT CAST(f_int1 AS CHAR),
+CAST(f_int1 AS CHAR), 'just inserted' FROM t0_template
+WHERE f_int1 BETWEEN @max_row_div2 - 1 AND @max_row_div2 + 1
+ORDER BY f_int1;
+DROP TRIGGER trg_3;
+
+# check trigger-12 success: 1
+DELETE FROM t1
+WHERE f_int1 <> CAST(f_char1 AS SIGNED INT)
+AND f_int2 <> CAST(f_char1 AS SIGNED INT)
+AND f_charbig = '####updated per insert trigger####';
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+CHECKSUM TABLE t1 EXTENDED;
+Table Checksum
+test.t1 <some_value>
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+# check layout success: 1
+REPAIR TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+# check layout success: 1
+TRUNCATE t1;
+
+# check TRUNCATE success: 1
+# check layout success: 1
+# End usability test (inc/partition_check.inc)
+DROP TABLE t1;
+DROP VIEW IF EXISTS v1;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t0_aux;
+DROP TABLE IF EXISTS t0_definition;
+DROP TABLE IF EXISTS t0_template;
diff --git a/mysql-test/suite/parts/r/partition_auto_increment_maria.result b/mysql-test/suite/parts/r/partition_auto_increment_maria.result
new file mode 100644
index 00000000000..c8ff7a11bfa
--- /dev/null
+++ b/mysql-test/suite/parts/r/partition_auto_increment_maria.result
@@ -0,0 +1,868 @@
+DROP TABLE IF EXISTS t1;
+# test without partitioning for reference
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1))
+ENGINE='MARIA';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+1
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (NULL);
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+6
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+6
+INSERT INTO t1 VALUES (0);
+INSERT INTO t1 VALUES (5), (16);
+INSERT INTO t1 VALUES (17);
+INSERT INTO t1 VALUES (19), (NULL);
+INSERT INTO t1 VALUES (NULL), (10), (NULL);
+INSERT INTO t1 VALUES (NULL);
+SET INSERT_ID = 30;
+INSERT INTO t1 VALUES (NULL);
+UPDATE t1 SET c1 = 50 WHERE c1 = 17;
+UPDATE t1 SET c1 = 51 WHERE c1 = 19;
+FLUSH TABLES;
+UPDATE t1 SET c1 = 40 WHERE c1 = 50;
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+ AND TABLE_NAME='t1';
+AUTO_INCREMENT
+52
+UPDATE t1 SET c1 = NULL WHERE c1 = 4;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+6
+10
+20
+21
+22
+23
+30
+40
+51
+52
+53
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1))
+ENGINE='MARIA';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+FLUSH TABLE;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+INSERT INTO t1 VALUES (4);
+FLUSH TABLE;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+INSERT INTO t1 VALUES (NULL);
+FLUSH TABLE;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+DELETE FROM t1;
+INSERT INTO t1 VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+SELECT * FROM t1 ORDER BY c1;
+c1
+6
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+SELECT * FROM t1 ORDER BY c1;
+c1
+1
+INSERT INTO t1 VALUES (100);
+INSERT INTO t1 VALUES (NULL);
+DELETE FROM t1 WHERE c1 >= 100;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=102 DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1
+DROP TABLE t1;
+# Simple test with NULL
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1))
+ENGINE='MARIA'
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+INSERT INTO t1 VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1;
+c1
+1
+DROP TABLE t1;
+# Test with sql_mode and first insert as 0
+CREATE TABLE t1 (
+c1 INT,
+c2 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c2))
+ENGINE='MARIA'
+PARTITION BY HASH(c2)
+PARTITIONS 2;
+INSERT INTO t1 VALUES (1, NULL);
+INSERT INTO t1 VALUES (1, 1), (99, 99);
+INSERT INTO t1 VALUES (1, NULL);
+SET @@session.sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
+INSERT INTO t1 VALUES (1, 0);
+SELECT * FROM t1 ORDER BY c1, c2;
+c1 c2
+1 0
+1 1
+1 2
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 INT,
+c2 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c2))
+ENGINE='MARIA'
+PARTITION BY HASH(c2)
+PARTITIONS 2;
+INSERT INTO t1 VALUES (1, 0);
+INSERT INTO t1 VALUES (1, 1), (1, NULL);
+INSERT INTO t1 VALUES (2, NULL), (4, 7);
+INSERT INTO t1 VALUES (1, NULL);
+SELECT * FROM t1 ORDER BY c1, c2;
+c1 c2
+1 0
+1 1
+1 2
+1 8
+2 3
+4 7
+SET @@session.sql_mode = '';
+DROP TABLE t1;
+# Simple test with NULL, 0 and explicit values both incr. and desc.
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1))
+ENGINE='MARIA'
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+INSERT INTO t1 VALUES (2), (4), (NULL);
+INSERT INTO t1 VALUES (0);
+INSERT INTO t1 VALUES (5), (16);
+INSERT INTO t1 VALUES (17), (19), (NULL);
+INSERT INTO t1 VALUES (NULL), (10), (NULL);
+INSERT INTO t1 VALUES (NULL), (9);
+INSERT INTO t1 VALUES (59), (55);
+INSERT INTO t1 VALUES (NULL), (90);
+INSERT INTO t1 VALUES (NULL);
+UPDATE t1 SET c1 = 150 WHERE c1 = 17;
+UPDATE t1 SET c1 = 151 WHERE c1 = 19;
+FLUSH TABLES;
+UPDATE t1 SET c1 = 140 WHERE c1 = 150;
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+ AND TABLE_NAME='t1';
+AUTO_INCREMENT
+152
+UPDATE t1 SET c1 = NULL WHERE c1 = 4;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+6
+9
+10
+20
+21
+22
+23
+55
+59
+60
+90
+91
+140
+151
+152
+153
+DROP TABLE t1;
+# Test with auto_increment_increment and auto_increment_offset.
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1))
+ENGINE='MARIA'
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+SET @@session.auto_increment_increment = 10;
+SET @@session.auto_increment_offset = 5;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (NULL), (NULL), (NULL);
+SET @@session.auto_increment_increment = 5;
+SET @@session.auto_increment_offset = 3;
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (33 + 1);
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (38 + 2);
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (43 + 3);
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (48 + 4);
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (53 + 5);
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (63 + 6);
+INSERT INTO t1 VALUES (NULL);
+SET @@session.auto_increment_increment = 1;
+SET @@session.auto_increment_offset = 1;
+SELECT * FROM t1 ORDER BY c1;
+c1
+1
+5
+15
+25
+33
+34
+38
+40
+43
+46
+48
+52
+53
+58
+63
+69
+73
+DROP TABLE t1;
+# Test reported auto_increment value
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1))
+ENGINE='MARIA'
+PARTITION BY HASH (c1)
+PARTITIONS 2;
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+1
+INSERT INTO t1 VALUES (2);
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+3
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (NULL);
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+6
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (17);
+INSERT INTO t1 VALUES (19);
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (NULL);
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+22
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+22
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+6
+10
+17
+19
+20
+21
+INSERT INTO t1 VALUES (NULL);
+SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='test'
+AND TABLE_NAME='t1';
+AUTO_INCREMENT
+23
+INSERT INTO t1 VALUES (NULL);
+INSERT INTO t1 VALUES (15);
+INSERT INTO t1 VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+6
+10
+15
+17
+19
+20
+21
+22
+23
+24
+INSERT INTO t1 VALUES (NULL);
+DELETE FROM t1;
+INSERT INTO t1 VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=27 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1 ORDER BY c1;
+c1
+26
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=28 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1 ORDER BY c1;
+c1
+27
+INSERT INTO t1 VALUES (100);
+INSERT INTO t1 VALUES (NULL);
+DELETE FROM t1 WHERE c1 >= 100;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=102 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+DROP TABLE t1;
+# Test with two threads
+# con default
+CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
+ENGINE = 'MARIA'
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+INSERT INTO t1 (c1) VALUES (2);
+INSERT INTO t1 (c1) VALUES (4);
+# con1
+INSERT INTO t1 (c1) VALUES (NULL);
+INSERT INTO t1 (c1) VALUES (10);
+# con default
+INSERT INTO t1 (c1) VALUES (NULL);
+INSERT INTO t1 (c1) VALUES (NULL);
+INSERT INTO t1 (c1) VALUES (19);
+INSERT INTO t1 (c1) VALUES (21);
+# con1
+INSERT INTO t1 (c1) VALUES (NULL);
+# con default
+INSERT INTO t1 (c1) VALUES (16);
+# con1
+INSERT INTO t1 (c1) VALUES (NULL);
+# con default
+INSERT INTO t1 (c1) VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+24
+DROP TABLE t1;
+# Test with two threads + start transaction NO PARTITIONING
+# con default
+CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
+ENGINE = 'MARIA';
+START TRANSACTION;
+INSERT INTO t1 (c1) VALUES (2);
+INSERT INTO t1 (c1) VALUES (4);
+# con1
+START TRANSACTION;
+INSERT INTO t1 (c1) VALUES (NULL);
+INSERT INTO t1 (c1) VALUES (10);
+# con default
+INSERT INTO t1 (c1) VALUES (NULL);
+INSERT INTO t1 (c1) VALUES (NULL);
+INSERT INTO t1 (c1) VALUES (19);
+INSERT INTO t1 (c1) VALUES (21);
+# con1
+INSERT INTO t1 (c1) VALUES (NULL);
+# con default
+INSERT INTO t1 (c1) VALUES (16);
+# con1
+INSERT INTO t1 (c1) VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+COMMIT;
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+# con default
+INSERT INTO t1 (c1) VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+24
+COMMIT;
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+24
+DROP TABLE t1;
+# Test with two threads + start transaction
+# con default
+CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
+ENGINE = 'MARIA'
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+START TRANSACTION;
+INSERT INTO t1 (c1) VALUES (2);
+INSERT INTO t1 (c1) VALUES (4);
+# con1
+START TRANSACTION;
+INSERT INTO t1 (c1) VALUES (NULL), (10);
+# con default
+INSERT INTO t1 (c1) VALUES (NULL), (NULL), (19);
+INSERT INTO t1 (c1) VALUES (21);
+# con1
+INSERT INTO t1 (c1) VALUES (NULL);
+# con default
+INSERT INTO t1 (c1) VALUES (16);
+# con1
+INSERT INTO t1 (c1) VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+COMMIT;
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+# con default
+INSERT INTO t1 (c1) VALUES (NULL);
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+24
+COMMIT;
+SELECT * FROM t1 ORDER BY c1;
+c1
+2
+4
+5
+10
+11
+12
+16
+19
+21
+22
+23
+24
+DROP TABLE t1;
+# Test with another column after
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+c2 INT,
+PRIMARY KEY (c1,c2))
+ENGINE = 'MARIA'
+PARTITION BY HASH(c2)
+PARTITIONS 2;
+INSERT INTO t1 VALUES (1, 0);
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (NULL, 1), (NULL, 2), (NULL, 3);
+INSERT INTO t1 VALUES (NULL, 3);
+INSERT INTO t1 VALUES (2, 0), (NULL, 2);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (2, 22);
+INSERT INTO t1 VALUES (NULL, 2);
+SELECT * FROM t1 ORDER BY c1,c2;
+c1 c2
+1 0
+1 1
+2 0
+2 1
+2 2
+2 22
+3 2
+4 3
+5 3
+6 2
+7 2
+DROP TABLE t1;
+# Test with another column before
+CREATE TABLE t1 (
+c1 INT,
+c2 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c2))
+ENGINE = 'MARIA'
+PARTITION BY HASH(c2)
+PARTITIONS 2;
+INSERT INTO t1 VALUES (1, 0);
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (1, NULL);
+INSERT INTO t1 VALUES (2, NULL), (3, 11), (3, NULL), (2, 0);
+INSERT INTO t1 VALUES (2, NULL);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (2, 22);
+INSERT INTO t1 VALUES (2, NULL);
+SELECT * FROM t1 ORDER BY c1,c2;
+c1 c2
+1 1
+1 2
+2 3
+2 13
+2 14
+2 22
+2 23
+3 11
+3 12
+DROP TABLE t1;
+# Test with auto_increment on secondary column in multi-column-index
+CREATE TABLE t1 (
+c1 INT,
+c2 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1,c2))
+ENGINE = 'MARIA'
+PARTITION BY HASH(c2)
+PARTITIONS 2;
+INSERT INTO t1 VALUES (1, 0);
+INSERT INTO t1 VALUES (1, 1);
+INSERT INTO t1 VALUES (1, NULL);
+INSERT INTO t1 VALUES (2, NULL);
+INSERT INTO t1 VALUES (3, NULL);
+INSERT INTO t1 VALUES (3, NULL), (2, 0), (2, NULL);
+INSERT INTO t1 VALUES (2, 2);
+INSERT INTO t1 VALUES (2, 22), (2, NULL);
+SELECT * FROM t1 ORDER BY c1,c2;
+c1 c2
+1 1
+1 2
+2 1
+2 2
+2 3
+2 22
+2 23
+3 1
+3 2
+DROP TABLE t1;
+# Test AUTO_INCREMENT in CREATE
+CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
+ENGINE = 'MARIA'
+AUTO_INCREMENT = 15
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=15 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 (c1) VALUES (4);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=15 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 (c1) VALUES (0);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=16 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 (c1) VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=17 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1 ORDER BY c1;
+c1
+4
+15
+16
+# Test sql_mode 'NO_AUTO_VALUE_ON_ZERO'
+SET @@session.sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
+INSERT INTO t1 (c1) VALUES (300);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=301 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 (c1) VALUES (0);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=301 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 (c1) VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=302 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1 ORDER BY c1;
+c1
+0
+4
+15
+16
+300
+301
+SET @@session.sql_mode = '';
+DROP TABLE t1;
+# Test SET INSERT_ID
+CREATE TABLE t1 (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (c1))
+ENGINE = 'MARIA'
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 (c1) VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1;
+c1
+1
+SET INSERT_ID = 23;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 (c1) VALUES (NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=24 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1 ORDER BY c1;
+c1
+1
+23
+DROP TABLE t1;
+# Testing with FLUSH TABLE
+CREATE TABLE t1 (
+c1 INT NOT NULL AUTO_INCREMENT,
+PRIMARY KEY (c1))
+ENGINE='MARIA'
+PARTITION BY HASH(c1)
+PARTITIONS 2;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+FLUSH TABLE;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 VALUES (4);
+FLUSH TABLE;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+INSERT INTO t1 VALUES (NULL);
+FLUSH TABLE;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=MARIA AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+PARTITIONS 2 */
+SELECT * FROM t1 ORDER BY c1;
+c1
+4
+5
+DROP TABLE t1;
diff --git a/mysql-test/suite/parts/t/partition_alter2_1_maria.test b/mysql-test/suite/parts/t/partition_alter2_1_maria.test
new file mode 100644
index 00000000000..d261c705459
--- /dev/null
+++ b/mysql-test/suite/parts/t/partition_alter2_1_maria.test
@@ -0,0 +1,83 @@
+################################################################################
+# t/partition_alter2_1_maria.test #
+# #
+# Purpose: #
+# Tests around Alter column used in partitioning function #
+# MARIA branch #
+# #
+#------------------------------------------------------------------------------#
+# Original Author: mleich #
+# Original Date: 2006-03-05 #
+# Change Author: #
+# Change Date: #
+# Change: #
+################################################################################
+
+#
+# NOTE: PLEASE DO NOT ADD NOT MARIA SPECIFIC TESTCASES HERE !
+# TESTCASES WHICH MUST BE APPLIED TO ALL STORAGE ENGINES MUST BE ADDED IN
+# THE SOURCED FILES ONLY.
+#
+# Please read the README at the end of inc/partition.pre before changing
+# any of the variables.
+#
+
+#------------------------------------------------------------------------------#
+# General not engine specific settings and requirements
+
+##### Options, for debugging support #####
+let $debug= 0;
+let $with_partitioning= 1;
+
+##### Option, for displaying files #####
+let $ls= 1;
+
+##### Number of rows for the INSERT/UPDATE/DELETE/SELECT experiments #####
+# on partioned tables
+SET @max_row = 20;
+
+##### Execute more tests #####
+let $more_trigger_tests= 0;
+let $more_pk_ui_tests= 0;
+
+# The server must support partitioning.
+--source include/have_partition.inc
+
+# Lots of ALTER TABLE, slow in Maria (disk syncs), takes ~15 minutes
+--source include/big_test.inc
+
+#------------------------------------------------------------------------------#
+# Engine specific settings and requirements
+
+##### Storage engine to be tested
+--source include/have_maria.inc
+let $engine= 'MARIA';
+
+##### Execute the test of "table" files
+# MARIA has files per PK, UI, ...
+let $do_file_tests= 1;
+
+##### Execute PRIMARY KEY tests #####
+# AFAIK MARIA treats PRIMARY KEYs like UNIQUE INDEXes
+let $do_pk_tests= 0;
+
+##### Assign a big number smaller than the maximum value for partitions #####
+# and smaller than the maximum value of SIGNED INTEGER
+let $MAX_VALUE= (2147483646);
+
+# Generate the prerequisites ($variables, @variables, tables) needed
+--source suite/parts/inc/partition.pre
+
+##### Workarounds for known open engine specific bugs
+# none
+
+#------------------------------------------------------------------------------#
+# Execute the tests to be applied to all storage engines
+--source suite/parts/inc/partition_alter2_1.inc
+
+#------------------------------------------------------------------------------#
+# Execute storage engine specific tests
+
+#------------------------------------------------------------------------------#
+# Cleanup
+--source suite/parts/inc/partition_cleanup.inc
diff --git a/mysql-test/suite/parts/t/partition_alter2_2_maria.test b/mysql-test/suite/parts/t/partition_alter2_2_maria.test
new file mode 100644
index 00000000000..a46e9a3924e
--- /dev/null
+++ b/mysql-test/suite/parts/t/partition_alter2_2_maria.test
@@ -0,0 +1,83 @@
+################################################################################
+# t/partition_alter2_2_maria.test #
+# #
+# Purpose: #
+# Tests around Alter column used in partitioning function #
+# MARIA branch #
+# #
+#------------------------------------------------------------------------------#
+# Original Author: mleich #
+# Original Date: 2006-03-05 #
+# Change Author: #
+# Change Date: #
+# Change: #
+################################################################################
+
+#
+# NOTE: PLEASE DO NOT ADD NOT MARIA SPECIFIC TESTCASES HERE !
+# TESTCASES WHICH MUST BE APPLIED TO ALL STORAGE ENGINES MUST BE ADDED IN
+# THE SOURCED FILES ONLY.
+#
+# Please read the README at the end of inc/partition.pre before changing
+# any of the variables.
+#
+
+#------------------------------------------------------------------------------#
+# General not engine specific settings and requirements
+
+##### Options, for debugging support #####
+let $debug= 0;
+let $with_partitioning= 1;
+
+##### Option, for displaying files #####
+let $ls= 1;
+
+##### Number of rows for the INSERT/UPDATE/DELETE/SELECT experiments #####
+# on partioned tables
+SET @max_row = 20;
+
+##### Execute more tests #####
+let $more_trigger_tests= 0;
+let $more_pk_ui_tests= 0;
+
+# The server must support partitioning.
+--source include/have_partition.inc
+
+# Lots of ALTER TABLE, slow in Maria (disk syncs), takes ~15 minutes
+--source include/big_test.inc
+
+#------------------------------------------------------------------------------#
+# Engine specific settings and requirements
+
+##### Storage engine to be tested
+--source include/have_maria.inc
+let $engine= 'MARIA';
+
+##### Execute the test of "table" files
+# MAARIA has files per PK, UI, ...
+let $do_file_tests= 1;
+
+##### Execute PRIMARY KEY tests #####
+# AFAIK MARIA treats PRIMARY KEYs like UNIQUE INDEXes
+let $do_pk_tests= 0;
+
+##### Assign a big number smaller than the maximum value for partitions #####
+# and smaller than the maximum value of SIGNED INTEGER
+let $MAX_VALUE= (2147483646);
+
+# Generate the prerequisites ($variables, @variables, tables) needed
+--source suite/parts/inc/partition.pre
+
+##### Workarounds for known open engine specific bugs
+# none
+
+#------------------------------------------------------------------------------#
+# Execute the tests to be applied to all storage engines
+--source suite/parts/inc/partition_alter2_2.inc
+
+#------------------------------------------------------------------------------#
+# Execute storage engine specific tests
+
+#------------------------------------------------------------------------------#
+# Cleanup
+--source suite/parts/inc/partition_cleanup.inc
diff --git a/mysql-test/suite/parts/t/partition_auto_increment_maria.test b/mysql-test/suite/parts/t/partition_auto_increment_maria.test
new file mode 100644
index 00000000000..5f1515ec929
--- /dev/null
+++ b/mysql-test/suite/parts/t/partition_auto_increment_maria.test
@@ -0,0 +1,35 @@
+################################################################################
+# t/partition_auto_increment_maria.test #
+# #
+# Purpose: #
+# Tests around auto increment column #
+# MARIA branch #
+# #
+#------------------------------------------------------------------------------#
+# Original Author: MattiasJ #
+# Original Date: 2008-02-12 #
+# Change Author: #
+# Change Date: #
+# Change: #
+################################################################################
+
+#
+# NOTE: PLEASE DO NOT ADD NOT MARIA SPECIFIC TESTCASES HERE !
+# TESTCASES WHICH MUST BE APPLIED TO ALL STORAGE ENGINES MUST BE ADDED IN
+# THE SOURCED FILES ONLY.
+#
+
+# The server must support partitioning.
+--source include/have_partition.inc
+
+#------------------------------------------------------------------------------#
+# Engine specific settings and requirements
+
+##### Storage engine to be tested
+--source include/have_maria.inc
+let $engine= 'MARIA';
+
+#------------------------------------------------------------------------------#
+# Execute the tests to be applied to all storage engines
+--source suite/parts/inc/partition_auto_increment.inc
+
diff --git a/mysql-test/suite/rpl/r/rpl_insert.result b/mysql-test/suite/rpl/r/rpl_insert.result
index b6a97926f73..6080d18c5aa 100644
--- a/mysql-test/suite/rpl/r/rpl_insert.result
+++ b/mysql-test/suite/rpl/r/rpl_insert.result
@@ -9,7 +9,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
CREATE SCHEMA IF NOT EXISTS mysqlslap;
USE mysqlslap;
-CREATE TABLE t1 (id INT, name VARCHAR(64));
+CREATE TABLE t1 (id INT, name VARCHAR(64)) ENGINE=MyISAM;
SELECT COUNT(*) FROM mysqlslap.t1;
COUNT(*)
5000
diff --git a/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result b/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result
index 129bad0fbcc..18a5dbfccc1 100644
--- a/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result
+++ b/mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result
@@ -4,21 +4,21 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
-create table t1 (a int);
+create table t1 (a int) ENGINE=MyISAM;
insert into t1 values (10);
-create table t2 (a int);
+create table t2 (a int) ENGINE=MyISAM;
create table t3 (a int) engine=merge union(t1);
create table t4 (a int);
insert into t4 select * from t3;
rename table t1 to t5, t2 to t1;
flush no_write_to_binlog tables;
-SHOW BINLOG EVENTS FROM 897 ;
+SHOW BINLOG EVENTS FROM 925 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
select * from t3;
a
flush tables;
-SHOW BINLOG EVENTS FROM 897 ;
+SHOW BINLOG EVENTS FROM 925 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
master-bin.000001 # Query 1 # use `test`; flush tables
diff --git a/mysql-test/suite/rpl/r/rpl_row_insert_delayed.result b/mysql-test/suite/rpl/r/rpl_row_insert_delayed.result
index 1551d83266d..fa6c8cf9982 100644
--- a/mysql-test/suite/rpl/r/rpl_row_insert_delayed.result
+++ b/mysql-test/suite/rpl/r/rpl_row_insert_delayed.result
@@ -11,7 +11,7 @@ USE mysqlslap;
select @@global.binlog_format;
@@global.binlog_format
ROW
-CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
FLUSH TABLE t1;
SELECT COUNT(*) FROM t1;
COUNT(*)
diff --git a/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result b/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result
index 74031af1dde..ea2a9ce9a79 100644
--- a/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result
+++ b/mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result
@@ -4,21 +4,21 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
-create table t1 (a int);
+create table t1 (a int) ENGINE=MyISAM;
insert into t1 values (10);
-create table t2 (a int);
+create table t2 (a int) ENGINE=MyISAM;
create table t3 (a int) engine=merge union(t1);
create table t4 (a int);
insert into t4 select * from t3;
rename table t1 to t5, t2 to t1;
flush no_write_to_binlog tables;
-SHOW BINLOG EVENTS FROM 656 ;
+SHOW BINLOG EVENTS FROM 684 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
select * from t3;
a
flush tables;
-SHOW BINLOG EVENTS FROM 656 ;
+SHOW BINLOG EVENTS FROM 684 ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; rename table t1 to t5, t2 to t1
master-bin.000001 # Query 1 # use `test`; flush tables
diff --git a/mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result b/mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result
index 5ca0ea2b780..70aeb733769 100644
--- a/mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result
+++ b/mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result
@@ -11,7 +11,7 @@ USE mysqlslap;
select @@global.binlog_format;
@@global.binlog_format
STATEMENT
-CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
FLUSH TABLE t1;
SELECT COUNT(*) FROM t1;
COUNT(*)
@@ -77,7 +77,7 @@ USE mysqlslap;
select @@global.binlog_format;
@@global.binlog_format
MIXED
-CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64));
+CREATE TABLE t1 (id INT primary key auto_increment, name VARCHAR(64)) ENGINE=MyISAM;
FLUSH TABLE t1;
SELECT COUNT(*) FROM t1;
COUNT(*)
diff --git a/mysql-test/suite/rpl/r/rpl_stm_maria.result b/mysql-test/suite/rpl/r/rpl_stm_maria.result
new file mode 100644
index 00000000000..be21b946ab5
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_stm_maria.result
@@ -0,0 +1,51 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP TABLE IF EXISTS t3;
+create table t1 (a int auto_increment, primary key (a), b int,
+rand_value double not null) engine=maria;
+create table t2 (a int auto_increment, primary key (a), b int) engine=maria;
+create table t3 (a int auto_increment, primary key (a), name
+varchar(64) not null, old_a int, old_b int, rand_value double not
+null) engine=maria;
+create trigger t1 before insert on t1 for each row
+begin
+insert into t3 values (NULL, "t1", new.a, new.b, rand());
+end|
+create trigger t2 after insert on t2 for each row
+begin
+insert into t3 values (NULL, "t2", new.a, new.b, rand());
+end|
+insert into t3 values(100,"log",0,0,0);
+SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186;
+insert into t1 values(1,1,rand()),(NULL,2,rand());
+insert into t2 (b) values(last_insert_id());
+insert into t2 values(3,0),(NULL,0);
+insert into t2 values(NULL,0),(500,0);
+select a,b, truncate(rand_value,4) from t1;
+a b truncate(rand_value,4)
+1 1 0.4320
+2 2 0.3055
+select * from t2;
+a b
+1 2
+3 0
+4 0
+5 0
+500 0
+select a,name, old_a, old_b, truncate(rand_value,4) from t3;
+a name old_a old_b truncate(rand_value,4)
+100 log 0 0 0.0000
+101 t1 1 1 0.3203
+102 t1 0 2 0.5666
+103 t2 1 2 0.9164
+104 t2 3 0 0.8826
+105 t2 4 0 0.6635
+106 t2 5 0 0.6699
+107 t2 500 0 0.3593
+drop table t1,t2,t3;
diff --git a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result
index 7447d12f9b2..1f9f940df01 100644
--- a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result
+++ b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result
@@ -135,7 +135,7 @@ execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for_23_",UUID()));
insert into t1 select "yesterday_24_";
-create table t2 select rpad(UUID(),100,' ');
+create table t2 ENGINE=MyISAM select rpad(UUID(),100,' ');
create table t3 select 1 union select UUID();
create table t4 select * from t1 where 3 in (select 1 union select 2 union select UUID() union select 3);
create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3);
diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test
index 124cf4a956f..a9cd6b15b6e 100644
--- a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test
+++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test
@@ -1,3 +1,4 @@
+--source include/big_test.inc
--source include/have_innodb.inc
--source include/have_partition.inc
--source include/have_binlog_format_mixed_or_row.inc
diff --git a/mysql-test/suite/rpl/t/rpl_insert.test b/mysql-test/suite/rpl/t/rpl_insert.test
index d304dfb6cc7..6fb9ec8fd72 100644
--- a/mysql-test/suite/rpl/t/rpl_insert.test
+++ b/mysql-test/suite/rpl/t/rpl_insert.test
@@ -11,7 +11,7 @@ CREATE SCHEMA IF NOT EXISTS mysqlslap;
USE mysqlslap;
--enable_warnings
-CREATE TABLE t1 (id INT, name VARCHAR(64));
+CREATE TABLE t1 (id INT, name VARCHAR(64)) ENGINE=MyISAM;
sync_slave_with_master;
connection master;
diff --git a/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test b/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test
index 667e1d9a1a8..064a7c89dbe 100644
--- a/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test
+++ b/mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test
@@ -1,7 +1,7 @@
# depends on the binlog output
-- source include/have_binlog_format_row.inc
-let $rename_event_pos= 897;
+let $rename_event_pos= 925;
# Bug#18326: Do not lock table for writing during prepare of statement
# The use of the ps protocol causes extra table maps in the binlog, so
diff --git a/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test b/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test
index a8a33d05e8b..dad61002be4 100644
--- a/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test
+++ b/mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test
@@ -1,7 +1,7 @@
# depends on the binlog output
--source include/have_binlog_format_mixed_or_statement.inc
-let $rename_event_pos= 656;
+let $rename_event_pos= 684;
-- source extra/rpl_tests/rpl_flsh_tbls.test
# End of 4.1 tests
diff --git a/mysql-test/suite/rpl/t/rpl_stm_maria.test b/mysql-test/suite/rpl/t/rpl_stm_maria.test
new file mode 100644
index 00000000000..f850473ab51
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_stm_maria.test
@@ -0,0 +1,51 @@
+# Test of Maria-specific replication bugs
+
+--source include/have_maria.inc
+--source include/have_binlog_format_mixed_or_statement.inc
+--source include/master-slave.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP TABLE IF EXISTS t3;
+--enable_warnings
+
+# This one taken from rpl_trigger.test (from BUG#12482)
+# used to segfault slave in execution of row-based events
+
+# Need an explicit ENGINE= clause as @@STORAGE_ENGINE is not replicated
+create table t1 (a int auto_increment, primary key (a), b int,
+rand_value double not null) engine=maria;
+create table t2 (a int auto_increment, primary key (a), b int) engine=maria;
+create table t3 (a int auto_increment, primary key (a), name
+varchar(64) not null, old_a int, old_b int, rand_value double not
+null) engine=maria;
+
+delimiter |;
+create trigger t1 before insert on t1 for each row
+begin
+ insert into t3 values (NULL, "t1", new.a, new.b, rand());
+end|
+
+create trigger t2 after insert on t2 for each row
+begin
+ insert into t3 values (NULL, "t2", new.a, new.b, rand());
+end|
+delimiter ;|
+
+insert into t3 values(100,"log",0,0,0);
+
+SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186;
+
+insert into t1 values(1,1,rand()),(NULL,2,rand());
+insert into t2 (b) values(last_insert_id());
+insert into t2 values(3,0),(NULL,0);
+insert into t2 values(NULL,0),(500,0);
+
+select a,b, truncate(rand_value,4) from t1;
+select * from t2;
+select a,name, old_a, old_b, truncate(rand_value,4) from t3;
+sync_slave_with_master;
+connection master;
+drop table t1,t2,t3;
+sync_slave_with_master;
diff --git a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test
index e6c1d5256a0..a9c668b4293 100644
--- a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test
+++ b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test
@@ -140,7 +140,7 @@ insert into t1 select "yesterday_24_";
# Test of CREATE TABLE SELECT
-create table t2 select rpad(UUID(),100,' ');
+create table t2 ENGINE=MyISAM select rpad(UUID(),100,' ');
create table t3 select 1 union select UUID();
create table t4 select * from t1 where 3 in (select 1 union select 2 union select UUID() union select 3);
create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3);
diff --git a/mysql-test/suite/sys_vars/r/sync_frm_basic.result b/mysql-test/suite/sys_vars/r/sync_frm_basic.result
index 9792307d17f..2467ea15e7c 100644
--- a/mysql-test/suite/sys_vars/r/sync_frm_basic.result
+++ b/mysql-test/suite/sys_vars/r/sync_frm_basic.result
@@ -1,7 +1,7 @@
SET @start_value = @@global.sync_frm;
SELECT @start_value;
@start_value
-1
+VAL
'#--------------------FN_DYNVARS_169_01------------------------#'
SET @@global.sync_frm = FALSE;
SET @@global.sync_frm = DEFAULT;
@@ -94,4 +94,4 @@ ERROR 42S22: Unknown column 'sync_frm' in 'field list'
SET @@global.sync_frm = @start_value;
SELECT @@global.sync_frm;
@@global.sync_frm
-1
+VAL
diff --git a/mysql-test/suite/sys_vars/t/slow_query_log_file_basic-master.opt b/mysql-test/suite/sys_vars/t/slow_query_log_file_basic-master.opt
index aca191f7fea..2b6ac309d6c 100644
--- a/mysql-test/suite/sys_vars/t/slow_query_log_file_basic-master.opt
+++ b/mysql-test/suite/sys_vars/t/slow_query_log_file_basic-master.opt
@@ -1 +1 @@
---log-slow-queries=slowtest.log
+--slow-query-log --slow-query-log-file=slowtest.log
diff --git a/mysql-test/suite/sys_vars/t/slow_query_log_file_func-master.opt b/mysql-test/suite/sys_vars/t/slow_query_log_file_func-master.opt
index e5b1c0948b0..e866f016022 100644
--- a/mysql-test/suite/sys_vars/t/slow_query_log_file_func-master.opt
+++ b/mysql-test/suite/sys_vars/t/slow_query_log_file_func-master.opt
@@ -1,2 +1,2 @@
---log-slow-queries=my_slow_test.log
+--slow-query-log --slow-query-log-file=my_slow_test.log
diff --git a/mysql-test/suite/sys_vars/t/sync_frm_basic.test b/mysql-test/suite/sys_vars/t/sync_frm_basic.test
index 6c00182a805..af268fd2c44 100644
--- a/mysql-test/suite/sys_vars/t/sync_frm_basic.test
+++ b/mysql-test/suite/sys_vars/t/sync_frm_basic.test
@@ -34,6 +34,8 @@
################################################################
SET @start_value = @@global.sync_frm;
+# In some cases the server may have been started with --disable-sync-frm
+--replace_column 1 VAL
SELECT @start_value;
@@ -155,9 +157,9 @@ SELECT sync_frm = @@session.sync_frm;
##############################
SET @@global.sync_frm = @start_value;
+--replace_column 1 VAL
SELECT @@global.sync_frm;
-
######################################################
# END OF sync_frm TESTS #
######################################################
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index ae48d5a8736..2498d566f66 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -159,7 +159,7 @@ drop table t1;
# Test of ALTER TABLE DELAYED
#
-CREATE TABLE t1 (i int(10), index(i) );
+CREATE TABLE t1 (i int(10), index(i) ) ENGINE=MyISAM;
ALTER TABLE t1 DISABLE KEYS;
INSERT DELAYED INTO t1 VALUES(1),(2),(3);
ALTER TABLE t1 ENABLE KEYS;
diff --git a/mysql-test/t/bootstrap.test b/mysql-test/t/bootstrap.test
index db89269b35d..3b62887869d 100644
--- a/mysql-test/t/bootstrap.test
+++ b/mysql-test/t/bootstrap.test
@@ -5,7 +5,6 @@
drop table if exists t1;
--enable_warnings
-
# Add the datadir to the bootstrap command
let $MYSQLD_DATADIR= `select @@datadir`;
let $MYSQLD_BOOTSTRAP_CMD= $MYSQLD_BOOTSTRAP_CMD --datadir=$MYSQLD_DATADIR;
diff --git a/mysql-test/t/change_user.test b/mysql-test/t/change_user.test
index 89f35116a2c..540f9d1b53f 100644
--- a/mysql-test/t/change_user.test
+++ b/mysql-test/t/change_user.test
@@ -1,5 +1,6 @@
#
# Bug#20023 mysql_change_user() resets the value of SQL_BIG_SELECTS
+# The replace's are here to fix things for 32 bit systems
#
--echo Bug#20023
@@ -26,6 +27,10 @@ SET @@session.max_join_size = default;
--echo change_user
--change_user
SELECT @@session.sql_big_selects;
+--replace_result 4294967295 18446744073709551615
+SELECT @@global.max_join_size;
+--replace_result 4294967295 18446744073709551615
+SELECT @@session.max_join_size;
#
# Bug#31418 User locks misfunctioning after mysql_change_user()
diff --git a/mysql-test/t/crash_commit_before-master.opt b/mysql-test/t/crash_commit_before-master.opt
index a745693594e..425fda95086 100644
--- a/mysql-test/t/crash_commit_before-master.opt
+++ b/mysql-test/t/crash_commit_before-master.opt
@@ -1,2 +1 @@
--skip-stack-trace --skip-core-file
-
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index f9708002ee6..0412bc0628c 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -1368,9 +1368,11 @@ drop function f1;
# Bug#25629 CREATE TABLE LIKE does not work with INFORMATION_SCHEMA
#
create table t1 like information_schema.processlist;
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
show create table t1;
drop table t1;
create temporary table t1 like information_schema.processlist;
+--replace_result ENGINE=MyISAM "" ENGINE=MARIA "" " PAGE_CHECKSUM=1" "" " PAGE_CHECKSUM=0" ""
show create table t1;
drop table t1;
create table t1 like information_schema.character_sets;
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index f0c769251cf..bb64319f1e4 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -164,7 +164,7 @@ drop table t1;
# UTF8 breaks primary keys for cols > 333 characters
#
--error 1071
-create table t1 (a text character set utf8, primary key(a(360)));
+create table t1 (a text character set utf8, primary key(a(371)));
#
diff --git a/mysql-test/t/delayed.test b/mysql-test/t/delayed.test
index ce57645bd4b..87d6ab55ee5 100644
--- a/mysql-test/t/delayed.test
+++ b/mysql-test/t/delayed.test
@@ -5,6 +5,15 @@
# (Can't be tested with purify :( )
#
+# limit the test to engines which support INSERT DELAYED
+disable_query_log;
+--require r/true.require
+select @@global.storage_engine in
+("memory","myisam","archive","blackhole") and
+@@session.storage_engine in
+("memory","myisam","archive","blackhole") as `TRUE`;
+enable_query_log;
+
--disable_warnings
drop table if exists t1;
--enable_warnings
@@ -247,7 +256,11 @@ DROP TABLE t1;
# Bug #32676: insert delayed crash with wrong column and function specified
#
CREATE TABLE t1 (a INT);
---error ER_BAD_FIELD_ERROR
+--error ER_SP_DOES_NOT_EXIST
+INSERT DELAYED INTO t1 SET a= b();
+--error ER_BAD_FIELD_ERROR
+INSERT DELAYED INTO t1 SET b= 1;
+--error ER_SP_DOES_NOT_EXIST
INSERT DELAYED INTO t1 SET b= b();
DROP TABLE t1;
diff --git a/mysql-test/t/events_logs_tests-master.opt b/mysql-test/t/events_logs_tests-master.opt
index 35ff7911705..73d26b7260d 100644
--- a/mysql-test/t/events_logs_tests-master.opt
+++ b/mysql-test/t/events_logs_tests-master.opt
@@ -1 +1 @@
---log-slow-queries
+--slow-query-log --log-output=table --general-log --general-log-file="" --slow-query-log-file=""
diff --git a/mysql-test/t/events_logs_tests.test b/mysql-test/t/events_logs_tests.test
index 3240dccbc76..1c296ee302b 100644
--- a/mysql-test/t/events_logs_tests.test
+++ b/mysql-test/t/events_logs_tests.test
@@ -75,12 +75,10 @@ create event ev_log_general on schedule at now() on completion not preserve
--replace_column 1 USER_HOST
select user_host, db, sql_text from mysql.slow_log
where sql_text like 'select \'events_logs_test\'%';
-
drop database events_test;
set global event_scheduler=off;
set @@global.long_query_time=default;
set @@session.long_query_time=default;
-
#
# Safety
#
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index 852369fd568..e045d34ed32 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -447,6 +447,15 @@ WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
DROP TABLE t1;
#
+# bug#34374 - mysql generates incorrect warning
+#
+create table t1(a text,b date,fulltext index(a))engine=myisam;
+insert into t1 set a='water',b='2008-08-04';
+select 1 from t1 where match(a) against ('water' in boolean mode) and b>='2008-08-01';
+drop table t1;
+show warnings;
+
+#
# BUG#37245 - Full text search problem
#
CREATE TABLE t1(a CHAR(10));
diff --git a/mysql-test/t/insert.test b/mysql-test/t/insert.test
index c58fb61ad30..a5eb31496b1 100644
--- a/mysql-test/t/insert.test
+++ b/mysql-test/t/insert.test
@@ -235,8 +235,10 @@ insert into t1 values (1,11), (2,22);
insert into t2 values (1,12), (2,24);
--error 1393
insert into v1 (f1) values (3) on duplicate key update f3= f3 + 10;
+--error 1393
insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
select * from t1;
+--error 1393
insert into v1 (f1) values (3) on duplicate key update f1= f3 + 10;
select * from t1;
drop view v1;
diff --git a/mysql-test/t/log_tables-big-master.opt b/mysql-test/t/log_tables-big-master.opt
index 35ff7911705..b9bc885d0e4 100644
--- a/mysql-test/t/log_tables-big-master.opt
+++ b/mysql-test/t/log_tables-big-master.opt
@@ -1 +1 @@
---log-slow-queries
+--log-output=table,file --slow-query-log --general-log --general-log-file="" --slow-query-log-file=""
diff --git a/mysql-test/t/log_tables-master.opt b/mysql-test/t/log_tables-master.opt
index 35ff7911705..4c25518cefe 100644
--- a/mysql-test/t/log_tables-master.opt
+++ b/mysql-test/t/log_tables-master.opt
@@ -1 +1 @@
---log-slow-queries
+--log-output=table,file --slow-query-log --general-log
diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test
index dd3e4e28aeb..6e5d2aee7fd 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -2,6 +2,11 @@
# Test of MERGE TABLES
#
+# MERGE tables require MyISAM tables
+let $default=`select @@global.storage_engine`;
+set global storage_engine=myisam;
+set session storage_engine=myisam;
+
--disable_warnings
drop table if exists t1,t2,t3,t4,t5,t6;
drop database if exists mysqltest;
@@ -612,9 +617,9 @@ ALTER TABLE m1 UNION=(t1);
ALTER TABLE m1 UNION=();
SHOW CREATE TABLE m1;
DROP TABLE t1, m1;
-
--echo End of 5.0 tests
+
#
# Bug #8306: TRUNCATE leads to index corruption
#
@@ -751,7 +756,7 @@ DROP TABLE t1, t2;
# *after* the administration task. It was terminated by UNLOCK TABLES only.
#
# This is the same test case as for
-# Bug#26867 - LOCK TABLES + REPAIR + merge table result in memory/cpu hogging
+# Bug#26867 - LOCK TABLES REPAIR + merge table result in memory/cpu hogging
#
#
CREATE TABLE t1 (c1 INT) ENGINE= MyISAM;
@@ -1423,3 +1428,9 @@ EXPLAIN SELECT COUNT(*) FROM t4;
DROP TABLE t1, t2, t3, t4;
--echo End of 5.1 tests
+
+--disable_result_log
+--disable_query_log
+eval set global storage_engine=$default;
+--enable_result_log
+--enable_query_log
diff --git a/mysql-test/t/multi_statement-master.opt b/mysql-test/t/multi_statement-master.opt
index b30df037531..c735cf4c21b 100644
--- a/mysql-test/t/multi_statement-master.opt
+++ b/mysql-test/t/multi_statement-master.opt
@@ -1,2 +1,3 @@
---log-slow-queries=slow.log
+--slow-query-log
+--slow-query-log-file=slow.log
--log-queries-not-using-indexes
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index 6d7e03b1c28..b5099695e47 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -4,7 +4,7 @@
# Initialise
--disable_warnings
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
--enable_warnings
SET SQL_WARNINGS=1;
@@ -1478,5 +1478,24 @@ let $MYSQLD_DATADIR= `select @@datadir`;
--exec $MYISAMCHK -d $MYSQLD_DATADIR/test/t1
DROP TABLE t1;
---echo End of 5.1 tests
+# Test warnings with transactional=1 with MyISAM
+#
+create table t1 (n int not null, c char(1)) transactional=1;
+show create table t1;
+drop table t1;
+
+#
+# Test of BUG#35570 CHECKSUM TABLE unreliable if LINESTRING field
+# (same content / differen checksum)
+#
+CREATE TABLE t1 (line LINESTRING NOT NULL) engine=myisam;
+INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t1;
+CREATE TABLE t2 (line LINESTRING NOT NULL) engine=myisam;
+INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)"));
+checksum table t2;
+CREATE TABLE t3 select * from t1;
+checksum table t3;
+drop table t1,t2,t3;
+--echo End of 5.1 tests
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index de5abdd7c9d..ae5c27af1d8 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -207,7 +207,7 @@ DROP TABLE t1;
--echo # Test for --insert-ignore
--echo #
-CREATE TABLE t1 (a int);
+CREATE TABLE t1 (a int) ENGINE=MyISAM;
INSERT INTO t1 VALUES (1),(2),(3);
INSERT INTO t1 VALUES (4),(5),(6);
--exec $MYSQL_DUMP --skip-comments --insert-ignore test t1
@@ -1471,8 +1471,8 @@ DROP TABLE t1;
# Bug #25993: crashe with a merge table and -c
#
-CREATE TABLE t2 (a int);
-CREATE TABLE t3 (a int);
+CREATE TABLE t2 (a int) ENGINE=MyISAM;
+CREATE TABLE t3 (a int) ENGINE=MyISAM;
CREATE TABLE t1 (a int) ENGINE=merge UNION=(t2, t3);
--exec $MYSQL_DUMP --skip-comments -c test
DROP TABLE t1, t2, t3;
diff --git a/mysql-test/t/old-mode-master.opt b/mysql-test/t/old-mode-master.opt
new file mode 100644
index 00000000000..840ee0dedcf
--- /dev/null
+++ b/mysql-test/t/old-mode-master.opt
@@ -0,0 +1 @@
+--old=1
diff --git a/mysql-test/t/old-mode.test b/mysql-test/t/old-mode.test
new file mode 100644
index 00000000000..6d0fe64bbb8
--- /dev/null
+++ b/mysql-test/t/old-mode.test
@@ -0,0 +1,17 @@
+#
+# Test 'old' mode
+#
+
+# Initialise
+--disable_warnings
+drop table if exists t1,t2;
+--enable_warnings
+
+create table t1 (a int, b varchar(200), c text not null) checksum=1;
+create table t2 (a int, b varchar(200), c text not null) checksum=0;
+insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, "");
+insert t2 select * from t1;
+checksum table t1, t2;
+checksum table t1, t2 quick;
+checksum table t1, t2 extended;
+drop table t1,t2;
diff --git a/mysql-test/t/ps-master.opt b/mysql-test/t/ps-master.opt
index 3eb98fc3d6b..0e3f2e5092d 100644
--- a/mysql-test/t/ps-master.opt
+++ b/mysql-test/t/ps-master.opt
@@ -1 +1 @@
---log-slow-queries --log-long-format --log-queries-not-using-indexes
+--log-output=table,file --slow-query-log --log-long-format --log-queries-not-using-indexes --general-log
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index 7841e7274dd..9a1547fa3d4 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -45,9 +45,9 @@ show status like "Qcache_queries_in_cache";
#
# MERGE TABLES with INSERT/UPDATE and DELETE
#
-create table t1 (a int not null);
+create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
-create table t2 (a int not null);
+create table t2 (a int not null) ENGINE=MyISAM;
insert into t2 values (4),(5),(6);
create table t3 (a int not null) engine=MERGE UNION=(t1,t2) INSERT_METHOD=FIRST;
# insert
@@ -294,7 +294,7 @@ drop table t1;
flush query cache;
reset query cache;
-create table t1 (a int not null);
+create table t1 (a int not null) ENGINE=MyISAM;
insert into t1 values (1),(2),(3);
select * from t1;
select * from t1;
diff --git a/mysql-test/t/query_cache_debug.test b/mysql-test/t/query_cache_debug.test
index 18dfe487ac3..6834301adce 100644
--- a/mysql-test/t/query_cache_debug.test
+++ b/mysql-test/t/query_cache_debug.test
@@ -1,4 +1,5 @@
--source include/not_embedded.inc
+--source include/big_test.inc
--source include/have_query_cache.inc
--source include/have_debug.inc
diff --git a/mysql-test/t/query_cache_merge.test b/mysql-test/t/query_cache_merge.test
index 4e25bc3ed14..189de8e4092 100644
--- a/mysql-test/t/query_cache_merge.test
+++ b/mysql-test/t/query_cache_merge.test
@@ -19,7 +19,7 @@ let $1 = 257;
while ($1)
{
eval drop table if exists t$1;
- eval create table t$1(a int);
+ eval create table t$1(a int) ENGINE=MyISAM;
eval insert into t$1 values (1),(2);
dec $1;
}
diff --git a/mysql-test/t/row-checksum-old-master.opt b/mysql-test/t/row-checksum-old-master.opt
new file mode 100644
index 00000000000..8e7b7f9e36f
--- /dev/null
+++ b/mysql-test/t/row-checksum-old-master.opt
@@ -0,0 +1 @@
+--old
diff --git a/mysql-test/t/row-checksum-old.test b/mysql-test/t/row-checksum-old.test
new file mode 100644
index 00000000000..71188ddf432
--- /dev/null
+++ b/mysql-test/t/row-checksum-old.test
@@ -0,0 +1,4 @@
+#
+# Run row-checksum.test with old mode
+#
+--source t/row-checksum.test
diff --git a/mysql-test/t/row-checksum.test b/mysql-test/t/row-checksum.test
new file mode 100644
index 00000000000..920a2384aa8
--- /dev/null
+++ b/mysql-test/t/row-checksum.test
@@ -0,0 +1,62 @@
+#
+# Test checksum
+#
+
+-- source include/have_innodb.inc
+-- source include/have_maria.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+checksum table t1 quick;
+checksum table t1 extended;
+drop table if exists t1;
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=1;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+checksum table t1 quick;
+checksum table t1 extended;
+drop table if exists t1;
+
+create table t1 (a int null, v varchar(100)) engine=innodb checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+checksum table t1 quick;
+checksum table t1 extended;
+drop table t1;
+
+create table t1 (a int null, v varchar(100)) engine=maria checksum=0;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+checksum table t1 quick;
+checksum table t1 extended;
+drop table t1;
+create table t1 (a int null, v varchar(100)) engine=maria checksum=1;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+checksum table t1 quick;
+checksum table t1 extended;
+drop table t1;
+
+
+#
+# These checksums will be different prefixes fixed sizes rows with one extra
+# flag byte
+#
+create table t1 (a int null, v varchar(100)) engine=myisam checksum=1 row_format=fixed;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+checksum table t1 quick;
+checksum table t1 extended;
+drop table if exists t1;
+
+create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
+insert into t1 values(null, null), (1, "hello");
+checksum table t1;
+checksum table t1 quick;
+checksum table t1 extended;
+drop table t1;
diff --git a/mysql-test/t/show_check-master.opt b/mysql-test/t/show_check-master.opt
index 7a438da06cc..6fd0fec0e08 100644
--- a/mysql-test/t/show_check-master.opt
+++ b/mysql-test/t/show_check-master.opt
@@ -1 +1 @@
---log-slow-queries --log-long-format --log-queries-not-using-indexes --myisam-recover=""
+--log-output=table --slow-query-log --log-long-format --log-queries-not-using-indexes --myisam-recover="" --general-log --general-log-file="" --slow-query-log-file=""
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 9dcb645b28d..57cae8af815 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -337,8 +337,8 @@ select * from t12;
drop table t11, t12, t2;
#insert with subselects
-CREATE TABLE t1 (x int);
-create table t2 (a int);
+CREATE TABLE t1 (x int) ENGINE=MyISAM;
+create table t2 (a int) ENGINE=MyISAM;
create table t3 (b int);
insert into t2 values (1);
insert into t3 values (1),(2);
@@ -373,7 +373,7 @@ select * from t1;
drop table t1, t2, t3;
#replace with subselects
-CREATE TABLE t1 (x int not null, y int, primary key (x));
+CREATE TABLE t1 (x int not null, y int, primary key (x)) ENGINE=MyISAM;
create table t2 (a int);
create table t3 (a int);
insert into t2 values (1);
@@ -3380,7 +3380,11 @@ CREATE VIEW v2 (a,b) AS
--error 1369
INSERT INTO v2(a,b) VALUES (2,2);
+
+# disabled for now as this refers to old content of t2
+--disable_parsing
INSERT INTO v2(a,b) VALUES (1,2);
+--enable_parsing
SELECT * FROM v1;
CREATE VIEW v3 AS
diff --git a/mysql-test/t/subselect_debug.test b/mysql-test/t/subselect_debug.test
index 358705da4f2..c2a7bafe1cd 100644
--- a/mysql-test/t/subselect_debug.test
+++ b/mysql-test/t/subselect_debug.test
@@ -9,8 +9,9 @@ CREATE TABLE t1(id INT);
INSERT INTO t1 VALUES (1),(2),(3),(4);
INSERT INTO t1 SELECT a.id FROM t1 a,t1 b,t1 c,t1 d;
# Setup the mysqld to crash at certain point
+SET @orig_debug=@@debug;
SET SESSION debug="d,subselect_exec_fail";
SELECT SUM(EXISTS(SELECT RAND() FROM t1)) FROM t1;
SELECT REVERSE(EXISTS(SELECT RAND() FROM t1));
-SET SESSION debug=DEFAULT;
+SET SESSION debug=@orig_debug;
DROP TABLE t1;
diff --git a/mysql-test/t/union-master.opt b/mysql-test/t/union-master.opt
index 3eb98fc3d6b..4ddf5c3734a 100644
--- a/mysql-test/t/union-master.opt
+++ b/mysql-test/t/union-master.opt
@@ -1 +1 @@
---log-slow-queries --log-long-format --log-queries-not-using-indexes
+--slow-query-log --log-long-format --log-queries-not-using-indexes
diff --git a/mysql-test/t/variables-big.test b/mysql-test/t/variables-big.test
index 43326f3d016..2dacabfece7 100644
--- a/mysql-test/t/variables-big.test
+++ b/mysql-test/t/variables-big.test
@@ -9,12 +9,18 @@
#
set session transaction_prealloc_size=1024*1024*1024*1;
+--replace_column 1 #
show processlist;
set session transaction_prealloc_size=1024*1024*1024*2;
+--replace_column 1 #
show processlist;
+--replace_column 1 #
set session transaction_prealloc_size=1024*1024*1024*3;
+--replace_column 1 #
show processlist;
set session transaction_prealloc_size=1024*1024*1024*4;
+--replace_column 1 #
show processlist;
set session transaction_prealloc_size=1024*1024*1024*5;
+--replace_column 1 #
show processlist;
diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp
index 64c439314a9..8d578cd22cb 100644
--- a/mysql-test/valgrind.supp
+++ b/mysql-test/valgrind.supp
@@ -24,6 +24,15 @@
}
{
+ pthread allocate_tls memory loss
+ Memcheck:Leak
+ fun:calloc
+ obj:/lib*/ld*.so
+ fun:_dl_allocate_tls
+ fun:pthread_create*
+}
+
+{
pthead_exit memory loss 1
Memcheck:Leak
fun:malloc
@@ -268,18 +277,6 @@
}
#
-# Warning from my_thread_init becasue mysqld dies before kill thread exists
-#
-
-{
- my_thread_init kill thread memory loss second
- Memcheck:Leak
- fun:calloc
- fun:my_thread_init
- fun:kill_server_thread
-}
-
-#
# Leaks reported in _dl_* internal functions on Linux amd64 / glibc2.3.2.
#
@@ -372,6 +369,78 @@
fun:__libc_start_main
}
+{
+ dlclose memory loss from udf_free
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlclose
+ fun:_Z8udf_freev
+}
+
+{
+ dlclose memory loss from plugin
+ Memcheck:Leak
+ fun:calloc
+ fun:_dlerror_run
+ fun:dlclose
+ fun:plugin_dl_del(st_mysql_lex_string const*)
+}
+
+{
+ dlopen / ptread_cancel_init memory loss on Suse Linux 10.3 32/64 bit
+ Memcheck:Leak
+ fun:*alloc
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/libc-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/libc-*.so
+ fun:__libc_dlopen_mode
+ fun:pthread_cancel_init
+ fun:_Unwind_ForcedUnwind
+}
+
+{
+ dlopen / ptread_cancel_init memory loss on Suse Linux 10.3 32/64 bit
+ Memcheck:Leak
+ fun:*alloc
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/libc-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/libc-*.so
+ fun:__libc_dlopen_mode
+ fun:pthread_cancel_init
+ fun:_Unwind_ForcedUnwind
+}
+
+#
+# Reading wrong addresses on SuSe Linux 10.3 32 bit
+#
+
+{
+ Reading wrong data in libc_dlopen
+ Memcheck:Addr4
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/libc-*.so
+ obj:/lib*/ld-*.so
+ obj:/lib*/libc-*.so
+ fun:__libc_dlopen_mode
+ fun:pthread_cancel_init
+}
+
#
# These seem to be libc threading stuff, not related to MySQL code (allocations
# during pthread_exit()). Googling shows other projects also using these
@@ -478,6 +547,8 @@
fun:_ZN19TransporterRegistry11performSendEv
fun:_ZN19TransporterRegistry14forceSendCheckEi
}
+
+#
# Warning when printing stack trace (to suppress some not needed warnings)
#
diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt
index 545278485d1..8552eae3974 100755..100644
--- a/mysys/CMakeLists.txt
+++ b/mysys/CMakeLists.txt
@@ -27,11 +27,11 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/zlib ${CMAKE_SOURCE_DIR}/include ${CMAKE
SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_modify.c
errors.c hash.c list.c md5.c mf_brkhant.c mf_cache.c mf_dirname.c mf_fn_ext.c
- mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c
+ mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c my_safehash.c
mf_keycaches.c mf_loadpath.c mf_pack.c mf_path.c mf_qsort.c mf_qsort2.c
mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_arr_appstr.c mf_tempdir.c
mf_tempfile.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_access.c
- my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chsize.c
+ my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chmod.c my_chsize.c
my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c
my_div.c my_error.c my_file.c my_fopen.c my_fstream.c my_gethostbyname.c
my_gethwaddr.c my_getopt.c my_getsystime.c my_getwd.c my_handler.c my_init.c
@@ -41,7 +41,11 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_
my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c
my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c
rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
- thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c)
+ thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c
+ lf_alloc-pin.c lf_dynarray.c lf_hash.c
+ my_atomic.c my_getncpus.c my_rnd.c
+ my_uuid.c wqueue.c waiting_threads.c
+)
IF(NOT SOURCE_SUBLIBS)
ADD_LIBRARY(mysys ${MYSYS_SOURCES})
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
index 3312c692c09..6efdd0d75e7 100644
--- a/mysys/Makefile.am
+++ b/mysys/Makefile.am
@@ -20,18 +20,21 @@ INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
-I$(top_srcdir)/include -I$(srcdir)
pkglib_LIBRARIES = libmysys.a
LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a $(top_builddir)/dbug/libdbug.a
-noinst_HEADERS = mysys_priv.h my_static.h my_handler_errors.h
+noinst_HEADERS = mysys_priv.h my_static.h my_handler_errors.h my_safehash.h
libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
mf_path.c mf_loadpath.c my_file.c \
my_open.c my_create.c my_dup.c my_seek.c my_read.c \
my_pread.c my_write.c my_getpagesize.c \
+ my_safehash.c \
mf_keycache.c mf_keycaches.c my_crc32.c \
mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \
mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \
my_malloc.c my_realloc.c my_once.c mulalloc.c \
my_alloc.c safemalloc.c my_new.cc \
- my_vle.c my_atomic.c \
+ my_vle.c my_atomic.c lf_hash.c \
+ lf_dynarray.c lf_alloc-pin.c \
my_fopen.c my_fstream.c my_getsystime.c \
+ my_rnd.c my_uuid.c \
my_error.c errors.c my_div.c my_messnc.c \
mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \
my_symlink.c my_symlink2.c \
@@ -42,7 +45,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
tree.c trie.c list.c hash.c array.c string.c typelib.c \
my_copy.c my_append.c my_lib.c \
my_delete.c my_rename.c my_redel.c \
- my_chsize.c my_clock.c \
+ my_chsize.c my_chmod.c my_clock.c \
my_quick.c my_lockmem.c my_static.c \
my_sync.c my_getopt.c my_mkdir.c \
default_modify.c default.c \
@@ -52,12 +55,14 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
my_gethostbyname.c rijndael.c my_aes.c sha1.c \
my_handler.c my_netware.c my_largepage.c \
my_memmem.c stacktrace.c \
- my_windac.c my_access.c base64.c my_libwrap.c
-EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
- thr_mutex.c thr_rwlock.c \
- CMakeLists.txt mf_soundex.c \
+ my_windac.c my_access.c base64.c my_libwrap.c \
+ wqueue.c
+if THREAD
+libmysys_a_SOURCES+= thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
+ thr_mutex.c thr_rwlock.c waiting_threads.c
+endif
+EXTRA_DIST = CMakeLists.txt mf_soundex.c \
my_conio.c my_wincond.c my_winthread.c
-libmysys_a_LIBADD = @THREAD_LOBJECTS@
# test_dir_DEPENDENCIES= $(LIBRARIES)
# testhash_DEPENDENCIES= $(LIBRARIES)
# test_charset_DEPENDENCIES= $(LIBRARIES)
@@ -71,11 +76,16 @@ DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \
-DDEFAULT_SYSCONFDIR="\"$(sysconfdir)\"" \
@DEFS@
-libmysys_a_DEPENDENCIES= @THREAD_LOBJECTS@
-
# I hope this always does the right thing. Otherwise this is only test programs
FLAGS=$(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) @NOINST_LDFLAGS@
+CLEANFILES = test_bitmap$(EXEEXT) test_priority_queue$(EXEEXT) \
+ test_thr_alarm$(EXEEXT) test_thr_lock$(EXEEXT) \
+ test_vsnprintf$(EXEEXT) test_io_cache$(EXEEXT) \
+ test_dir$(EXEEXT) test_charset$(EXEEXT) \
+ testhash$(EXEEXT) test_gethwaddr$(EXEEXT) \
+ test_base64$(EXEEXT) test_thr_mutex$(EXEEXT)
+
#
# The CP .. RM stuff is to avoid problems with some compilers (like alpha ccc)
# which automaticly removes the object files you use to compile a final program
@@ -126,5 +136,9 @@ test_base64$(EXEEXT): base64.c $(LIBRARIES)
$(LINK) $(FLAGS) -DMAIN ./test_base64.c $(LDADD) $(LIBS)
$(RM) -f ./test_base64.c
+test_thr_mutex$(EXEEXT): test_thr_mutex.c $(LIBRARIES)
+ $(LINK) $(FLAGS) $(srcdir)/test_thr_mutex.c $(LDADD) $(LIBS)
+
+
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/mysys/array.c b/mysys/array.c
index f11a327232c..b31260344a9 100644
--- a/mysys/array.c
+++ b/mysys/array.c
@@ -30,8 +30,8 @@
alloc_increment Increment for adding new elements
DESCRIPTION
- init_dynamic_array() initiates array and allocate space for
- init_alloc eilements.
+ init_dynamic_array() initiates array and allocate space for
+ init_alloc eilements.
Array is usable even if space allocation failed.
Static buffers must begin immediately after the array structure.
@@ -41,7 +41,7 @@
*/
my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
- void *init_buffer, uint init_alloc,
+ void *init_buffer, uint init_alloc,
uint alloc_increment CALLER_INFO_PROTO)
{
DBUG_ENTER("init_dynamic_array");
@@ -51,33 +51,28 @@ my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
if (init_alloc > 8 && alloc_increment > init_alloc * 2)
alloc_increment=init_alloc*2;
}
-
- if (!init_alloc)
- {
- init_alloc=alloc_increment;
- init_buffer= 0;
- }
array->elements=0;
array->max_element=init_alloc;
array->alloc_increment=alloc_increment;
array->size_of_element=element_size;
if ((array->buffer= init_buffer))
DBUG_RETURN(FALSE);
- if (!(array->buffer=(uchar*) my_malloc_ci(element_size*init_alloc,
+ if (init_alloc &&
+ !(array->buffer=(uchar*) my_malloc_ci(element_size*init_alloc,
MYF(MY_WME))))
{
array->max_element=0;
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
-}
+}
my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
- uint init_alloc,
+ uint init_alloc,
uint alloc_increment CALLER_INFO_PROTO)
{
/* placeholder to preserve ABI */
- return my_init_dynamic_array_ci(array, element_size, init_alloc,
+ return my_init_dynamic_array_ci(array, element_size, init_alloc,
alloc_increment);
}
/*
@@ -93,7 +88,7 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
FALSE Ok
*/
-my_bool insert_dynamic(DYNAMIC_ARRAY *array, uchar* element)
+my_bool insert_dynamic(DYNAMIC_ARRAY *array, const uchar* element)
{
uchar* buffer;
if (array->elements == array->max_element)
@@ -112,7 +107,7 @@ my_bool insert_dynamic(DYNAMIC_ARRAY *array, uchar* element)
/*
- Alloc space for next element(s)
+ Alloc space for next element(s)
SYNOPSIS
alloc_dynamic()
@@ -130,6 +125,7 @@ my_bool insert_dynamic(DYNAMIC_ARRAY *array, uchar* element)
uchar *alloc_dynamic(DYNAMIC_ARRAY *array)
{
+ DBUG_ENTER("alloc_dynamic");
if (array->elements == array->max_element)
{
char *new_ptr;
@@ -143,20 +139,20 @@ uchar *alloc_dynamic(DYNAMIC_ARRAY *array)
array->alloc_increment) *
array->size_of_element,
MYF(MY_WME))))
- return 0;
- memcpy(new_ptr, array->buffer,
+ DBUG_RETURN(0);
+ memcpy(new_ptr, array->buffer,
array->elements * array->size_of_element);
}
- else
- if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
- array->alloc_increment)*
- array->size_of_element,
- MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
- return 0;
+ else if (!(new_ptr=(char*)
+ my_realloc(array->buffer,(array->max_element+
+ array->alloc_increment)*
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ DBUG_RETURN(0);
array->buffer= (uchar*) new_ptr;
array->max_element+=array->alloc_increment;
}
- return array->buffer+(array->elements++ * array->size_of_element);
+ DBUG_RETURN(array->buffer+(array->elements++ * array->size_of_element));
}
@@ -166,8 +162,8 @@ uchar *alloc_dynamic(DYNAMIC_ARRAY *array)
SYNOPSIS
pop_dynamic()
array
-
- RETURN VALUE
+
+ RETURN VALUE
pointer Ok
0 Array is empty
*/
@@ -189,9 +185,9 @@ uchar *pop_dynamic(DYNAMIC_ARRAY *array)
idx Index where element is to be inserted
DESCRIPTION
- set_dynamic() replaces element in array.
- If idx > max_element insert new element. Allocate memory if needed.
-
+ set_dynamic() replaces element in array.
+ If idx > max_element insert new element. Allocate memory if needed.
+
RETURN VALUE
TRUE Idx was out of range and allocation of new memory failed
FALSE Ok
@@ -231,6 +227,8 @@ my_bool set_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements)
{
+ DBUG_ENTER("allocate_dynamic");
+
if (max_elements >= array->max_element)
{
uint size;
@@ -244,23 +242,20 @@ my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements)
so we have to create an all-new malloc since we overflowed
*/
if (!(new_ptr= (uchar *) my_malloc(size *
- array->size_of_element,
- MYF(MY_WME))))
- return 0;
- memcpy(new_ptr, array->buffer,
+ array->size_of_element,
+ MYF(MY_WME))))
+ DBUG_RETURN(0);
+ memcpy(new_ptr, array->buffer,
array->elements * array->size_of_element);
}
- else
-
-
- if (!(new_ptr= (uchar*) my_realloc(array->buffer,size*
- array->size_of_element,
- MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
- return TRUE;
+ else if (!(new_ptr= (uchar*) my_realloc(array->buffer,size*
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ DBUG_RETURN(TRUE);
array->buffer= new_ptr;
array->max_element= size;
}
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -269,9 +264,9 @@ my_bool allocate_dynamic(DYNAMIC_ARRAY *array, uint max_elements)
SYNOPSIS
get_dynamic()
- array
+ array
uchar* Element to be returned. If idx > elements contain zeroes.
- idx Index of element wanted.
+ idx Index of element wanted.
*/
void get_dynamic(DYNAMIC_ARRAY *array, uchar* element, uint idx)
@@ -348,7 +343,7 @@ void freeze_size(DYNAMIC_ARRAY *array)
*/
if (array->buffer == (uchar *)(array + 1))
return;
-
+
if (array->buffer && array->max_element != elements)
{
array->buffer=(uchar*) my_realloc(array->buffer,
@@ -365,7 +360,7 @@ void freeze_size(DYNAMIC_ARRAY *array)
SYNOPSIS
get_index_dynamic()
array Array
- element Whose element index
+ element Whose element index
*/
diff --git a/mysys/checksum.c b/mysys/checksum.c
index 4f86f6845f0..1d264b54321 100644
--- a/mysys/checksum.c
+++ b/mysys/checksum.c
@@ -18,6 +18,8 @@
#include <my_sys.h>
#include <zlib.h>
+ha_checksum my_crc_dbug_check= 1; /* Unlikely number */
+
/*
Calculate a long checksum for a memoryblock.
@@ -30,13 +32,9 @@
ha_checksum my_checksum(ha_checksum crc, const uchar *pos, size_t length)
{
-#ifdef NOT_USED
- const uchar *end=pos+length;
- for ( ; pos != end ; pos++)
- crc=((crc << 8) + *((uchar*) pos)) + (crc >> (8*sizeof(ha_checksum)-8));
+ crc= (ha_checksum) crc32((uint)crc, pos, length);
+ DBUG_PRINT("info", ("crc: %lu", (ulong) crc));
+ if (crc == my_crc_dbug_check)
+ my_debug_put_break_here();
return crc;
-#else
- return (ha_checksum)crc32((uint)crc, pos, length);
-#endif
}
-
diff --git a/mysys/errors.c b/mysys/errors.c
index 537a75c6ef3..3c690ed5ca4 100644
--- a/mysys/errors.c
+++ b/mysys/errors.c
@@ -49,7 +49,8 @@ const char * NEAR globerrs[GLOBERRS]=
"Can't sync file '%s' to disk (Errcode: %d)",
"Collation '%s' is not a compiled collation and is not specified in the '%s' file",
"File '%s' not found (Errcode: %d)",
- "File '%s' (fileno: %d) was not closed"
+ "File '%s' (fileno: %d) was not closed",
+ "Can't change mode for file '%s' to 0x%lx (Error: %d)"
};
void init_glob_errs(void)
@@ -90,5 +91,6 @@ void init_glob_errs()
EE(EE_UNKNOWN_COLLATION)= "Collation '%s' is not a compiled collation and is not specified in the %s file";
EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
EE(EE_FILE_NOT_CLOSED) = "File '%s' (fileno: %d) was not closed";
+ EE(EE_CANT_CHMOD) = "Can't change mode for file '%s' to 0x%lx (Error: %d)";
}
#endif
diff --git a/mysys/hash.c b/mysys/hash.c
index dd2d589e509..63aad7d30ed 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -304,7 +304,13 @@ static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
}
- /* Write a hash-key to the hash-index */
+/**
+ Write a hash-key to the hash-index
+
+ @return
+ @retval 0 ok
+ @retval 1 Duplicate key or out of memory
+*/
my_bool my_hash_insert(HASH *info, const uchar *record)
{
@@ -319,7 +325,7 @@ my_bool my_hash_insert(HASH *info, const uchar *record)
LINT_INIT(ptr_to_rec);
LINT_INIT(ptr_to_rec2);
- if (HASH_UNIQUE & info->flags)
+ if (info->flags & HASH_UNIQUE)
{
uchar *key= (uchar*) my_hash_key(info, record, &idx, 1);
if (my_hash_search(info, key, idx))
@@ -443,11 +449,21 @@ my_bool my_hash_insert(HASH *info, const uchar *record)
}
-/******************************************************************************
-** Remove one record from hash-table. The record with the same record
-** ptr is removed.
-** if there is a free-function it's called for record if found
-******************************************************************************/
+/**
+ Remove one record from hash-table.
+
+ @fn hash_delete()
+ @param hash Hash tree
+ @param record Row to be deleted
+
+ @notes
+ The record with the same record ptr is removed.
+ If there is a free-function it's called if record was found.
+
+ @return
+ @retval 0 ok
+ @retval 1 Record not found
+*/
my_bool my_hash_delete(HASH *hash, uchar *record)
{
@@ -531,10 +547,11 @@ exit:
DBUG_RETURN(0);
}
- /*
- Update keys when record has changed.
- This is much more efficent than using a delete & insert.
- */
+
+/**
+ Update keys when record has changed.
+ This is much more efficent than using a delete & insert.
+*/
my_bool my_hash_update(HASH *hash, uchar *record, uchar *old_key,
size_t old_key_length)
@@ -657,6 +674,37 @@ void my_hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record,
}
+/**
+ Iterate over all elements in hash and call function with the element
+
+ @param hash hash array
+ @param action function to call for each argument
+ @param argument second argument for call to action
+
+ @notes
+ If one of functions calls returns 1 then the iteration aborts
+
+ @retval 0 ok
+ @retval 1 iteration aborted becasue action returned 1
+*/
+
+my_bool my_hash_iterate(HASH *hash, my_hash_walk_action action, void *argument)
+{
+ uint records, i;
+ HASH_LINK *data;
+
+ records= hash->records;
+ data= dynamic_element(&hash->array,0,HASH_LINK*);
+
+ for (i= 0 ; i < records ; i++)
+ {
+ if ((*action)(data[i].data, argument))
+ return 1;
+ }
+ return 0;
+}
+
+
#ifndef DBUG_OFF
my_bool my_hash_check(HASH *hash)
diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c
new file mode 100644
index 00000000000..0293bfc6faf
--- /dev/null
+++ b/mysys/lf_alloc-pin.c
@@ -0,0 +1,535 @@
+/* QQ: TODO multi-pinbox */
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ wait-free concurrent allocator based on pinning addresses
+
+ It works as follows: every thread (strictly speaking - every CPU, but
+ it's too difficult to do) has a small array of pointers. They're called
+ "pins". Before using an object its address must be stored in this array
+ (pinned). When an object is no longer necessary its address must be
+ removed from this array (unpinned). When a thread wants to free() an
+ object it scans all pins of all threads to see if somebody has this
+ object pinned. If yes - the object is not freed (but stored in a
+ "purgatory"). To reduce the cost of a single free() pins are not scanned
+ on every free() but only added to (thread-local) purgatory. On every
+ LF_PURGATORY_SIZE free() purgatory is scanned and all unpinned objects
+ are freed.
+
+ Pins are used to solve ABA problem. To use pins one must obey
+ a pinning protocol:
+
+ 1. Let's assume that PTR is a shared pointer to an object. Shared means
+ that any thread may modify it anytime to point to a different object
+ and free the old object. Later the freed object may be potentially
+ allocated by another thread. If we're unlucky that other thread may
+ set PTR to point to this object again. This is ABA problem.
+ 2. Create a local pointer LOCAL_PTR.
+ 3. Pin the PTR in a loop:
+ do
+ {
+ LOCAL_PTR= PTR;
+ pin(PTR, PIN_NUMBER);
+ } while (LOCAL_PTR != PTR)
+ 4. It is guaranteed that after the loop has ended, LOCAL_PTR
+ points to an object (or NULL, if PTR may be NULL), that
+ will never be freed. It is not guaranteed though
+ that LOCAL_PTR == PTR (as PTR can change any time)
+ 5. When done working with the object, remove the pin:
+ unpin(PIN_NUMBER)
+ 6. When copying pins (as in the list traversing loop:
+ pin(CUR, 1);
+ while ()
+ {
+ do // standard
+ { // pinning
+ NEXT=CUR->next; // loop
+ pin(NEXT, 0); // see #3
+ } while (NEXT != CUR->next); // above
+ ...
+ ...
+ CUR=NEXT;
+ pin(CUR, 1); // copy pin[0] to pin[1]
+ }
+ which keeps CUR address constantly pinned), note than pins may be
+ copied only upwards (!!!), that is pin[N] to pin[M], M > N.
+ 7. Don't keep the object pinned longer than necessary - the number of
+ pins you have is limited (and small), keeping an object pinned
+ prevents its reuse and cause unnecessary mallocs.
+
+ Explanations:
+
+ 3. The loop is important. The following can occur:
+ thread1> LOCAL_PTR= PTR
+ thread2> free(PTR); PTR=0;
+ thread1> pin(PTR, PIN_NUMBER);
+ now thread1 cannot access LOCAL_PTR, even if it's pinned,
+ because it points to a freed memory. That is, it *must*
+ verify that it has indeed pinned PTR, the shared pointer.
+
+ 6. When a thread wants to free some LOCAL_PTR, and it scans
+ all lists of pins to see whether it's pinned, it does it
+ upwards, from low pin numbers to high. Thus another thread
+ must copy an address from one pin to another in the same
+ direction - upwards, otherwise the scanning thread may
+ miss it.
+
+ Implementation details:
+
+ Pins are given away from a "pinbox". Pinbox is stack-based allocator.
+ It used dynarray for storing pins, new elements are allocated by dynarray
+ as necessary, old are pushed in the stack for reuse. ABA is solved by
+ versioning a pointer - because we use an array, a pointer to pins is 16 bit,
+ upper 16 bits are used for a version.
+
+ It is assumed that pins belong to a THD and are not transferable
+ between THD's (LF_PINS::stack_ends_here being a primary reason
+ for this limitation).
+*/
+#include <my_global.h>
+#include <my_sys.h>
+#include <lf.h>
+
+#define LF_PINBOX_MAX_PINS 65536
+
+static void _lf_pinbox_real_free(LF_PINS *pins);
+
+/*
+ Initialize a pinbox. Normally called from lf_alloc_init.
+ See the latter for details.
+*/
+void lf_pinbox_init(LF_PINBOX *pinbox, uint free_ptr_offset,
+ lf_pinbox_free_func *free_func, void *free_func_arg)
+{
+ DBUG_ASSERT(free_ptr_offset % sizeof(void *) == 0);
+ compile_time_assert(sizeof(LF_PINS) == 128);
+ lf_dynarray_init(&pinbox->pinarray, sizeof(LF_PINS));
+ pinbox->pinstack_top_ver= 0;
+ pinbox->pins_in_array= 0;
+ pinbox->free_ptr_offset= free_ptr_offset;
+ pinbox->free_func= free_func;
+ pinbox->free_func_arg= free_func_arg;
+}
+
+void lf_pinbox_destroy(LF_PINBOX *pinbox)
+{
+ lf_dynarray_destroy(&pinbox->pinarray);
+}
+
+/*
+ Get pins from a pinbox. Usually called via lf_alloc_get_pins() or
+ lf_hash_get_pins().
+
+ SYNOPSYS
+ pinbox -
+
+ DESCRIPTION
+ get a new LF_PINS structure from a stack of unused pins,
+ or allocate a new one out of dynarray.
+
+ NOTE
+ It is assumed that pins belong to a thread and are not transferable
+ between threads.
+*/
+LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
+{
+ uint32 pins, next, top_ver;
+ LF_PINS *el;
+ /*
+ We have an array of max. 64k elements.
+ The highest index currently allocated is pinbox->pins_in_array.
+ Freed elements are in a lifo stack, pinstack_top_ver.
+ pinstack_top_ver is 32 bits; 16 low bits are the index in the
+ array, to the first element of the list. 16 high bits are a version
+ (every time the 16 low bits are updated, the 16 high bits are
+ incremented). Versioniong prevents the ABA problem.
+ */
+ top_ver= pinbox->pinstack_top_ver;
+ do
+ {
+ if (!(pins= top_ver % LF_PINBOX_MAX_PINS))
+ {
+ /* the stack of free elements is empty */
+ pins= my_atomic_add32((int32 volatile*) &pinbox->pins_in_array, 1)+1;
+ if (unlikely(pins >= LF_PINBOX_MAX_PINS))
+ return 0;
+ /*
+ note that the first allocated element has index 1 (pins==1).
+ index 0 is reserved to mean "NULL pointer"
+ */
+ el= (LF_PINS *)_lf_dynarray_lvalue(&pinbox->pinarray, pins);
+ if (unlikely(!el))
+ return 0;
+ break;
+ }
+ el= (LF_PINS *)_lf_dynarray_value(&pinbox->pinarray, pins);
+ next= el->link;
+ } while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
+ (int32*) &top_ver,
+ top_ver-pins+next+LF_PINBOX_MAX_PINS));
+ /*
+ set el->link to the index of el in the dynarray (el->link has two usages:
+ - if element is allocated, it's its own index
+ - if element is free, it's its next element in the free stack
+ */
+ el->link= pins;
+ el->purgatory_count= 0;
+ el->pinbox= pinbox;
+ el->stack_ends_here= & my_thread_var->stack_ends_here;
+ return el;
+}
+
+/*
+ Put pins back to a pinbox. Usually called via lf_alloc_put_pins() or
+ lf_hash_put_pins().
+
+ DESCRIPTION
+ empty the purgatory (XXX deadlock warning below!),
+ push LF_PINS structure to a stack
+*/
+void _lf_pinbox_put_pins(LF_PINS *pins)
+{
+ LF_PINBOX *pinbox= pins->pinbox;
+ uint32 top_ver, nr;
+ nr= pins->link;
+#ifdef MY_LF_EXTRA_DEBUG
+ {
+ int i;
+ for (i= 0; i < LF_PINBOX_PINS; i++)
+ DBUG_ASSERT(pins->pin[i] == 0);
+ }
+#endif
+ /*
+ XXX this will deadlock if other threads will wait for
+ the caller to do something after _lf_pinbox_put_pins(),
+ and they would have pinned addresses that the caller wants to free.
+ Thus: only free pins when all work is done and nobody can wait for you!!!
+ */
+ while (pins->purgatory_count)
+ {
+ _lf_pinbox_real_free(pins);
+ if (pins->purgatory_count)
+ {
+ my_atomic_rwlock_wrunlock(&pins->pinbox->pinarray.lock);
+ pthread_yield();
+ my_atomic_rwlock_wrlock(&pins->pinbox->pinarray.lock);
+ }
+ }
+ top_ver= pinbox->pinstack_top_ver;
+ do
+ {
+ pins->link= top_ver % LF_PINBOX_MAX_PINS;
+ } while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
+ (int32*) &top_ver,
+ top_ver-pins->link+nr+LF_PINBOX_MAX_PINS));
+ return;
+}
+
+static int ptr_cmp(void **a, void **b)
+{
+ return *a < *b ? -1 : *a == *b ? 0 : 1;
+}
+
+#define add_to_purgatory(PINS, ADDR) \
+ do \
+ { \
+ *(void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset)= \
+ (PINS)->purgatory; \
+ (PINS)->purgatory= (ADDR); \
+ (PINS)->purgatory_count++; \
+ } while (0)
+
+/*
+ Free an object allocated via pinbox allocator
+
+ DESCRIPTION
+ add an object to purgatory. if necessary, call _lf_pinbox_real_free()
+ to actually free something.
+*/
+void _lf_pinbox_free(LF_PINS *pins, void *addr)
+{
+ add_to_purgatory(pins, addr);
+ if (pins->purgatory_count % LF_PURGATORY_SIZE)
+ _lf_pinbox_real_free(pins);
+}
+
+struct st_harvester {
+ void **granary;
+ int npins;
+};
+
+/*
+ callback for _lf_dynarray_iterate:
+ scan all pins of all threads and accumulate all pins
+*/
+static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
+{
+ int i;
+ LF_PINS *el_end= el+min(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
+ for (; el < el_end; el++)
+ {
+ for (i= 0; i < LF_PINBOX_PINS; i++)
+ {
+ void *p= el->pin[i];
+ if (p)
+ *hv->granary++= p;
+ }
+ }
+ /*
+ hv->npins may become negative below, but it means that
+ we're on the last dynarray page and harvest_pins() won't be
+ called again. We don't bother to make hv->npins() correct
+ (that is 0) in this case.
+ */
+ hv->npins-= LF_DYNARRAY_LEVEL_LENGTH;
+ return 0;
+}
+
+/*
+ callback for _lf_dynarray_iterate:
+ scan all pins of all threads and see if addr is present there
+*/
+static int match_pins(LF_PINS *el, void *addr)
+{
+ int i;
+ LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
+ for (; el < el_end; el++)
+ for (i= 0; i < LF_PINBOX_PINS; i++)
+ if (el->pin[i] == addr)
+ return 1;
+ return 0;
+}
+
+#if STACK_DIRECTION < 0
+#define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END))
+#else
+#define available_stack_size(CUR,END) (long) ((char*)(END) - (char*)(CUR))
+#endif
+
+#define next_node(P, X) (*((uchar * volatile *)(((uchar *)(X)) + (P)->free_ptr_offset)))
+#define anext_node(X) next_node(&allocator->pinbox, (X))
+
+/*
+ Scan the purgatory and free everything that can be freed
+*/
+static void _lf_pinbox_real_free(LF_PINS *pins)
+{
+ int npins, alloca_size;
+ void *list, **addr;
+ void *first, *last= NULL;
+ LF_PINBOX *pinbox= pins->pinbox;
+
+ LINT_INIT(first);
+ npins= pinbox->pins_in_array+1;
+
+#ifdef HAVE_ALLOCA
+ alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
+ /* create a sorted list of pinned addresses, to speed up searches */
+ if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size)
+ {
+ struct st_harvester hv;
+ addr= (void **) alloca(alloca_size);
+ hv.granary= addr;
+ hv.npins= npins;
+ /* scan the dynarray and accumulate all pinned addresses */
+ _lf_dynarray_iterate(&pinbox->pinarray,
+ (lf_dynarray_func)harvest_pins, &hv);
+
+ npins= hv.granary-addr;
+ /* and sort them */
+ if (npins)
+ qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
+ }
+ else
+#endif
+ addr= 0;
+
+ list= pins->purgatory;
+ pins->purgatory= 0;
+ pins->purgatory_count= 0;
+ while (list)
+ {
+ void *cur= list;
+ list= *(void **)((char *)cur+pinbox->free_ptr_offset);
+ if (npins)
+ {
+ if (addr) /* use binary search */
+ {
+ void **a, **b, **c;
+ for (a= addr, b= addr+npins-1, c= a+(b-a)/2; (b-a) > 1; c= a+(b-a)/2)
+ if (cur == *c)
+ a= b= c;
+ else if (cur > *c)
+ a= c;
+ else
+ b= c;
+ if (cur == *a || cur == *b)
+ goto found;
+ }
+ else /* no alloca - no cookie. linear search here */
+ {
+ if (_lf_dynarray_iterate(&pinbox->pinarray,
+ (lf_dynarray_func)match_pins, cur))
+ goto found;
+ }
+ }
+ /* not pinned - freeing */
+ if (last)
+ last= next_node(pinbox, last)= (uchar *)cur;
+ else
+ first= last= (uchar *)cur;
+ continue;
+found:
+ /* pinned - keeping */
+ add_to_purgatory(pins, cur);
+ }
+ if (last)
+ pinbox->free_func(first, last, pinbox->free_func_arg);
+}
+
+/* lock-free memory allocator for fixed-size objects */
+
+LF_REQUIRE_PINS(1)
+
+/*
+ callback for _lf_pinbox_real_free to free a list of unpinned objects -
+ add it back to the allocator stack
+
+ DESCRIPTION
+ 'first' and 'last' are the ends of the linked list of nodes:
+ first->el->el->....->el->last. Use first==last to free only one element.
+*/
+static void alloc_free(uchar *first,
+ uchar volatile *last,
+ LF_ALLOCATOR *allocator)
+{
+ /*
+ we need a union here to access type-punned pointer reliably.
+ otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop
+ */
+ union { uchar * node; void *ptr; } tmp;
+ tmp.node= allocator->top;
+ do
+ {
+ anext_node(last)= tmp.node;
+ } while (!my_atomic_casptr((void **)(char *)&allocator->top,
+ (void **)&tmp.ptr, first) && LF_BACKOFF);
+}
+
+/*
+ initialize lock-free allocator
+
+ SYNOPSYS
+ allocator -
+ size a size of an object to allocate
+ free_ptr_offset an offset inside the object to a sizeof(void *)
+ memory that is guaranteed to be unused after
+ the object is put in the purgatory. Unused by ANY
+ thread, not only the purgatory owner.
+ This memory will be used to link waiting-to-be-freed
+ objects in a purgatory list.
+*/
+void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset)
+{
+ lf_pinbox_init(&allocator->pinbox, free_ptr_offset,
+ (lf_pinbox_free_func *)alloc_free, allocator);
+ allocator->top= 0;
+ allocator->mallocs= 0;
+ allocator->element_size= size;
+ allocator->constructor= 0;
+ allocator->destructor= 0;
+ DBUG_ASSERT(size >= sizeof(void*) + free_ptr_offset);
+}
+
+/*
+ destroy the allocator, free everything that's in it
+
+ NOTE
+ As every other init/destroy function here and elsewhere it
+ is not thread safe. No, this function is no different, ensure
+ that no thread needs the allocator before destroying it.
+ We are not responsible for any damage that may be caused by
+ accessing the allocator when it is being or has been destroyed.
+ Oh yes, and don't put your cat in a microwave.
+*/
+void lf_alloc_destroy(LF_ALLOCATOR *allocator)
+{
+ uchar *node= allocator->top;
+ while (node)
+ {
+ uchar *tmp= anext_node(node);
+ if (allocator->destructor)
+ allocator->destructor(node);
+ my_free((void *)node, MYF(0));
+ node= tmp;
+ }
+ lf_pinbox_destroy(&allocator->pinbox);
+ allocator->top= 0;
+}
+
+/*
+ Allocate and return an new object.
+
+ DESCRIPTION
+ Pop an unused object from the stack or malloc it is the stack is empty.
+ pin[0] is used, it's removed on return.
+*/
+void *_lf_alloc_new(LF_PINS *pins)
+{
+ LF_ALLOCATOR *allocator= (LF_ALLOCATOR *)(pins->pinbox->free_func_arg);
+ uchar *node;
+ for (;;)
+ {
+ do
+ {
+ node= allocator->top;
+ _lf_pin(pins, 0, node);
+ } while (node != allocator->top && LF_BACKOFF);
+ if (!node)
+ {
+ node= (void *)my_malloc(allocator->element_size, MYF(MY_WME));
+ if (allocator->constructor)
+ allocator->constructor(node);
+#ifdef MY_LF_EXTRA_DEBUG
+ if (likely(node != 0))
+ my_atomic_add32(&allocator->mallocs, 1);
+#endif
+ break;
+ }
+ if (my_atomic_casptr((void **)(char *)&allocator->top,
+ (void *)&node, anext_node(node)))
+ break;
+ }
+ _lf_unpin(pins, 0);
+ return node;
+}
+
+/*
+ count the number of objects in a pool.
+
+ NOTE
+ This is NOT thread-safe !!!
+*/
+uint lf_alloc_pool_count(LF_ALLOCATOR *allocator)
+{
+ uint i;
+ uchar *node;
+ for (node= allocator->top, i= 0; node; node= anext_node(node), i++)
+ /* no op */;
+ return i;
+}
+
diff --git a/mysys/lf_dynarray.c b/mysys/lf_dynarray.c
new file mode 100644
index 00000000000..7c8f54f07cf
--- /dev/null
+++ b/mysys/lf_dynarray.c
@@ -0,0 +1,208 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Analog of DYNAMIC_ARRAY that never reallocs
+ (so no pointer into the array may ever become invalid).
+
+ Memory is allocated in non-contiguous chunks.
+ This data structure is not space efficient for sparse arrays.
+
+ Every element is aligned to sizeof(element) boundary
+ (to avoid false sharing if element is big enough).
+
+ LF_DYNARRAY is a recursive structure. On the zero level
+ LF_DYNARRAY::level[0] it's an array of LF_DYNARRAY_LEVEL_LENGTH elements,
+ on the first level it's an array of LF_DYNARRAY_LEVEL_LENGTH pointers
+ to arrays of elements, on the second level it's an array of pointers
+ to arrays of pointers to arrays of elements. And so on.
+
+ With four levels the number of elements is limited to 4311810304
+ (but as in all functions index is uint, the real limit is 2^32-1)
+
+ Actually, it's wait-free, not lock-free ;-)
+*/
+
+#include <my_global.h>
+#include <m_string.h>
+#include <my_sys.h>
+#include <lf.h>
+
+void lf_dynarray_init(LF_DYNARRAY *array, uint element_size)
+{
+ bzero(array, sizeof(*array));
+ array->size_of_element= element_size;
+ my_atomic_rwlock_init(&array->lock);
+}
+
+static void recursive_free(void **alloc, int level)
+{
+ if (!alloc)
+ return;
+
+ if (level)
+ {
+ int i;
+ for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
+ recursive_free(alloc[i], level-1);
+ my_free((void *)alloc, MYF(0));
+ }
+ else
+ my_free(alloc[-1], MYF(0));
+}
+
+void lf_dynarray_destroy(LF_DYNARRAY *array)
+{
+ int i;
+ for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
+ recursive_free(array->level[i], i);
+ my_atomic_rwlock_destroy(&array->lock);
+}
+
+static const ulong dynarray_idxes_in_prev_levels[LF_DYNARRAY_LEVELS]=
+{
+ 0, /* +1 here to to avoid -1's below */
+ LF_DYNARRAY_LEVEL_LENGTH,
+ LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH +
+ LF_DYNARRAY_LEVEL_LENGTH,
+ LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
+ LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH *
+ LF_DYNARRAY_LEVEL_LENGTH + LF_DYNARRAY_LEVEL_LENGTH
+};
+
+static const ulong dynarray_idxes_in_prev_level[LF_DYNARRAY_LEVELS]=
+{
+ 0, /* +1 here to to avoid -1's below */
+ LF_DYNARRAY_LEVEL_LENGTH,
+ LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH,
+ LF_DYNARRAY_LEVEL_LENGTH * LF_DYNARRAY_LEVEL_LENGTH *
+ LF_DYNARRAY_LEVEL_LENGTH,
+};
+
+/*
+ Returns a valid lvalue pointer to the element number 'idx'.
+ Allocates memory if necessary.
+*/
+void *_lf_dynarray_lvalue(LF_DYNARRAY *array, uint idx)
+{
+ void * ptr, * volatile * ptr_ptr= 0;
+ int i;
+
+ for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
+ /* no-op */;
+ ptr_ptr= &array->level[i];
+ idx-= dynarray_idxes_in_prev_levels[i];
+ for (; i > 0; i--)
+ {
+ if (!(ptr= *ptr_ptr))
+ {
+ void *alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * sizeof(void *),
+ MYF(MY_WME|MY_ZEROFILL));
+ if (unlikely(!alloc))
+ return(NULL);
+ if (my_atomic_casptr(ptr_ptr, &ptr, alloc))
+ ptr= alloc;
+ else
+ my_free(alloc, MYF(0));
+ }
+ ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
+ idx%= dynarray_idxes_in_prev_level[i];
+ }
+ if (!(ptr= *ptr_ptr))
+ {
+ uchar *alloc, *data;
+ alloc= my_malloc(LF_DYNARRAY_LEVEL_LENGTH * array->size_of_element +
+ max(array->size_of_element, sizeof(void *)),
+ MYF(MY_WME|MY_ZEROFILL));
+ if (unlikely(!alloc))
+ return(NULL);
+ /* reserve the space for free() address */
+ data= alloc + sizeof(void *);
+ { /* alignment */
+ intptr mod= ((intptr)data) % array->size_of_element;
+ if (mod)
+ data+= array->size_of_element - mod;
+ }
+ ((void **)data)[-1]= alloc; /* free() will need the original pointer */
+ if (my_atomic_casptr(ptr_ptr, &ptr, data))
+ ptr= data;
+ else
+ my_free(alloc, MYF(0));
+ }
+ return ((uchar*)ptr) + array->size_of_element * idx;
+}
+
+/*
+ Returns a pointer to the element number 'idx'
+ or NULL if an element does not exists
+*/
+void *_lf_dynarray_value(LF_DYNARRAY *array, uint idx)
+{
+ void * ptr, * volatile * ptr_ptr= 0;
+ int i;
+
+ for (i= LF_DYNARRAY_LEVELS-1; idx < dynarray_idxes_in_prev_levels[i]; i--)
+ /* no-op */;
+ ptr_ptr= &array->level[i];
+ idx-= dynarray_idxes_in_prev_levels[i];
+ for (; i > 0; i--)
+ {
+ if (!(ptr= *ptr_ptr))
+ return(NULL);
+ ptr_ptr= ((void **)ptr) + idx / dynarray_idxes_in_prev_level[i];
+ idx %= dynarray_idxes_in_prev_level[i];
+ }
+ if (!(ptr= *ptr_ptr))
+ return(NULL);
+ return ((uchar*)ptr) + array->size_of_element * idx;
+}
+
+static int recursive_iterate(LF_DYNARRAY *array, void *ptr, int level,
+ lf_dynarray_func func, void *arg)
+{
+ int res, i;
+ if (!ptr)
+ return 0;
+ if (!level)
+ return func(ptr, arg);
+ for (i= 0; i < LF_DYNARRAY_LEVEL_LENGTH; i++)
+ if ((res= recursive_iterate(array, ((void **)ptr)[i], level-1, func, arg)))
+ return res;
+ return 0;
+}
+
+/*
+ Calls func(array, arg) on every array of LF_DYNARRAY_LEVEL_LENGTH elements
+ in lf_dynarray.
+
+ DESCRIPTION
+ lf_dynarray consists of a set of arrays, LF_DYNARRAY_LEVEL_LENGTH elements
+ each. _lf_dynarray_iterate() calls user-supplied function on every array
+ from the set. It is the fastest way to scan the array, faster than
+ for (i=0; i < N; i++) { func(_lf_dynarray_value(dynarray, i)); }
+
+ NOTE
+ if func() returns non-zero, the scan is aborted
+*/
+int _lf_dynarray_iterate(LF_DYNARRAY *array, lf_dynarray_func func, void *arg)
+{
+ int i, res;
+ for (i= 0; i < LF_DYNARRAY_LEVELS; i++)
+ if ((res= recursive_iterate(array, array->level[i], i, func, arg)))
+ return res;
+ return 0;
+}
+
diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c
new file mode 100644
index 00000000000..ce7056af995
--- /dev/null
+++ b/mysys/lf_hash.c
@@ -0,0 +1,506 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ extensible hash
+
+ TODO
+ try to get rid of dummy nodes ?
+ for non-unique hash, count only _distinct_ values
+ (but how to do it in lf_hash_delete ?)
+*/
+#include <my_global.h>
+#include <m_string.h>
+#include <my_sys.h>
+#include <my_bit.h>
+#include <lf.h>
+
+LF_REQUIRE_PINS(3)
+
+/* An element of the list */
+typedef struct {
+ intptr volatile link; /* a pointer to the next element in a listand a flag */
+ uint32 hashnr; /* reversed hash number, for sorting */
+ const uchar *key;
+ size_t keylen;
+ /*
+ data is stored here, directly after the keylen.
+ thus the pointer to data is (void*)(slist_element_ptr+1)
+ */
+} LF_SLIST;
+
+const int LF_HASH_OVERHEAD= sizeof(LF_SLIST);
+
+/*
+ a structure to pass the context (pointers two the three successive elements
+ in a list) from lfind to linsert/ldelete
+*/
+typedef struct {
+ intptr volatile *prev;
+ LF_SLIST *curr, *next;
+} CURSOR;
+
+/*
+ the last bit in LF_SLIST::link is a "deleted" flag.
+ the helper macros below convert it to a pure pointer or a pure flag
+*/
+#define PTR(V) (LF_SLIST *)((V) & (~(intptr)1))
+#define DELETED(V) ((V) & 1)
+
+/*
+ DESCRIPTION
+ Search for hashnr/key/keylen in the list starting from 'head' and
+ position the cursor. The list is ORDER BY hashnr, key
+
+ RETURN
+ 0 - not found
+ 1 - found
+
+ NOTE
+ cursor is positioned in either case
+ pins[0..2] are used, they are NOT removed on return
+*/
+static int lfind(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
+ const uchar *key, uint keylen, CURSOR *cursor, LF_PINS *pins)
+{
+ uint32 cur_hashnr;
+ const uchar *cur_key;
+ uint cur_keylen;
+ intptr link;
+
+retry:
+ cursor->prev= (intptr *)head;
+ do { /* PTR() isn't necessary below, head is a dummy node */
+ cursor->curr= (LF_SLIST *)(*cursor->prev);
+ _lf_pin(pins, 1, cursor->curr);
+ } while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
+ for (;;)
+ {
+ if (unlikely(!cursor->curr))
+ return 0; /* end of the list */
+ do {
+ /* QQ: XXX or goto retry ? */
+ link= cursor->curr->link;
+ cursor->next= PTR(link);
+ _lf_pin(pins, 0, cursor->next);
+ } while (link != cursor->curr->link && LF_BACKOFF);
+ cur_hashnr= cursor->curr->hashnr;
+ cur_key= cursor->curr->key;
+ cur_keylen= cursor->curr->keylen;
+ if (*cursor->prev != (intptr)cursor->curr)
+ {
+ (void)LF_BACKOFF;
+ goto retry;
+ }
+ if (!DELETED(link))
+ {
+ if (cur_hashnr >= hashnr)
+ {
+ int r= 1;
+ if (cur_hashnr > hashnr ||
+ (r= my_strnncoll(cs, (uchar*) cur_key, cur_keylen, (uchar*) key,
+ keylen)) >= 0)
+ return !r;
+ }
+ cursor->prev= &(cursor->curr->link);
+ _lf_pin(pins, 2, cursor->curr);
+ }
+ else
+ {
+ /*
+ we found a deleted node - be nice, help the other thread
+ and remove this deleted node
+ */
+ if (my_atomic_casptr((void **)cursor->prev,
+ (void **)&cursor->curr, cursor->next))
+ _lf_alloc_free(pins, cursor->curr);
+ else
+ {
+ (void)LF_BACKOFF;
+ goto retry;
+ }
+ }
+ cursor->curr= cursor->next;
+ _lf_pin(pins, 1, cursor->curr);
+ }
+}
+
+/*
+ DESCRIPTION
+ insert a 'node' in the list that starts from 'head' in the correct
+ position (as found by lfind)
+
+ RETURN
+ 0 - inserted
+ not 0 - a pointer to a duplicate (not pinned and thus unusable)
+
+ NOTE
+ it uses pins[0..2], on return all pins are removed.
+ if there're nodes with the same key value, a new node is added before them.
+*/
+static LF_SLIST *linsert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
+ LF_SLIST *node, LF_PINS *pins, uint flags)
+{
+ CURSOR cursor;
+ int res;
+
+ for (;;)
+ {
+ if (lfind(head, cs, node->hashnr, node->key, node->keylen,
+ &cursor, pins) &&
+ (flags & LF_HASH_UNIQUE))
+ {
+ res= 0; /* duplicate found */
+ break;
+ }
+ else
+ {
+ node->link= (intptr)cursor.curr;
+ DBUG_ASSERT(node->link != (intptr)node); /* no circular references */
+ DBUG_ASSERT(cursor.prev != &node->link); /* no circular references */
+ if (my_atomic_casptr((void **)cursor.prev, (void **)&cursor.curr, node))
+ {
+ res= 1; /* inserted ok */
+ break;
+ }
+ }
+ }
+ _lf_unpin(pins, 0);
+ _lf_unpin(pins, 1);
+ _lf_unpin(pins, 2);
+ /*
+ Note that cursor.curr is not pinned here and the pointer is unreliable,
+ the object may dissapear anytime. But if it points to a dummy node, the
+ pointer is safe, because dummy nodes are never freed - initialize_bucket()
+ uses this fact.
+ */
+ return res ? 0 : cursor.curr;
+}
+
+/*
+ DESCRIPTION
+ deletes a node as identified by hashnr/keey/keylen from the list
+ that starts from 'head'
+
+ RETURN
+ 0 - ok
+ 1 - not found
+
+ NOTE
+ it uses pins[0..2], on return all pins are removed.
+*/
+static int ldelete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
+ const uchar *key, uint keylen, LF_PINS *pins)
+{
+ CURSOR cursor;
+ int res;
+
+ for (;;)
+ {
+ if (!lfind(head, cs, hashnr, key, keylen, &cursor, pins))
+ {
+ res= 1; /* not found */
+ break;
+ }
+ else
+ {
+ /* mark the node deleted */
+ if (my_atomic_casptr((void **)&(cursor.curr->link),
+ (void **)&cursor.next,
+ (void *)(((intptr)cursor.next) | 1)))
+ {
+ /* and remove it from the list */
+ if (my_atomic_casptr((void **)cursor.prev,
+ (void **)&cursor.curr, cursor.next))
+ _lf_alloc_free(pins, cursor.curr);
+ else
+ {
+ /*
+ somebody already "helped" us and removed the node ?
+ Let's check if we need to help that someone too!
+ (to ensure the number of "set DELETED flag" actions
+ is equal to the number of "remove from the list" actions)
+ */
+ lfind(head, cs, hashnr, key, keylen, &cursor, pins);
+ }
+ res= 0;
+ break;
+ }
+ }
+ }
+ _lf_unpin(pins, 0);
+ _lf_unpin(pins, 1);
+ _lf_unpin(pins, 2);
+ return res;
+}
+
+/*
+ DESCRIPTION
+ searches for a node as identified by hashnr/keey/keylen in the list
+ that starts from 'head'
+
+ RETURN
+ 0 - not found
+ node - found
+
+ NOTE
+ it uses pins[0..2], on return the pin[2] keeps the node found
+ all other pins are removed.
+*/
+static LF_SLIST *lsearch(LF_SLIST * volatile *head, CHARSET_INFO *cs,
+ uint32 hashnr, const uchar *key, uint keylen,
+ LF_PINS *pins)
+{
+ CURSOR cursor;
+ int res= lfind(head, cs, hashnr, key, keylen, &cursor, pins);
+ if (res)
+ _lf_pin(pins, 2, cursor.curr);
+ _lf_unpin(pins, 0);
+ _lf_unpin(pins, 1);
+ return res ? cursor.curr : 0;
+}
+
+static inline const uchar* hash_key(const LF_HASH *hash,
+ const uchar *record, size_t *length)
+{
+ if (hash->get_key)
+ return (*hash->get_key)(record, length, 0);
+ *length= hash->key_length;
+ return record + hash->key_offset;
+}
+
+/*
+ Compute the hash key value from the raw key.
+
+ @note, that the hash value is limited to 2^31, because we need one
+ bit to distinguish between normal and dummy nodes.
+*/
+static inline uint calc_hash(LF_HASH *hash, const uchar *key, uint keylen)
+{
+ ulong nr1= 1, nr2= 4;
+ hash->charset->coll->hash_sort(hash->charset, (uchar*) key, keylen,
+ &nr1, &nr2);
+ return nr1 & INT_MAX32;
+}
+
+#define MAX_LOAD 1.0 /* average number of elements in a bucket */
+
+static int initialize_bucket(LF_HASH *, LF_SLIST * volatile*, uint, LF_PINS *);
+
+/*
+ Initializes lf_hash, the arguments are compatible with hash_init
+
+ @note element_size sets both the size of allocated memory block for
+ lf_alloc and a size of memcpy'ed block size in lf_hash_insert. Typically
+ they are the same, indeed. But LF_HASH::element_size can be decreased
+ after lf_hash_init, and then lf_alloc will allocate larger block that
+ lf_hash_insert will copy over. It is desireable if part of the element
+ is expensive to initialize - for example if there is a mutex or
+ DYNAMIC_ARRAY. In this case they should be initialize in the
+ LF_ALLOCATOR::constructor, and lf_hash_insert should not overwrite them.
+ See wt_init() for example.
+*/
+void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
+ uint key_offset, uint key_length, hash_get_key get_key,
+ CHARSET_INFO *charset)
+{
+ lf_alloc_init(&hash->alloc, sizeof(LF_SLIST)+element_size,
+ offsetof(LF_SLIST, key));
+ lf_dynarray_init(&hash->array, sizeof(LF_SLIST *));
+ hash->size= 1;
+ hash->count= 0;
+ hash->element_size= element_size;
+ hash->flags= flags;
+ hash->charset= charset ? charset : &my_charset_bin;
+ hash->key_offset= key_offset;
+ hash->key_length= key_length;
+ hash->get_key= get_key;
+ DBUG_ASSERT(get_key ? !key_offset && !key_length : key_length);
+}
+
+void lf_hash_destroy(LF_HASH *hash)
+{
+ LF_SLIST *el, **head= (LF_SLIST **)_lf_dynarray_value(&hash->array, 0);
+
+ if (unlikely(!head))
+ return;
+ el= *head;
+
+ while (el)
+ {
+ intptr next= el->link;
+ if (el->hashnr & 1)
+ lf_alloc_direct_free(&hash->alloc, el); /* normal node */
+ else
+ my_free((void *)el, MYF(0)); /* dummy node */
+ el= (LF_SLIST *)next;
+ }
+ lf_alloc_destroy(&hash->alloc);
+ lf_dynarray_destroy(&hash->array);
+}
+
+/*
+ DESCRIPTION
+ inserts a new element to a hash. it will have a _copy_ of
+ data, not a pointer to it.
+
+ RETURN
+ 0 - inserted
+ 1 - didn't (unique key conflict)
+ -1 - out of memory
+
+ NOTE
+ see linsert() for pin usage notes
+*/
+int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data)
+{
+ int csize, bucket, hashnr;
+ LF_SLIST *node, * volatile *el;
+
+ lf_rwlock_by_pins(pins);
+ node= (LF_SLIST *)_lf_alloc_new(pins);
+ if (unlikely(!node))
+ return -1;
+ memcpy(node+1, data, hash->element_size);
+ node->key= hash_key(hash, (uchar *)(node+1), &node->keylen);
+ hashnr= calc_hash(hash, node->key, node->keylen);
+ bucket= hashnr % hash->size;
+ el= _lf_dynarray_lvalue(&hash->array, bucket);
+ if (unlikely(!el))
+ return -1;
+ if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
+ return -1;
+ node->hashnr= my_reverse_bits(hashnr) | 1; /* normal node */
+ if (linsert(el, hash->charset, node, pins, hash->flags))
+ {
+ _lf_alloc_free(pins, node);
+ lf_rwunlock_by_pins(pins);
+ return 1;
+ }
+ csize= hash->size;
+ if ((my_atomic_add32(&hash->count, 1)+1.0) / csize > MAX_LOAD)
+ my_atomic_cas32(&hash->size, &csize, csize*2);
+ lf_rwunlock_by_pins(pins);
+ return 0;
+}
+
+/*
+ DESCRIPTION
+ deletes an element with the given key from the hash (if a hash is
+ not unique and there're many elements with this key - the "first"
+ matching element is deleted)
+ RETURN
+ 0 - deleted
+ 1 - didn't (not found)
+ -1 - out of memory
+ NOTE
+ see ldelete() for pin usage notes
+*/
+int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
+{
+ LF_SLIST * volatile *el;
+ uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
+
+ bucket= hashnr % hash->size;
+ lf_rwlock_by_pins(pins);
+ el= _lf_dynarray_lvalue(&hash->array, bucket);
+ if (unlikely(!el))
+ return -1;
+ /*
+ note that we still need to initialize_bucket here,
+ we cannot return "node not found", because an old bucket of that
+ node may've been split and the node was assigned to a new bucket
+ that was never accessed before and thus is not initialized.
+ */
+ if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
+ return -1;
+ if (ldelete(el, hash->charset, my_reverse_bits(hashnr) | 1,
+ (uchar *)key, keylen, pins))
+ {
+ lf_rwunlock_by_pins(pins);
+ return 1;
+ }
+ my_atomic_add32(&hash->count, -1);
+ lf_rwunlock_by_pins(pins);
+ return 0;
+}
+
+/*
+ RETURN
+ a pointer to an element with the given key (if a hash is not unique and
+ there're many elements with this key - the "first" matching element)
+ NULL if nothing is found
+ MY_ERRPTR if OOM
+
+ NOTE
+ see lsearch() for pin usage notes
+*/
+void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
+{
+ LF_SLIST * volatile *el, *found;
+ uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
+
+ bucket= hashnr % hash->size;
+ lf_rwlock_by_pins(pins);
+ el= _lf_dynarray_lvalue(&hash->array, bucket);
+ if (unlikely(!el))
+ return MY_ERRPTR;
+ if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
+ return MY_ERRPTR;
+ found= lsearch(el, hash->charset, my_reverse_bits(hashnr) | 1,
+ (uchar *)key, keylen, pins);
+ lf_rwunlock_by_pins(pins);
+ return found ? found+1 : 0;
+}
+
+static const uchar *dummy_key= (uchar*)"";
+
+/*
+ RETURN
+ 0 - ok
+ -1 - out of memory
+*/
+static int initialize_bucket(LF_HASH *hash, LF_SLIST * volatile *node,
+ uint bucket, LF_PINS *pins)
+{
+ uint parent= my_clear_highest_bit(bucket);
+ LF_SLIST *dummy= (LF_SLIST *)my_malloc(sizeof(LF_SLIST), MYF(MY_WME));
+ LF_SLIST **tmp= 0, *cur;
+ LF_SLIST * volatile *el= _lf_dynarray_lvalue(&hash->array, parent);
+ if (unlikely(!el || !dummy))
+ return -1;
+ if (*el == NULL && bucket &&
+ unlikely(initialize_bucket(hash, el, parent, pins)))
+ return -1;
+ dummy->hashnr= my_reverse_bits(bucket) | 0; /* dummy node */
+ dummy->key= dummy_key;
+ dummy->keylen= 0;
+ if ((cur= linsert(el, hash->charset, dummy, pins, LF_HASH_UNIQUE)))
+ {
+ my_free((void *)dummy, MYF(0));
+ dummy= cur;
+ }
+ my_atomic_casptr((void **)node, (void **)&tmp, dummy);
+ /*
+ note that if the CAS above failed (after linsert() succeeded),
+ it would mean that some other thread has executed linsert() for
+ the same dummy node, its linsert() failed, it picked up our
+ dummy node (in "dummy= cur") and executed the same CAS as above.
+ Which means that even if CAS above failed we don't need to retry,
+ and we should not free(dummy) - there's no memory leak here
+ */
+ return 0;
+}
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
index 0f49dd22bb9..6d63f8b8bf5 100644
--- a/mysys/mf_iocache.c
+++ b/mysys/mf_iocache.c
@@ -527,7 +527,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count)
{
if (Count)
{
- info->error= left_length; /* We only got this many char */
+ info->error= (int) left_length; /* We only got this many char */
DBUG_RETURN(1);
}
length=0; /* Didn't read any chars */
@@ -1255,7 +1255,7 @@ read_append_buffer:
info->append_read_pos += copy_len;
Count -= copy_len;
if (Count)
- info->error = save_count - Count;
+ info->error= (int) (save_count - Count);
/* Fill read buffer with data from write buffer */
memcpy(info->buffer, info->append_read_pos,
@@ -1644,8 +1644,8 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count,
{
/* Of no overlap, write everything without buffering */
if (pos + Count <= info->pos_in_file)
- return my_pwrite(info->file, Buffer, Count, pos,
- info->myflags | MY_NABP);
+ return (int) my_pwrite(info->file, Buffer, Count, pos,
+ info->myflags | MY_NABP);
/* Write the part of the block that is before buffer */
length= (uint) (info->pos_in_file - pos);
if (my_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP))
@@ -1834,6 +1834,9 @@ int end_io_cache(IO_CACHE *info)
pthread_mutex_destroy(&info->append_buffer_lock);
#endif
}
+#ifdef THREAD
+ info->share= 0;
+#endif
DBUG_RETURN(error);
} /* end_io_cache */
diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c
index c54c7d13548..728501e6c50 100644
--- a/mysys/mf_iocache2.c
+++ b/mysys/mf_iocache2.c
@@ -420,9 +420,9 @@ process_flags:
/* minimum width padding */
if (minimum_width > length2)
{
- char *buffz;
+ uchar *buffz;
- buffz= my_alloca(minimum_width - length2);
+ buffz= (uchar*) my_alloca(minimum_width - length2);
if (is_zero_padded)
memset(buffz, '0', minimum_width - length2);
else
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
index 7cbd35580f1..81066a51f7b 100644
--- a/mysys/mf_keycache.c
+++ b/mysys/mf_keycache.c
@@ -2569,7 +2569,7 @@ uchar *key_cache_read(KEY_CACHE *keycache,
do
{
/* Cache could be disabled in a later iteration. */
-
+
if (!keycache->can_be_used)
goto no_key_cache;
/* Start reading at the beginning of the cache block. */
@@ -3174,7 +3174,7 @@ int key_cache_write(KEY_CACHE *keycache,
if (!dont_write)
{
- /* Not used in the server. buff has been written to disk at start. */
+ /* Not used in the server. buff has been written to disk at start. */
if ((block->status & BLOCK_CHANGED) &&
(!offset && read_length >= keycache->key_cache_block_size))
link_to_file_list(keycache, block, block->hash_link->file, 1);
@@ -3558,10 +3558,11 @@ static int flush_key_blocks_int(KEY_CACHE *keycache,
file, keycache->blocks_used, keycache->blocks_changed));
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
- DBUG_EXECUTE("check_keycache",
- test_key_cache(keycache, "start of flush_key_blocks", 0););
+ DBUG_EXECUTE("check_keycache",
+ test_key_cache(keycache, "start of flush_key_blocks", 0););
#endif
+ DBUG_ASSERT(type != FLUSH_KEEP_LAZY);
cache= cache_buff;
if (keycache->disk_blocks > 0 &&
(!my_disable_flush_key_blocks || type != FLUSH_KEEP))
diff --git a/mysys/mf_keycaches.c b/mysys/mf_keycaches.c
index 6227a05ce06..9ea5678da9a 100644
--- a/mysys/mf_keycaches.c
+++ b/mysys/mf_keycaches.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (C) 2003-2007 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,269 +25,7 @@
#include <keycache.h>
#include <hash.h>
#include <m_string.h>
-
-/*****************************************************************************
- General functions to handle SAFE_HASH objects.
-
- A SAFE_HASH object is used to store the hash, the mutex and default value
- needed by the rest of the key cache code.
- This is a separate struct to make it easy to later reuse the code for other
- purposes
-
- All entries are linked in a list to allow us to traverse all elements
- and delete selected ones. (HASH doesn't allow any easy ways to do this).
-*****************************************************************************/
-
-/*
- Struct to store a key and pointer to object
-*/
-
-typedef struct st_safe_hash_entry
-{
- uchar *key;
- uint length;
- uchar *data;
- struct st_safe_hash_entry *next, **prev;
-} SAFE_HASH_ENTRY;
-
-
-typedef struct st_safe_hash_with_default
-{
-#ifdef THREAD
- rw_lock_t mutex;
-#endif
- HASH hash;
- uchar *default_value;
- SAFE_HASH_ENTRY *root;
-} SAFE_HASH;
-
-
-/*
- Free a SAFE_HASH_ENTRY
-
- This function is called by the hash object on delete
-*/
-
-static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
-{
- DBUG_ENTER("free_assign_entry");
- my_free((uchar*) entry, MYF(0));
- DBUG_VOID_RETURN;
-}
-
-
-/* Get key and length for a SAFE_HASH_ENTRY */
-
-static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=entry->length;
- return (uchar*) entry->key;
-}
-
-
-/*
- Init a SAFE_HASH object
-
- SYNOPSIS
- safe_hash_init()
- hash safe_hash handler
- elements Expected max number of elements
- default_value default value
-
- NOTES
- In case of error we set hash->default_value to 0 to allow one to call
- safe_hash_free on an object that couldn't be initialized.
-
- RETURN
- 0 ok
- 1 error
-*/
-
-static my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
- uchar *default_value)
-{
- DBUG_ENTER("safe_hash");
- if (hash_init(&hash->hash, &my_charset_bin, elements,
- 0, 0, (hash_get_key) safe_hash_entry_get,
- (void (*)(void*)) safe_hash_entry_free, 0))
- {
- hash->default_value= 0;
- DBUG_RETURN(1);
- }
- my_rwlock_init(&hash->mutex, 0);
- hash->default_value= default_value;
- hash->root= 0;
- DBUG_RETURN(0);
-}
-
-
-/*
- Free a SAFE_HASH object
-
- NOTES
- This is safe to call on any object that has been sent to safe_hash_init()
-*/
-
-static void safe_hash_free(SAFE_HASH *hash)
-{
- /*
- Test if safe_hash_init succeeded. This will also guard us against multiple
- free calls.
- */
- if (hash->default_value)
- {
- hash_free(&hash->hash);
- rwlock_destroy(&hash->mutex);
- hash->default_value=0;
- }
-}
-
-/*
- Return the value stored for a key or default value if no key
-*/
-
-static uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length)
-{
- uchar *result;
- DBUG_ENTER("safe_hash_search");
- rw_rdlock(&hash->mutex);
- result= hash_search(&hash->hash, key, length);
- rw_unlock(&hash->mutex);
- if (!result)
- result= hash->default_value;
- else
- result= ((SAFE_HASH_ENTRY*) result)->data;
- DBUG_PRINT("exit",("data: 0x%lx", (long) result));
- DBUG_RETURN(result);
-}
-
-
-/*
- Associate a key with some data
-
- SYONOPSIS
- safe_hash_set()
- hash Hash handle
- key key (path to table etc..)
- length Length of key
- data data to to associate with the data
-
- NOTES
- This can be used both to insert a new entry and change an existing
- entry.
- If one associates a key with the default key cache, the key is deleted
-
- RETURN
- 0 ok
- 1 error (Can only be EOM). In this case my_message() is called.
-*/
-
-static my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
- uchar *data)
-{
- SAFE_HASH_ENTRY *entry;
- my_bool error= 0;
- DBUG_ENTER("safe_hash_set");
- DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
-
- rw_wrlock(&hash->mutex);
- entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
-
- if (data == hash->default_value)
- {
- /*
- The key is to be associated with the default entry. In this case
- we can just delete the entry (if it existed) from the hash as a
- search will return the default entry
- */
- if (!entry) /* nothing to do */
- goto end;
- /* unlink entry from list */
- if ((*entry->prev= entry->next))
- entry->next->prev= entry->prev;
- hash_delete(&hash->hash, (uchar*) entry);
- goto end;
- }
- if (entry)
- {
- /* Entry existed; Just change the pointer to point at the new data */
- entry->data= data;
- }
- else
- {
- if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
- MYF(MY_WME))))
- {
- error= 1;
- goto end;
- }
- entry->key= (uchar*) (entry +1);
- memcpy((char*) entry->key, (char*) key, length);
- entry->length= length;
- entry->data= data;
- /* Link entry to list */
- if ((entry->next= hash->root))
- entry->next->prev= &entry->next;
- entry->prev= &hash->root;
- hash->root= entry;
- if (my_hash_insert(&hash->hash, (uchar*) entry))
- {
- /* This can only happen if hash got out of memory */
- my_free((char*) entry, MYF(0));
- error= 1;
- goto end;
- }
- }
-
-end:
- rw_unlock(&hash->mutex);
- DBUG_RETURN(error);
-}
-
-
-/*
- Change all entres with one data value to another data value
-
- SYONOPSIS
- safe_hash_change()
- hash Hash handle
- old_data Old data
- new_data Change all 'old_data' to this
-
- NOTES
- We use the linked list to traverse all elements in the hash as
- this allows us to delete elements in the case where 'new_data' is the
- default value.
-*/
-
-static void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
-{
- SAFE_HASH_ENTRY *entry, *next;
- DBUG_ENTER("safe_hash_set");
-
- rw_wrlock(&hash->mutex);
-
- for (entry= hash->root ; entry ; entry= next)
- {
- next= entry->next;
- if (entry->data == old_data)
- {
- if (new_data == hash->default_value)
- {
- if ((*entry->prev= entry->next))
- entry->next->prev= entry->prev;
- hash_delete(&hash->hash, (uchar*) entry);
- }
- else
- entry->data= new_data;
- }
- }
-
- rw_unlock(&hash->mutex);
- DBUG_VOID_RETURN;
-}
-
+#include "my_safehash.h"
/*****************************************************************************
Functions to handle the key cache objects
@@ -315,6 +53,7 @@ void multi_keycache_free(void)
multi_key_cache_search()
key key to find (usually table path)
uint length Length of key.
+ def Default value if no key cache
NOTES
This function is coded in such a way that we will return the
@@ -325,11 +64,13 @@ void multi_keycache_free(void)
key cache to use
*/
-KEY_CACHE *multi_key_cache_search(uchar *key, uint length)
+KEY_CACHE *multi_key_cache_search(uchar *key, uint length,
+ KEY_CACHE *def)
{
if (!key_cache_hash.hash.records)
- return dflt_key_cache;
- return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length);
+ return def;
+ return (KEY_CACHE*) safe_hash_search(&key_cache_hash, key, length,
+ (void*) def);
}
@@ -361,3 +102,5 @@ void multi_key_cache_change(KEY_CACHE *old_data,
{
safe_hash_change(&key_cache_hash, (uchar*) old_data, (uchar*) new_data);
}
+
+
diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c
index e127b2584ae..137127a2fda 100644
--- a/mysys/my_bitmap.c
+++ b/mysys/my_bitmap.c
@@ -508,10 +508,8 @@ uint bitmap_get_first_set(const MY_BITMAP *map)
if (*byte_ptr & (1 << k))
return (i*32) + (j*8) + k;
}
- DBUG_ASSERT(0);
}
}
- DBUG_ASSERT(0);
}
}
return MY_BIT_NONE;
@@ -542,10 +540,8 @@ uint bitmap_get_first(const MY_BITMAP *map)
if (!(*byte_ptr & (1 << k)))
return (i*32) + (j*8) + k;
}
- DBUG_ASSERT(0);
}
}
- DBUG_ASSERT(0);
}
}
return MY_BIT_NONE;
diff --git a/mysys/my_chmod.c b/mysys/my_chmod.c
new file mode 100644
index 00000000000..afdea758833
--- /dev/null
+++ b/mysys/my_chmod.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+
+/**
+ @brief Change mode of file.
+
+ @fn my_chmod()
+ @param name Filename
+ @param mode_t Mode
+ @param my_flags Flags
+
+ @notes
+ The mode of the file given by path or referenced by fildes is changed
+
+ @retval 0 Ok
+ @retval # Error
+*/
+
+int my_chmod(const char *name, mode_t mode, myf my_flags)
+{
+ DBUG_ENTER("my_chmod");
+ DBUG_PRINT("my",("name: %s mode: %lu flags: %d", name, (ulong) mode,
+ my_flags));
+
+ if (chmod(name, mode))
+ {
+ my_errno= errno;
+ if (my_flags & MY_WME)
+ my_error(EE_CANT_CHMOD, MYF(0), name, (ulong) mode, my_errno);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
diff --git a/mysys/my_compress.c b/mysys/my_compress.c
index 0d076e77c35..45c4ab983cc 100644
--- a/mysys/my_compress.c
+++ b/mysys/my_compress.c
@@ -67,7 +67,7 @@ uchar *my_compress_alloc(const uchar *packet, size_t *len, size_t *complen)
if (!(compbuf= (uchar *) my_malloc(*complen, MYF(MY_WME))))
return 0; /* Not enough memory */
- tmp_complen= *complen;
+ tmp_complen= (uLongf) *complen;
res= compress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet, (uLong) *len);
*complen= tmp_complen;
@@ -118,7 +118,7 @@ my_bool my_uncompress(uchar *packet, size_t len, size_t *complen)
if (!compbuf)
DBUG_RETURN(1); /* Not enough memory */
- tmp_complen= *complen;
+ tmp_complen= (uLongf) *complen;
error= uncompress((Bytef*) compbuf, &tmp_complen, (Bytef*) packet,
(uLong) len);
*complen= tmp_complen;
diff --git a/mysys/my_error.c b/mysys/my_error.c
index 75701536dd3..81abbde96df 100644
--- a/mysys/my_error.c
+++ b/mysys/my_error.c
@@ -87,11 +87,11 @@ int my_error(int nr, myf MyFlags, ...)
/* get the error message string. Default, if NULL or empty string (""). */
if (! (format= (meh_p && (nr >= meh_p->meh_first)) ?
meh_p->meh_errmsgs[nr - meh_p->meh_first] : NULL) || ! *format)
- (void) my_snprintf (ebuff, sizeof(ebuff), "Unknown error %d", nr);
+ (void) my_snprintf(ebuff, sizeof(ebuff), "Unknown error %d", nr);
else
{
va_start(args,MyFlags);
- (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);
+ (void) my_vsnprintf(ebuff, sizeof(ebuff), format, args);
va_end(args);
}
DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
@@ -114,15 +114,39 @@ int my_printf_error(uint error, const char *format, myf MyFlags, ...)
va_list args;
char ebuff[ERRMSGSIZE+20];
DBUG_ENTER("my_printf_error");
- DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d Format: %s",
+ DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d format: %s",
error, MyFlags, errno, format));
va_start(args,MyFlags);
- (void) my_vsnprintf (ebuff, sizeof(ebuff), format, args);
+ (void) my_vsnprintf(ebuff, sizeof(ebuff), format, args);
va_end(args);
DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags));
}
+
+/*
+ Error with va_list
+
+ SYNOPSIS
+ my_printv_error()
+ error Errno
+ format Format string
+ MyFlags Flags
+ ... variable list
+*/
+
+int my_printv_error(uint error, const char *format, myf MyFlags, va_list ap)
+{
+ char ebuff[ERRMSGSIZE+20];
+ DBUG_ENTER("my_printv_error");
+ DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d format: %s",
+ error, MyFlags, errno, format));
+
+ (void) my_vsnprintf(ebuff, sizeof(ebuff), format, ap);
+ DBUG_RETURN((*error_handler_hook)(error, ebuff, MyFlags));
+}
+
+
/*
Give message using error_handler_hook
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
index 44156da6ae3..351851cca76 100644
--- a/mysys/my_fopen.c
+++ b/mysys/my_fopen.c
@@ -134,7 +134,7 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
FILE *fd;
char type[5];
DBUG_ENTER("my_fdopen");
- DBUG_PRINT("my",("Fd: %d Flags: %d MyFlags: %d",
+ DBUG_PRINT("my",("fd: %d Flags: %d MyFlags: %d",
Filedes, Flags, MyFlags));
make_ftype(type,Flags);
diff --git a/mysys/my_getncpus.c b/mysys/my_getncpus.c
index 82e87dee2e4..4cb96ac0bca 100644
--- a/mysys/my_getncpus.c
+++ b/mysys/my_getncpus.c
@@ -16,24 +16,26 @@
/* get the number of (online) CPUs */
#include "mysys_priv.h"
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
static int ncpus=0;
-#ifdef _SC_NPROCESSORS_ONLN
int my_getncpus()
{
if (!ncpus)
+ {
+#ifdef _SC_NPROCESSORS_ONLN
ncpus= sysconf(_SC_NPROCESSORS_ONLN);
- return ncpus;
-}
-
+#elif defined(__WIN__)
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ ncpus= sysinfo.dwNumberOfProcessors;
#else
-/* unknown */
-int my_getncpus()
-{
- return 2;
-}
-
+/* unknown so play safe: assume SMP and forbid uniprocessor build */
+ ncpus= 2;
#endif
-
+ }
+ return ncpus;
+}
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index f97550d4429..e579d8154db 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -28,23 +28,22 @@ static void default_reporter(enum loglevel level, const char *format, ...);
my_error_reporter my_getopt_error_reporter= &default_reporter;
static int findopt(char *optpat, uint length,
- const struct my_option **opt_res,
- char **ffname);
+ const struct my_option **opt_res,
+ char **ffname);
my_bool getopt_compare_strings(const char *s,
- const char *t,
- uint length);
+ const char *t,
+ uint length);
static longlong getopt_ll(char *arg, const struct my_option *optp, int *err);
static ulonglong getopt_ull(char *arg, const struct my_option *optp,
- int *err);
+ int *err);
static double getopt_double(char *arg, const struct my_option *optp, int *err);
static void init_variables(const struct my_option *options,
init_func_p init_one_value);
-static void init_one_value(const struct my_option *option, uchar* *variable,
- longlong value);
+static void init_one_value(const struct my_option *opt, uchar* *, longlong);
static void fini_one_value(const struct my_option *option, uchar* *variable,
longlong value);
-static int setval(const struct my_option *opts, uchar* *value, char *argument,
- my_bool set_maximum_value);
+static int setval(const struct my_option *opts, uchar **value, char *argument,
+ my_bool set_maximum_value);
static char *check_struct_option(char *cur_arg, char *key_name);
/*
@@ -775,7 +774,7 @@ static longlong eval_num_suffix(char *argument, int *error, char *option_name)
return num;
}
-/*
+/*
function: getopt_ll
Evaluates and returns the value that user gave as an argument
@@ -922,7 +921,6 @@ ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp,
my_getopt_error_reporter(WARNING_LEVEL,
"option '%s': unsigned value %s adjusted to %s",
optp->name, ullstr(old, buf1), ullstr(num, buf2));
-
return num;
}
@@ -963,8 +961,8 @@ static double getopt_double(char *arg, const struct my_option *optp, int *err)
SYNOPSIS
init_one_value()
- option Option to initialize
- value Pointer to variable
+ option Option to initialize
+ value Pointer to variable
*/
static void init_one_value(const struct my_option *option, uchar* *variable,
@@ -993,7 +991,7 @@ static void init_one_value(const struct my_option *option, uchar* *variable,
case GET_LL:
*((longlong*) variable)= (longlong) getopt_ll_limit_value((longlong) value, option, NULL);
break;
- case GET_ULL:
+ case GET_ULL: /* Fall through */
case GET_SET:
*((ulonglong*) variable)= (ulonglong) getopt_ull_limit_value((ulonglong) value, option, NULL);
break;
@@ -1061,7 +1059,7 @@ void my_cleanup_options(const struct my_option *options)
}
-/*
+/*
initialize all variables to their default values
SYNOPSIS
diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c
index b692b18bfc7..64480c4aa7a 100644
--- a/mysys/my_getsystime.c
+++ b/mysys/my_getsystime.c
@@ -222,4 +222,3 @@ time_t my_time_possible_from_micro(ulonglong microtime __attribute__((unused)))
return (time_t) (microtime / 1000000);
#endif /* defined(__WIN__) */
}
-
diff --git a/mysys/my_handler.c b/mysys/my_handler.c
index 3bc27b622cb..7c13149cb27 100644
--- a/mysys/my_handler.c
+++ b/mysys/my_handler.c
@@ -20,26 +20,27 @@
#include <my_base.h>
#include <my_handler.h>
#include <my_sys.h>
-
#include "my_handler_errors.h"
-int ha_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
- uchar *b, uint b_length, my_bool part_key,
+int ha_compare_text(CHARSET_INFO *charset_info, const uchar *a, uint a_length,
+ const uchar *b, uint b_length, my_bool part_key,
my_bool skip_end_space)
{
if (!part_key)
return charset_info->coll->strnncollsp(charset_info, a, a_length,
- b, b_length, (my_bool)!skip_end_space);
+ b, b_length,
+ (my_bool)!skip_end_space);
return charset_info->coll->strnncoll(charset_info, a, a_length,
b, b_length, part_key);
}
-static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
+static int compare_bin(const uchar *a, uint a_length,
+ const uchar *b, uint b_length,
my_bool part_key, my_bool skip_end_space)
{
uint length= min(a_length,b_length);
- uchar *end= a+ length;
+ const uchar *end= a+ length;
int flag;
while (a < end)
@@ -83,13 +84,15 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
ha_key_cmp()
keyseg Array of key segments of key to compare
a First key to compare, in format from _mi_pack_key()
- This is normally key specified by user
- b Second key to compare. This is always from a row
- key_length Length of key to compare. This can be shorter than
- a to just compare sub keys
+ This is always from the row
+ b Second key to compare. This is from the row or the user
+ key_length Length of key to compare, based on key b. This can be shorter
+ than b to just compare sub keys
next_flag How keys should be compared
If bit SEARCH_FIND is not set the keys includes the row
position and this should also be compared
+ If SEARCH_PAGE_KEY_HAS_TRANSID is set then 'a' has transid
+ If SEARCH_USER_KEY_HAS_TRANSID is set then 'b' has transid
diff_pos OUT Number of first keypart where values differ, counting
from one.
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
@@ -118,8 +121,8 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
#define FCMP(A,B) ((int) (A) - (int) (B))
-int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
- register uchar *b, uint key_length, uint nextflag,
+int ha_key_cmp(register HA_KEYSEG *keyseg, register const uchar *a,
+ register const uchar *b, uint key_length, uint32 nextflag,
uint *diff_pos)
{
int flag;
@@ -129,12 +132,12 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
float f_1,f_2;
double d_1,d_2;
uint next_key_length;
- uchar *orig_b= b;
+ const uchar *orig_b= b;
*diff_pos=0;
for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
{
- uchar *end;
+ const uchar *end;
uint piks=! (keyseg->flag & HA_NO_SORT);
(*diff_pos)++;
diff_pos[1]= (uint)(b - orig_b);
@@ -151,8 +154,13 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
b++;
if (!*a++) /* If key was NULL */
{
- if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
- nextflag=SEARCH_SAME; /* Allow duplicate keys */
+ if ((nextflag & (SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT |
+ SEARCH_NULL_ARE_EQUAL)) ==
+ (SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT))
+ {
+ /* Allow duplicate keys */
+ nextflag= (nextflag & ~(SEARCH_FIND | SEARCH_UPDATE)) | SEARCH_SAME;
+ }
else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
{
/*
@@ -366,7 +374,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
if (keyseg->flag & HA_REVERSE_SORT)
{
- swap_variables(uchar*, a, b);
+ swap_variables(const uchar*, a, b);
swap_flag=1; /* Remember swap of a & b */
end= a+ (int) (end-b);
}
@@ -391,7 +399,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
if (*b != '-')
return -1;
a++; b++;
- swap_variables(uchar*, a, b);
+ swap_variables(const uchar*, a, b);
swap_variables(int, alength, blength);
swap_flag=1-swap_flag;
alength--; blength--;
@@ -420,7 +428,7 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
}
if (swap_flag) /* Restore pointers */
- swap_variables(uchar*, a, b);
+ swap_variables(const uchar*, a, b);
break;
}
#ifdef HAVE_LONG_LONG
@@ -455,18 +463,90 @@ int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
end:
if (!(nextflag & SEARCH_FIND))
{
+ /*
+ Compare rowid and possible transid
+ This happens in the following case:
+ - INSERT, UPDATE, DELETE when we have not unique keys or
+ are using versioning
+ - SEARCH_NEXT, SEARCH_PREVIOUS when we need to restart search
+
+ The logic for comparing transid are as follows:
+ Keys with have a transid have lowest bit in the rowidt. This means that
+ if we are comparing a key with a transid with another key that doesn't
+ have a tranid, we must reset the lowest bit for both keys.
+
+ When we have transid, the keys are compared in transid order.
+ A key without a transid is regared to be smaller than a key with
+ a transid.
+ */
+
uint i;
+ uchar key_mask, tmp_a, tmp_b;
+
if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
- flag=0;
- for (i=keyseg->length ; i-- > 0 ; )
+ key_mask= (uchar) 255;
+
+ if (!(nextflag & (SEARCH_USER_KEY_HAS_TRANSID |
+ SEARCH_PAGE_KEY_HAS_TRANSID)))
+ {
+ /*
+ Neither key has a trid. Only compare row id's and don't
+ try to store rows in trid order
+ */
+ key_length= keyseg->length;
+ nextflag&= ~SEARCH_INSERT;
+ }
+ else
+ {
+ /*
+ Set key_mask so that we reset the last bit in the rowid before
+ we compare it. This is needed as the lowest bit in the rowid is
+ used to mark if the key has a transid or not.
+ */
+ key_mask= (uchar) 254;
+ if (!test_all_bits(nextflag, (SEARCH_USER_KEY_HAS_TRANSID |
+ SEARCH_PAGE_KEY_HAS_TRANSID)))
+ {
+ /*
+ No transaction id for user key or for key on page
+ Ignore transid as at least one of the keys are visible for all
+ */
+ key_length= keyseg->length;
+ }
+ else
+ {
+ /*
+ Both keys have trids. No need of special handling of incomplete
+ trids below.
+ */
+ nextflag&= ~SEARCH_INSERT;
+ }
+ }
+ DBUG_ASSERT(key_length > 0);
+
+ for (i= key_length-1 ; (int) i-- > 0 ; )
{
if (*a++ != *b++)
{
flag= FCMP(a[-1],b[-1]);
- break;
+ goto found;
}
}
+ tmp_a= *a & key_mask;
+ tmp_b= *b & key_mask;
+ flag= FCMP(tmp_a, tmp_b);
+
+ if (flag == 0 && (nextflag & SEARCH_INSERT))
+ {
+ /*
+ Ensure that on insert we get rows stored in trid order.
+ If one of the parts doesn't have a trid, this should be regarded
+ as smaller than the other
+ */
+ return (nextflag & SEARCH_USER_KEY_HAS_TRANSID) ? -1 : 1;
+ }
+found:
if (nextflag & SEARCH_SAME)
return (flag); /* read same */
if (nextflag & SEARCH_BIGGER)
@@ -498,11 +578,11 @@ end:
NULLs.
*/
-HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
+HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, const uchar *a)
{
for (; (enum ha_base_keytype) keyseg->type != HA_KEYTYPE_END; keyseg++)
{
- uchar *end;
+ const uchar *end;
if (keyseg->null_bit)
{
if (!*a++)
@@ -567,7 +647,6 @@ HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
}
-
/*
Register handler error messages for usage with my_error()
@@ -576,7 +655,6 @@ HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
will ignore calls to register already registered error numbers.
*/
-
void my_handler_error_register(void)
{
/*
diff --git a/mysys/my_handler_errors.h b/mysys/my_handler_errors.h
index e360af8c57e..4c952466545 100644
--- a/mysys/my_handler_errors.h
+++ b/mysys/my_handler_errors.h
@@ -32,7 +32,7 @@ static const char *handler_error_messages[]=
"Table is crashed and last repair failed",
"Table was marked as crashed and should be repaired",
"Lock timed out; Retry transaction",
- "Lock table is full; Restart program with a larger locktable",
+ "Lock table is full; Restart program with a larger lock table",
"Updates are not allowed under a read only transactions",
"Lock deadlock; Retry transaction",
"Foreign key constraint is incorrectly formed",
@@ -46,7 +46,7 @@ static const char *handler_error_messages[]=
"Unexpected null pointer found when using spatial index",
"The table changed in storage engine",
"There's no partition in table for the given value",
- "Row-based binlogging of row failed",
+ "Row-based binary logging of row failed",
"Index needed in foreign key constraint",
"Upholding foreign key constraints would lead to a duplicate key error in "
"some other table",
@@ -55,13 +55,14 @@ static const char *handler_error_messages[]=
"Failed to get next auto increment value",
"Failed to set row auto increment value",
"Unknown (generic) error from engine",
- "Record is the same",
+ "Record was not update. Original values was same as new values",
"It is not possible to log this statement",
"The event was corrupt, leading to illegal data being read",
"The table is of a new format not supported by this version",
- "The event could not be processed no other hanlder error happened",
- "Got a fatal error during initialzaction of handler",
- "File to short; Expected more data in file",
- "Read page with wrong checksum"
+ "The event could not be processed. No other handler error happened",
+ "Got a fatal error during initialization of handler",
+ "File too short; Expected more data in file",
+ "Read page with wrong checksum",
+ "Row is not visible by the current transaction"
};
diff --git a/mysys/my_init.c b/mysys/my_init.c
index edc37a3c96f..2401671687b 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -77,6 +77,10 @@ my_bool my_init(void)
my_umask= 0660; /* Default umask for new files */
my_umask_dir= 0700; /* Default umask for new directories */
init_glob_errs();
+ my_progname_short= "unknown";
+ if (my_progname)
+ my_progname_short= my_progname + dirname_length(my_progname);
+
#if defined(THREAD)
if (my_thread_global_init())
return 1;
@@ -162,6 +166,9 @@ void my_end(int infoflag)
free_charsets();
my_error_unregister_all();
my_once_free();
+#ifdef THREAD
+ my_thread_destroy_mutex();
+#endif
if ((infoflag & MY_GIVE_INFO) || print_info)
{
@@ -192,6 +199,10 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
#endif
#if defined(SAFEMALLOC)
+ /* Wait for other threads to free mysys_var */
+#ifdef THREAD
+ (void) my_wait_for_other_threads_to_die(1);
+#endif
TERMINATE(stderr, (infoflag & MY_GIVE_INFO) != 0);
#elif defined(__WIN__) && defined(_MSC_VER)
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
@@ -233,6 +244,13 @@ Voluntary context switches %ld, Involuntary context switches %ld\n",
my_init_done=0;
} /* my_end */
+#ifndef DBUG_OFF
+/* Dummy tag function for debugging */
+
+void my_debug_put_break_here(void)
+{
+}
+#endif
#ifdef __WIN__
diff --git a/mysys/my_lock.c b/mysys/my_lock.c
index c0522ee849d..8450fcfc30a 100644
--- a/mysys/my_lock.c
+++ b/mysys/my_lock.c
@@ -49,12 +49,12 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
int nxErrno;
#endif
DBUG_ENTER("my_lock");
- DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
+ DBUG_PRINT("my",("fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
fd,locktype,(long) start,(long) length,MyFlags));
#ifdef VMS
DBUG_RETURN(0);
#else
- if (my_disable_locking)
+ if (my_disable_locking && ! (MyFlags & MY_FORCE_LOCK))
DBUG_RETURN(0);
#if defined(__NETWARE__)
@@ -87,7 +87,7 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
nxLockFlags = NX_RANGE_LOCK_EXCL;
}
- if (MyFlags & MY_DONT_WAIT)
+ if (MyFlags & MY_NO_WAIT)
{
/* Don't block on the lock. */
nxLockFlags |= NX_RANGE_LOCK_TRYLOCK;
@@ -131,10 +131,16 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
lock.l_start= (off_t) start;
lock.l_len= (off_t) length;
- if (MyFlags & MY_DONT_WAIT)
+ if (MyFlags & (MY_NO_WAIT | MY_SHORT_WAIT))
{
if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */
- DBUG_RETURN(0); /* Ok, file locked */
+ DBUG_RETURN(0); /* Ok, file locked */
+ if (MyFlags & MY_NO_WAIT)
+ {
+ my_errno= (errno == EACCES) ? EAGAIN : errno ? errno : -1;
+ DBUG_RETURN(-1);
+ }
+
DBUG_PRINT("info",("Was locked, trying with alarm"));
ALARM_INIT;
while ((value=fcntl(fd,F_SETLKW,&lock)) && ! ALARM_TEST &&
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
index de7a2b611ed..5c27cf73482 100644
--- a/mysys/my_pread.c
+++ b/mysys/my_pread.c
@@ -15,6 +15,8 @@
#include "mysys_priv.h"
#include "mysys_err.h"
+#include "my_base.h"
+#include <m_string.h>
#include <errno.h>
#ifdef HAVE_PREAD
#include <unistd.h>
@@ -46,27 +48,37 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
{
size_t readbytes;
int error= 0;
+#ifndef HAVE_PREAD
+ int save_errno;
+#endif
+#ifndef DBUG_OFF
+ char llbuf[22];
DBUG_ENTER("my_pread");
- DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
- Filedes, (ulong) offset, (long) Buffer, (uint) Count,
- MyFlags));
+ DBUG_PRINT("my",("fd: %d Seek: %s Buffer: 0x%lx Count: %lu MyFlags: %d",
+ Filedes, ullstr(offset, llbuf), (long) Buffer,
+ (ulong)Count, MyFlags));
+#endif
for (;;)
{
-#ifndef __WIN__
- errno=0; /* Linux doesn't reset this */
-#endif
+ errno= 0; /* Linux, Windows don't reset this on EOF/success */
#ifndef HAVE_PREAD
pthread_mutex_lock(&my_file_info[Filedes].mutex);
readbytes= (uint) -1;
error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 ||
(readbytes= read(Filedes, Buffer, Count)) != Count);
+ save_errno= errno;
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
+ if (error)
+ {
+ errno= save_errno;
#else
if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
- my_errno= errno ? errno : -1;
-#endif
- if (error || readbytes != Count)
{
+#endif
+ my_errno= errno ? errno : -1;
+ if (errno == 0 || (readbytes != (size_t) -1 &&
+ (MyFlags & (MY_NABP | MY_FNABP))))
+ my_errno= HA_ERR_FILE_TOO_SHORT;
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
(int) readbytes, (uint) Count,Filedes,my_errno));
#ifdef THREAD
@@ -122,10 +134,13 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
{
size_t writenbytes, written;
uint errors;
+#ifndef DBUG_OFF
+ char llbuf[22];
DBUG_ENTER("my_pwrite");
- DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
- Filedes, (ulong) offset, (long) Buffer, (uint) Count,
- MyFlags));
+ DBUG_PRINT("my",("fd: %d Seek: %s Buffer: 0x%lx Count: %lu MyFlags: %d",
+ Filedes, ullstr(offset, llbuf), (long) Buffer,
+ (ulong)Count, MyFlags));
+#endif
errors= 0;
written= 0;
diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c
index aba3e47d754..e97bbe89be0 100644
--- a/mysys/my_pthread.c
+++ b/mysys/my_pthread.c
@@ -429,7 +429,8 @@ int sigwait(sigset_t *setp, int *sigp)
#include <netdb.h>
-int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
+int my_pthread_mutex_noposix_init(pthread_mutex_t *mp,
+ const pthread_mutexattr_t *attr)
{
int error;
if (!attr)
@@ -439,7 +440,8 @@ int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
return error;
}
-int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
+int my_pthread_cond_noposix_init(pthread_cond_t *mp,
+ const pthread_condattr_t *attr)
{
int error;
if (!attr)
diff --git a/mysys/my_read.c b/mysys/my_read.c
index f3e8a4b300e..8e098924e43 100644
--- a/mysys/my_read.c
+++ b/mysys/my_read.c
@@ -15,9 +15,9 @@
#include "mysys_priv.h"
#include "mysys_err.h"
+#include <my_base.h>
#include <errno.h>
-
/*
Read a chunk of bytes from a file with retry's if needed
@@ -37,16 +37,19 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
{
size_t readbytes, save_count;
DBUG_ENTER("my_read");
- DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
+ DBUG_PRINT("my",("fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
Filedes, (long) Buffer, (ulong) Count, MyFlags));
save_count= Count;
for (;;)
{
- errno= 0; /* Linux doesn't reset this */
+ errno= 0; /* Linux, Windows don't reset this on EOF/success */
if ((readbytes= read(Filedes, Buffer, Count)) != Count)
{
- my_errno= errno ? errno : -1;
+ my_errno= errno;
+ if (errno == 0 || (readbytes != (size_t) -1 &&
+ (MyFlags & (MY_NABP | MY_FNABP))))
+ my_errno= HA_ERR_FILE_TOO_SHORT;
DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d",
(int) readbytes, (ulong) Count, Filedes,
my_errno));
diff --git a/mysys/my_realloc.c b/mysys/my_realloc.c
index a55282e03a0..828890a0dc2 100644
--- a/mysys/my_realloc.c
+++ b/mysys/my_realloc.c
@@ -32,6 +32,7 @@
@note if size==0 realloc() may return NULL; my_realloc() treats this as an
error which is not the intention of realloc()
*/
+
void* my_realloc(void* oldpoint, size_t size, myf my_flags)
{
void *point;
diff --git a/mysys/my_rnd.c b/mysys/my_rnd.c
new file mode 100644
index 00000000000..b7dca0f2afd
--- /dev/null
+++ b/mysys/my_rnd.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 2007 MySQL AB & Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+/*
+ Initialize random generator
+
+ NOTES
+ MySQL's password checks depends on this, so don't do any changes
+ that changes the random numbers that are generated!
+*/
+
+void my_rnd_init(struct my_rnd_struct *rand_st, ulong seed1, ulong seed2)
+{
+#ifdef HAVE_purify
+ bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
+#endif
+ rand_st->max_value= 0x3FFFFFFFL;
+ rand_st->max_value_dbl=(double) rand_st->max_value;
+ rand_st->seed1=seed1%rand_st->max_value ;
+ rand_st->seed2=seed2%rand_st->max_value;
+}
+
+
+/*
+ Generate random number.
+
+ SYNOPSIS
+ my_rnd()
+ rand_st INOUT Structure used for number generation
+
+ RETURN VALUE
+ generated pseudo random number
+*/
+
+double my_rnd(struct my_rnd_struct *rand_st)
+{
+ rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
+ rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
+ return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+}
diff --git a/mysys/my_safehash.c b/mysys/my_safehash.c
new file mode 100644
index 00000000000..b3d6439793c
--- /dev/null
+++ b/mysys/my_safehash.c
@@ -0,0 +1,297 @@
+/* Copyright (C) 2003-2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Handling of multiple key caches
+
+ The idea is to have a thread safe hash on the table name,
+ with a default key cache value that is returned if the table name is not in
+ the cache.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include "my_safehash.h"
+
+/*****************************************************************************
+ General functions to handle SAFE_HASH objects.
+
+ A SAFE_HASH object is used to store the hash, the mutex and default value
+ needed by the rest of the key cache code.
+ This is a separate struct to make it easy to later reuse the code for other
+ purposes
+
+ All entries are linked in a list to allow us to traverse all elements
+ and delete selected ones. (HASH doesn't allow any easy ways to do this).
+*****************************************************************************/
+
+
+/*
+ Free a SAFE_HASH_ENTRY
+
+ SYNOPSIS
+ safe_hash_entry_free()
+ entry The entry which should be freed
+
+ NOTE
+ This function is called by the hash object on delete
+*/
+
+static void safe_hash_entry_free(SAFE_HASH_ENTRY *entry)
+{
+ DBUG_ENTER("safe_hash_entry_free");
+ my_free((uchar*) entry, MYF(0));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Get key and length for a SAFE_HASH_ENTRY
+
+ SYNOPSIS
+ safe_hash_entry_get()
+ entry The entry for which the key should be returned
+ length Length of the key
+
+ RETURN
+ # reference on the key
+*/
+
+static uchar *safe_hash_entry_get(SAFE_HASH_ENTRY *entry, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length= entry->length;
+ return (uchar*) entry->key;
+}
+
+
+/*
+ Init a SAFE_HASH object
+
+ SYNOPSIS
+ safe_hash_init()
+ hash safe_hash handler
+ elements Expected max number of elements
+ default_value default value
+
+ NOTES
+ In case of error we set hash->default_value to 0 to allow one to call
+ safe_hash_free on an object that couldn't be initialized.
+
+ RETURN
+ 0 OK
+ 1 error
+*/
+
+my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
+ uchar *default_value)
+{
+ DBUG_ENTER("safe_hash_init");
+ if (hash_init(&hash->hash, &my_charset_bin, elements,
+ 0, 0, (hash_get_key) safe_hash_entry_get,
+ (void (*)(void*)) safe_hash_entry_free, 0))
+ {
+ hash->default_value= 0;
+ DBUG_RETURN(1);
+ }
+ my_rwlock_init(&hash->mutex, 0);
+ hash->default_value= default_value;
+ hash->root= 0;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Free a SAFE_HASH object
+
+ SYNOPSIS
+ safe_hash_free()
+ hash Hash handle
+
+ NOTES
+ This is safe to call on any object that has been sent to safe_hash_init()
+*/
+
+void safe_hash_free(SAFE_HASH *hash)
+{
+ /*
+ Test if safe_hash_init succeeded. This will also guard us against multiple
+ free calls.
+ */
+ if (hash->default_value)
+ {
+ hash_free(&hash->hash);
+ rwlock_destroy(&hash->mutex);
+ hash->default_value=0;
+ }
+}
+
+
+/*
+ Return the value stored for a key or default value if no key
+
+ SYNOPSIS
+ safe_hash_search()
+ hash Hash handle
+ key key (path to table etc..)
+ length Length of key
+ def Default value of data
+
+ RETURN
+ # data associated with the key of default value if data was not found
+*/
+
+uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length,
+ uchar *def)
+{
+ uchar *result;
+ DBUG_ENTER("safe_hash_search");
+ rw_rdlock(&hash->mutex);
+ result= hash_search(&hash->hash, key, length);
+ rw_unlock(&hash->mutex);
+ if (!result)
+ result= def;
+ else
+ result= ((SAFE_HASH_ENTRY*) result)->data;
+ DBUG_PRINT("exit",("data: 0x%lx", (long) result));
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Associate a key with some data
+
+ SYNOPSIS
+ safe_hash_set()
+ hash Hash handle
+ key key (path to table etc..)
+ length Length of key
+ data data to to associate with the data
+
+ NOTES
+ This can be used both to insert a new entry and change an existing
+ entry.
+ If one associates a key with the default key cache, the key is deleted
+
+ RETURN
+ 0 OK
+ 1 error (Can only be EOM). In this case my_message() is called.
+*/
+
+my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
+ uchar *data)
+{
+ SAFE_HASH_ENTRY *entry;
+ my_bool error= 0;
+ DBUG_ENTER("safe_hash_set");
+ DBUG_PRINT("enter",("key: %.*s data: 0x%lx", length, key, (long) data));
+
+ rw_wrlock(&hash->mutex);
+ entry= (SAFE_HASH_ENTRY*) hash_search(&hash->hash, key, length);
+
+ if (data == hash->default_value)
+ {
+ /*
+ The key is to be associated with the default entry. In this case
+ we can just delete the entry (if it existed) from the hash as a
+ search will return the default entry
+ */
+ if (!entry) /* nothing to do */
+ goto end;
+ /* unlink entry from list */
+ if ((*entry->prev= entry->next))
+ entry->next->prev= entry->prev;
+ hash_delete(&hash->hash, (uchar*) entry);
+ goto end;
+ }
+ if (entry)
+ {
+ /* Entry existed; Just change the pointer to point at the new data */
+ entry->data= data;
+ }
+ else
+ {
+ if (!(entry= (SAFE_HASH_ENTRY *) my_malloc(sizeof(*entry) + length,
+ MYF(MY_WME))))
+ {
+ error= 1;
+ goto end;
+ }
+ entry->key= (uchar*) (entry +1);
+ memcpy((char*) entry->key, (char*) key, length);
+ entry->length= length;
+ entry->data= data;
+ /* Link entry to list */
+ if ((entry->next= hash->root))
+ entry->next->prev= &entry->next;
+ entry->prev= &hash->root;
+ hash->root= entry;
+ if (my_hash_insert(&hash->hash, (uchar*) entry))
+ {
+ /* This can only happen if hash got out of memory */
+ my_free((char*) entry, MYF(0));
+ error= 1;
+ goto end;
+ }
+ }
+
+end:
+ rw_unlock(&hash->mutex);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Change all entries with one data value to another data value
+
+ SYNOPSIS
+ safe_hash_change()
+ hash Hash handle
+ old_data Old data
+ new_data Change all 'old_data' to this
+
+ NOTES
+ We use the linked list to traverse all elements in the hash as
+ this allows us to delete elements in the case where 'new_data' is the
+ default value.
+*/
+
+void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data)
+{
+ SAFE_HASH_ENTRY *entry, *next;
+ DBUG_ENTER("safe_hash_change");
+
+ rw_wrlock(&hash->mutex);
+
+ for (entry= hash->root ; entry ; entry= next)
+ {
+ next= entry->next;
+ if (entry->data == old_data)
+ {
+ if (new_data == hash->default_value)
+ {
+ if ((*entry->prev= entry->next))
+ entry->next->prev= entry->prev;
+ hash_delete(&hash->hash, (uchar*) entry);
+ }
+ else
+ entry->data= new_data;
+ }
+ }
+
+ rw_unlock(&hash->mutex);
+ DBUG_VOID_RETURN;
+}
diff --git a/mysys/my_safehash.h b/mysys/my_safehash.h
new file mode 100644
index 00000000000..8a5856b6763
--- /dev/null
+++ b/mysys/my_safehash.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Handling of multiple key caches
+
+ The idea is to have a thread safe hash on the table name,
+ with a default key cache value that is returned if the table name is not in
+ the cache.
+*/
+
+#include <hash.h>
+
+/*
+ Struct to store a key and pointer to object
+*/
+
+typedef struct st_safe_hash_entry
+{
+ uchar *key;
+ uint length;
+ uchar *data;
+ struct st_safe_hash_entry *next, **prev;
+} SAFE_HASH_ENTRY;
+
+
+typedef struct st_safe_hash_with_default
+{
+#ifdef THREAD
+ rw_lock_t mutex;
+#endif
+ HASH hash;
+ uchar *default_value;
+ SAFE_HASH_ENTRY *root;
+} SAFE_HASH;
+
+
+my_bool safe_hash_init(SAFE_HASH *hash, uint elements,
+ uchar *default_value);
+void safe_hash_free(SAFE_HASH *hash);
+uchar *safe_hash_search(SAFE_HASH *hash, const uchar *key, uint length,
+ uchar *def);
+my_bool safe_hash_set(SAFE_HASH *hash, const uchar *key, uint length,
+ uchar *data);
+void safe_hash_change(SAFE_HASH *hash, uchar *old_data, uchar *new_data);
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
index 2c661baeff7..4e18b510a1e 100644
--- a/mysys/my_seek.c
+++ b/mysys/my_seek.c
@@ -47,7 +47,7 @@ my_off_t my_seek(File fd, my_off_t pos, int whence,
{
reg1 os_off_t newpos= -1;
DBUG_ENTER("my_seek");
- DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d",
+ DBUG_PRINT("my",("fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d",
fd, (ulong) (((ulonglong) pos) >> 32), (ulong) pos,
whence, MyFlags));
DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */
@@ -87,7 +87,7 @@ my_off_t my_tell(File fd, myf MyFlags __attribute__((unused)))
{
os_off_t pos;
DBUG_ENTER("my_tell");
- DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags));
+ DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
DBUG_ASSERT(fd >= 0);
#ifdef HAVE_TELL
pos=tell(fd);
diff --git a/mysys/my_sleep.c b/mysys/my_sleep.c
index 87170e4af41..cb21c15a925 100644
--- a/mysys/my_sleep.c
+++ b/mysys/my_sleep.c
@@ -30,7 +30,7 @@ void my_sleep(ulong m_seconds)
t.tv_usec= m_seconds % 1000000L;
select(0,0,0,0,&t); /* sleep */
#else
- uint sec= (uint) (m_seconds / 1000000L);
+ uint sec= (uint) ((m_seconds + 999999L) / 1000000L);
ulong start= (ulong) time((time_t*) 0);
while ((ulong) time((time_t*) 0) < start+sec);
#endif
diff --git a/mysys/my_static.c b/mysys/my_static.c
index d0c20da828a..c33d05420c9 100644
--- a/mysys/my_static.c
+++ b/mysys/my_static.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@ my_bool timed_mutexes= 0;
/* from my_init */
char * home_dir=0;
-const char *my_progname=0;
+const char *my_progname= NULL, *my_progname_short= NULL;
char NEAR curr_dir[FN_REFLEN]= {0},
NEAR home_dir_buff[FN_REFLEN]= {0};
ulong my_stream_opened=0,my_file_opened=0, my_tmp_file_created=0;
@@ -92,6 +92,19 @@ int (*error_handler_hook)(uint error,const char *str,myf MyFlags)=
int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)=
my_message_no_curses;
+static const char *proc_info_dummy(void *a __attribute__((unused)),
+ const char *b __attribute__((unused)),
+ const char *c __attribute__((unused)),
+ const char *d __attribute__((unused)),
+ const unsigned int e __attribute__((unused)))
+{
+ return 0;
+}
+
+/* this is to be able to call set_thd_proc_info from the C code */
+const char *(*proc_info_hook)(void *, const char *, const char *, const char *,
+ const unsigned int)= proc_info_dummy;
+
#ifdef __WIN__
/* from my_getsystime.c */
ulonglong query_performance_frequency, query_performance_offset;
diff --git a/mysys/my_sync.c b/mysys/my_sync.c
index ba6964b00d6..1b8420c034e 100644
--- a/mysys/my_sync.c
+++ b/mysys/my_sync.c
@@ -44,7 +44,7 @@ int my_sync(File fd, myf my_flags)
{
int res;
DBUG_ENTER("my_sync");
- DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags));
+ DBUG_PRINT("my",("fd: %d my_flags: %d", fd, my_flags));
do
{
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index 2278c467f32..3f4c4a4d638 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -115,6 +115,15 @@ my_bool my_thread_global_init(void)
}
#endif /* TARGET_OS_LINUX */
+ /* Mutex used by my_thread_init() and after my_thread_destroy_mutex() */
+ my_pthread_mutex_init(&THR_LOCK_threads, MY_MUTEX_INIT_FAST,
+ "THR_LOCK_threads", MYF_NO_DEADLOCK_DETECTION);
+ my_pthread_mutex_init(&THR_LOCK_malloc, MY_MUTEX_INIT_FAST,
+ "THR_LOCK_malloc", MYF_NO_DEADLOCK_DETECTION);
+
+ if (my_thread_init())
+ return 1;
+
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
/*
Set mutex type to "fast" a.k.a "adaptive"
@@ -138,7 +147,7 @@ my_bool my_thread_global_init(void)
PTHREAD_MUTEX_ERRORCHECK);
#endif
- pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST);
+ /* Mutex uses by mysys */
pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
@@ -146,7 +155,6 @@ my_bool my_thread_global_init(void)
pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&THR_LOCK_threads,MY_MUTEX_INIT_FAST);
pthread_mutex_init(&THR_LOCK_time,MY_MUTEX_INIT_FAST);
pthread_cond_init(&THR_COND_threads, NULL);
#if defined( __WIN__) || defined(OS2)
@@ -158,44 +166,64 @@ my_bool my_thread_global_init(void)
#ifndef HAVE_GETHOSTBYNAME_R
pthread_mutex_init(&LOCK_gethostbyname_r,MY_MUTEX_INIT_SLOW);
#endif
- if (my_thread_init())
- {
- my_thread_global_end(); /* Clean up */
- return 1;
- }
return 0;
}
-void my_thread_global_end(void)
+/**
+ Wait for all threads in system to die
+ @fn my_wait_for_other_threads_to_die()
+ @param number_of_threads Wait until this number of threads
+
+ @retval 0 Less or equal to number_of_threads left
+ @retval 1 Wait failed
+*/
+
+my_bool my_wait_for_other_threads_to_die(uint number_of_threads)
{
struct timespec abstime;
my_bool all_threads_killed= 1;
set_timespec(abstime, my_thread_end_wait_time);
pthread_mutex_lock(&THR_LOCK_threads);
- while (THR_thread_count > 0)
+ while (THR_thread_count > number_of_threads)
{
int error= pthread_cond_timedwait(&THR_COND_threads, &THR_LOCK_threads,
&abstime);
if (error == ETIMEDOUT || error == ETIME)
{
-#ifdef HAVE_PTHREAD_KILL
- /*
- We shouldn't give an error here, because if we don't have
- pthread_kill(), programs like mysqld can't ensure that all threads
- are killed when we enter here.
- */
- if (THR_thread_count)
- fprintf(stderr,
- "Error in my_thread_global_end(): %d threads didn't exit\n",
- THR_thread_count);
-#endif
all_threads_killed= 0;
break;
}
}
pthread_mutex_unlock(&THR_LOCK_threads);
+ return all_threads_killed;
+}
+
+
+/**
+ End the mysys thread system. Called when ending the last thread
+*/
+
+
+void my_thread_global_end(void)
+{
+ my_bool all_threads_killed;
+
+ if (!(all_threads_killed= my_wait_for_other_threads_to_die(0)))
+ {
+#ifdef HAVE_PTHREAD_KILL
+ /*
+ We shouldn't give an error here, because if we don't have
+ pthread_kill(), programs like mysqld can't ensure that all threads
+ are killed when we enter here.
+ */
+ if (THR_thread_count)
+ fprintf(stderr,
+ "Error in my_thread_global_end(): %d threads didn't exit\n",
+ THR_thread_count);
+#endif
+ }
pthread_key_delete(THR_KEY_mysys);
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
@@ -204,7 +232,25 @@ void my_thread_global_end(void)
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
pthread_mutexattr_destroy(&my_errorcheck_mutexattr);
#endif
- pthread_mutex_destroy(&THR_LOCK_malloc);
+ if (all_threads_killed)
+ {
+ pthread_mutex_destroy(&THR_LOCK_threads);
+ pthread_cond_destroy(&THR_COND_threads);
+ pthread_mutex_destroy(&THR_LOCK_malloc);
+ }
+}
+
+/* Free all mutex used by mysys */
+
+void my_thread_destroy_mutex(void)
+{
+ struct st_my_thread_var *tmp;
+ tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+ if (tmp)
+ {
+ safe_mutex_free_deadlock_data(&tmp->mutex);
+ }
+
pthread_mutex_destroy(&THR_LOCK_open);
pthread_mutex_destroy(&THR_LOCK_lock);
pthread_mutex_destroy(&THR_LOCK_isam);
@@ -213,11 +259,6 @@ void my_thread_global_end(void)
pthread_mutex_destroy(&THR_LOCK_net);
pthread_mutex_destroy(&THR_LOCK_time);
pthread_mutex_destroy(&THR_LOCK_charset);
- if (all_threads_killed)
- {
- pthread_mutex_destroy(&THR_LOCK_threads);
- pthread_cond_destroy(&THR_COND_threads);
- }
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
pthread_mutex_destroy(&LOCK_localtime_r);
#endif
@@ -256,7 +297,7 @@ my_bool my_thread_init(void)
#ifdef EXTRA_DEBUG_THREADS
fprintf(stderr,"my_thread_init(): thread_id: 0x%lx\n",
(ulong) pthread_self());
-#endif
+#endif
#if !defined(__WIN__) || defined(USE_TLS)
if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
@@ -264,7 +305,7 @@ my_bool my_thread_init(void)
#ifdef EXTRA_DEBUG_THREADS
fprintf(stderr,"my_thread_init() called more than once in thread 0x%lx\n",
(long) pthread_self());
-#endif
+#endif
goto end;
}
if (!(tmp= (struct st_my_thread_var *) calloc(1, sizeof(*tmp))))
@@ -287,14 +328,18 @@ my_bool my_thread_init(void)
#else
tmp->pthread_self= pthread_self();
#endif
- pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST);
+ my_pthread_mutex_init(&tmp->mutex, MY_MUTEX_INIT_FAST, "mysys_var->mutex",
+ 0);
pthread_cond_init(&tmp->suspend, NULL);
- tmp->init= 1;
+
+ tmp->stack_ends_here= (char*)&tmp +
+ STACK_DIRECTION * (long)my_thread_stack_size;
pthread_mutex_lock(&THR_LOCK_threads);
tmp->id= ++thread_id;
++THR_thread_count;
pthread_mutex_unlock(&THR_LOCK_threads);
+ tmp->init= 1;
#ifndef DBUG_OFF
/* Generate unique name for thread */
(void) my_thread_name();
@@ -325,9 +370,16 @@ void my_thread_end(void)
#ifdef EXTRA_DEBUG_THREADS
fprintf(stderr,"my_thread_end(): tmp: 0x%lx pthread_self: 0x%lx thread_id: %ld\n",
(long) tmp, (long) pthread_self(), tmp ? (long) tmp->id : 0L);
-#endif
+#endif
if (tmp && tmp->init)
{
+
+#if !defined(__bsdi__) && !defined(__OpenBSD__)
+ /* bsdi and openbsd 3.5 dumps core here */
+ pthread_cond_destroy(&tmp->suspend);
+#endif
+ pthread_mutex_destroy(&tmp->mutex);
+
#if !defined(DBUG_OFF)
/* tmp->dbug is allocated inside DBUG library */
if (tmp->dbug)
@@ -337,17 +389,19 @@ void my_thread_end(void)
tmp->dbug=0;
}
#endif
-#if !defined(__bsdi__) && !defined(__OpenBSD__)
- /* bsdi and openbsd 3.5 dumps core here */
- pthread_cond_destroy(&tmp->suspend);
-#endif
- pthread_mutex_destroy(&tmp->mutex);
#if !defined(__WIN__) || defined(USE_TLS)
+#ifndef DBUG_OFF
+ /* To find bugs when accessing unallocated data */
+ bfill(tmp, sizeof(tmp), 0x8F);
+#endif
free(tmp);
#else
tmp->init= 0;
#endif
+#if !defined(__WIN__) || defined(USE_TLS)
+ pthread_setspecific(THR_KEY_mysys,0);
+#endif
/*
Decrement counter for number of running threads. We are using this
in my_thread_global_end() to wait until all threads have called
@@ -360,10 +414,12 @@ void my_thread_end(void)
pthread_cond_signal(&THR_COND_threads);
pthread_mutex_unlock(&THR_LOCK_threads);
}
- /* The following free has to be done, even if my_thread_var() is 0 */
+ else
+ {
#if !defined(__WIN__) || defined(USE_TLS)
- pthread_setspecific(THR_KEY_mysys,0);
+ pthread_setspecific(THR_KEY_mysys,0);
#endif
+ }
}
struct st_my_thread_var *_my_thread_var(void)
@@ -371,6 +427,25 @@ struct st_my_thread_var *_my_thread_var(void)
return my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
}
+#ifndef DBUG_OFF
+/* Return pointer to DBUG for holding current state */
+
+extern void **my_thread_var_dbug()
+{
+ struct st_my_thread_var *tmp=
+ my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+ return tmp && tmp->init ? &tmp->dbug : 0;
+}
+#endif
+
+/* Return pointer to mutex_in_use */
+
+safe_mutex_t **my_thread_var_mutex_in_use()
+{
+ struct st_my_thread_var *tmp=
+ my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+ return tmp ? &tmp->mutex_in_use : 0;
+}
/****************************************************************************
Get name of current thread.
diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c
new file mode 100644
index 00000000000..d1e8331aaa1
--- /dev/null
+++ b/mysys/my_uuid.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 2007 MySQL AB, Sergei Golubchik & Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ implements Universal Unique Identifiers (UUIDs), as in
+ DCE 1.1: Remote Procedure Call,
+ Open Group Technical Standard Document Number C706, October 1997,
+ (supersedes C309 DCE: Remote Procedure Call 8/1994,
+ which was basis for ISO/IEC 11578:1996 specification)
+
+ A UUID has the following structure:
+
+ Field NDR Data Type Octet # Note
+ time_low unsigned long 0-3 The low field of the
+ timestamp.
+ time_mid unsigned short 4-5 The middle field of
+ the timestamp.
+ time_hi_and_version unsigned short 6-7 The high field of the
+ timestamp multiplexed
+ with the version number.
+ clock_seq_hi_and_reserved unsigned small 8 The high field of the
+ clock sequence multi-
+ plexed with the variant.
+ clock_seq_low unsigned small 9 The low field of the
+ clock sequence.
+ node character 10-15 The spatially unique node
+ identifier.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <myisampack.h> /* mi_int2store, mi_int4store */
+
+static my_bool my_uuid_inited= 0;
+static struct my_rnd_struct uuid_rand;
+static uint nanoseq;
+static ulonglong uuid_time= 0;
+static uchar uuid_suffix[2+6]; /* clock_seq and node */
+
+#ifdef THREAD
+pthread_mutex_t LOCK_uuid_generator;
+#endif
+
+/*
+ Number of 100-nanosecond intervals between
+ 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00
+*/
+
+#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * \
+ 1000 * 1000 * 10)
+#define UUID_VERSION 0x1000
+#define UUID_VARIANT 0x8000
+
+
+/* Helper function */
+
+static void set_clock_seq()
+{
+ uint16 clock_seq= ((uint)(my_rnd(&uuid_rand)*16383)) | UUID_VARIANT;
+ mi_int2store(uuid_suffix, clock_seq);
+}
+
+
+/**
+ Init structures needed for my_uuid
+
+ @func my_uuid_init()
+ @param seed1 Seed for random generator
+ @param seed2 Seed for random generator
+
+ @note
+ Seed1 & seed2 should NOT depend on clock. This is to be able to
+ generate a random mac address according to UUID specs.
+*/
+
+void my_uuid_init(ulong seed1, ulong seed2)
+{
+ uchar *mac= uuid_suffix+2;
+ ulonglong now;
+
+ if (my_uuid_inited)
+ return;
+ my_uuid_inited= 1;
+ now= my_getsystime();
+ nanoseq= 0;
+
+ if (my_gethwaddr(mac))
+ {
+ uint i;
+ /*
+ Generating random "hardware addr"
+
+ Specs explicitly specify that node identifier should NOT
+ correlate with a clock_seq value, so we use a separate
+ randominit() here.
+ */
+ /* purecov: begin inspected */
+ my_rnd_init(&uuid_rand, (ulong) (seed2+ now/2), (ulong) (now+rand()));
+ for (i=0; i < sizeof(mac); i++)
+ mac[i]= (uchar)(my_rnd(&uuid_rand)*255);
+ /* purecov: end */
+ }
+ my_rnd_init(&uuid_rand, (ulong) (seed1 + now), (ulong) (now/2+ getpid()));
+ set_clock_seq();
+ pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
+}
+
+
+/**
+ Create a global unique identifier (uuid)
+
+ @func my_uuid()
+ @param to Store uuid here. Must be of size MY_uuid_SIZE (16)
+*/
+
+void my_uuid(uchar *to)
+{
+ ulonglong tv;
+ uint32 time_low;
+ uint16 time_mid, time_hi_and_version;
+
+ DBUG_ASSERT(my_uuid_inited);
+
+ pthread_mutex_lock(&LOCK_uuid_generator);
+ tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq;
+
+ if (likely(tv > uuid_time))
+ {
+ /*
+ Current time is ahead of last timestamp, as it should be.
+ If we "borrowed time", give it back, just as long as we
+ stay ahead of the previous timestamp.
+ */
+ if (nanoseq)
+ {
+ ulong delta;
+ DBUG_ASSERT((tv > uuid_time) && (nanoseq > 0));
+ /*
+ -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time)
+ */
+ delta= min(nanoseq, (ulong)(tv - uuid_time -1));
+ tv-= delta;
+ nanoseq-= delta;
+ }
+ }
+ else
+ {
+ if (unlikely(tv == uuid_time))
+ {
+ /*
+ For low-res system clocks. If several requests for UUIDs
+ end up on the same tick, we add a nano-second to make them
+ different.
+ ( current_timestamp + nanoseq * calls_in_this_period )
+ may end up > next_timestamp; this is OK. Nonetheless, we'll
+ try to unwind nanoseq when we get a chance to.
+ If nanoseq overflows, we'll start over with a new numberspace
+ (so the if() below is needed so we can avoid the ++tv and thus
+ match the follow-up if() if nanoseq overflows!).
+ */
+ if (likely(++nanoseq))
+ ++tv;
+ }
+
+ if (unlikely(tv <= uuid_time))
+ {
+ /*
+ If the admin changes the system clock (or due to Daylight
+ Saving Time), the system clock may be turned *back* so we
+ go through a period once more for which we already gave out
+ UUIDs. To avoid duplicate UUIDs despite potentially identical
+ times, we make a new random component.
+ We also come here if the nanoseq "borrowing" overflows.
+ In either case, we throw away any nanoseq borrowing since it's
+ irrelevant in the new numberspace.
+ */
+ set_clock_seq();
+ tv= my_getsystime() + UUID_TIME_OFFSET;
+ nanoseq= 0;
+ DBUG_PRINT("uuid",("making new numberspace"));
+ }
+ }
+
+ uuid_time=tv;
+ pthread_mutex_unlock(&LOCK_uuid_generator);
+
+ time_low= (uint32) (tv & 0xFFFFFFFF);
+ time_mid= (uint16) ((tv >> 32) & 0xFFFF);
+ time_hi_and_version= (uint16) ((tv >> 48) | UUID_VERSION);
+
+ /*
+ Note, that the standard does NOT specify byte ordering in
+ multi-byte fields. it's implementation defined (but must be
+ the same for all fields).
+ We use big-endian, so we can use memcmp() to compare UUIDs
+ and for straightforward UUID to string conversion.
+ */
+ mi_int4store(to, time_low);
+ mi_int2store(to+4, time_mid);
+ mi_int2store(to+6, time_hi_and_version);
+ bmove(to+8, uuid_suffix, sizeof(uuid_suffix));
+}
+
+
+/**
+ Convert uuid to string representation
+
+ @func my_uuid2str()
+ @param guid uuid
+ @param s Output buffer.Must be at least MY_UUID_STRING_LENGTH+1 large.
+*/
+void my_uuid2str(const uchar *guid, char *s)
+{
+ int i;
+ for (i=0; i < MY_UUID_SIZE; i++)
+ {
+ *s++= _dig_vec_lower[guid[i] >>4];
+ *s++= _dig_vec_lower[guid[i] & 15];
+ if(i == 3 || i == 5 || i == 7 || i == 9)
+ *s++= '-';
+ }
+}
+
+void my_uuid_end()
+{
+ if (my_uuid_inited)
+ {
+ my_uuid_inited= 0;
+ pthread_mutex_destroy(&LOCK_uuid_generator);
+ }
+}
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
index d1b07b61408..c9bc33df8c4 100644
--- a/mysys/my_wincond.c
+++ b/mysys/my_wincond.c
@@ -126,7 +126,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
EnterCriticalSection(&cond->lock_waiting);
cond->waiting--;
- if (cond->waiting == 0 && result == (WAIT_OBJECT_0+BROADCAST))
+ if (cond->waiting == 0)
{
/*
We're the last waiter to be notified or to stop waiting, so
diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c
index e94369bec32..0af6a47ec4a 100644
--- a/mysys/my_winthread.c
+++ b/mysys/my_winthread.c
@@ -77,12 +77,15 @@ pthread_handler_t pthread_start(void *param)
{
pthread_handler func=((struct pthread_map *) param)->func;
void *func_param=((struct pthread_map *) param)->param;
+ void *result;
my_thread_init(); /* Will always succeed in windows */
pthread_mutex_lock(&THR_LOCK_thread); /* Wait for beginthread to return */
win_pthread_self=((struct pthread_map *) param)->pthreadself;
pthread_mutex_unlock(&THR_LOCK_thread);
free((char*) param); /* Free param from create */
- pthread_exit((void*) (*func)(func_param));
+ result= (void*) (*func)(func_param);
+ my_thread_end();
+ pthread_exit(result);
return 0; /* Safety */
}
@@ -92,21 +95,28 @@ int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
{
HANDLE hThread;
struct pthread_map *map;
+ DWORD StackSize= 0;
+ int priority= 0;
DBUG_ENTER("pthread_create");
if (!(map=malloc(sizeof(*map))))
DBUG_RETURN(-1);
map->func=func;
map->param=param;
+ if (attr != NULL)
+ {
+ StackSize= attr->dwStackSize;
+ priority= attr->priority;
+ }
+ if (StackSize == 0)
+ StackSize= PTHREAD_STACK_MIN;
pthread_mutex_lock(&THR_LOCK_thread);
#ifdef __BORLANDC__
hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
- attr->dwStackSize ? attr->dwStackSize :
- 65535, (void*) map);
+ StackSize, (void*) map);
#else
hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
- attr->dwStackSize ? attr->dwStackSize :
- 65535, (void*) map);
+ StackSize, (void*) map);
#endif
DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
*thread_id=map->pthreadself=hThread;
@@ -119,7 +129,7 @@ int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
("Can't create thread to handle request (error %d)",error));
DBUG_RETURN(error ? error : -1);
}
- VOID(SetThreadPriority(hThread, attr->priority)) ;
+ VOID(SetThreadPriority(hThread, priority)) ;
DBUG_RETURN(0);
}
diff --git a/mysys/my_write.c b/mysys/my_write.c
index c67b1d8f3f2..7f8b85c241e 100644
--- a/mysys/my_write.c
+++ b/mysys/my_write.c
@@ -25,7 +25,7 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
size_t writenbytes, written;
uint errors;
DBUG_ENTER("my_write");
- DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
+ DBUG_PRINT("my",("fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
Filedes, (long) Buffer, (ulong) Count, MyFlags));
errors=0; written=0;
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index 6e0959ae08c..113b64005f2 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -33,6 +33,7 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
#include <my_no_pthread.h>
#endif
+
/*
EDQUOT is used only in 3 C files only in mysys/. If it does not exist on
system, we set it to some value which can never happen.
@@ -42,3 +43,5 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
#endif
void my_error_unregister_all(void);
+void my_thread_destroy_mutex(void);
+my_bool my_wait_for_other_threads_to_die(uint number_of_threads);
diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c
index 905733524e3..59bc4e73af7 100644
--- a/mysys/safemalloc.c
+++ b/mysys/safemalloc.c
@@ -439,7 +439,6 @@ void TERMINATE(FILE *file, uint flag)
This is usefull to call from withing a debugger
*/
-
void sf_malloc_report_allocated(void *memory)
{
struct st_irem *irem;
diff --git a/mysys/test_thr_mutex.c b/mysys/test_thr_mutex.c
new file mode 100644
index 00000000000..0bd14a0d31b
--- /dev/null
+++ b/mysys/test_thr_mutex.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 2008 Sun Microsystems, Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Testing of deadlock detector */
+
+#include <my_global.h>
+#include <mysys_priv.h>
+
+
+int main(int argc __attribute__((unused)), char** argv)
+{
+ pthread_mutex_t LOCK_A, LOCK_B, LOCK_C, LOCK_D, LOCK_E, LOCK_F, LOCK_G;
+ pthread_mutex_t LOCK_H, LOCK_I;
+ MY_INIT(argv[0]);
+ DBUG_ENTER("main");
+
+ DBUG_PUSH("d:t:O,/tmp/trace");
+ printf("This program is testing the mutex deadlock detection.\n"
+ "It should print out different failures of wrong mutex usage"
+ "on stderr\n\n");
+
+ safe_mutex_deadlock_detector= 1;
+ pthread_mutex_init(&LOCK_A, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_B, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_C, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_D, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_E, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_F, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_G, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_H, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_I, MY_MUTEX_INIT_FAST);
+
+ printf("Testing A->B and B->A\n");
+ fflush(stdout);
+ pthread_mutex_lock(&LOCK_A);
+ pthread_mutex_lock(&LOCK_B);
+ pthread_mutex_unlock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_B);
+
+ /* Test different (wrong) lock order */
+ pthread_mutex_lock(&LOCK_B);
+ pthread_mutex_lock(&LOCK_A); /* Should give warning */
+
+ pthread_mutex_unlock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_B);
+
+ /* Check that we don't get another warning for same lock */
+ printf("Testing A->B and B->A again (should not give a warning)\n");
+ pthread_mutex_lock(&LOCK_B);
+ pthread_mutex_lock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_B);
+
+ /*
+ Test of ring with many mutex
+ We also unlock mutex in different orders to get the unlock code properly
+ tested.
+ */
+ printf("Testing A->C and C->D and D->A\n");
+ pthread_mutex_lock(&LOCK_A);
+ pthread_mutex_lock(&LOCK_C);
+ pthread_mutex_unlock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_C);
+ pthread_mutex_lock(&LOCK_C);
+ pthread_mutex_lock(&LOCK_D);
+ pthread_mutex_unlock(&LOCK_D);
+ pthread_mutex_unlock(&LOCK_C);
+
+ pthread_mutex_lock(&LOCK_D);
+ pthread_mutex_lock(&LOCK_A); /* Should give warning */
+
+ pthread_mutex_unlock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_D);
+
+ printf("Testing E -> F ; H -> I ; F -> H ; H -> I -> E\n");
+ fflush(stdout);
+
+ pthread_mutex_lock(&LOCK_E);
+ pthread_mutex_lock(&LOCK_F);
+ pthread_mutex_unlock(&LOCK_E);
+ pthread_mutex_unlock(&LOCK_F);
+ pthread_mutex_lock(&LOCK_H);
+ pthread_mutex_lock(&LOCK_I);
+ pthread_mutex_unlock(&LOCK_I);
+ pthread_mutex_unlock(&LOCK_H);
+ pthread_mutex_lock(&LOCK_F);
+ pthread_mutex_lock(&LOCK_H);
+ pthread_mutex_unlock(&LOCK_H);
+ pthread_mutex_unlock(&LOCK_F);
+
+ pthread_mutex_lock(&LOCK_H);
+ pthread_mutex_lock(&LOCK_I);
+ pthread_mutex_lock(&LOCK_E); /* Should give warning */
+
+ pthread_mutex_unlock(&LOCK_E);
+ pthread_mutex_unlock(&LOCK_I);
+ pthread_mutex_unlock(&LOCK_H);
+
+ printf("\nFollowing shouldn't give any warnings\n");
+ printf("Testing A->B and B->A without deadlock detection\n");
+ fflush(stdout);
+
+ /* Reinitialize mutex to get rid of old wrong usage markers */
+ pthread_mutex_destroy(&LOCK_A);
+ pthread_mutex_destroy(&LOCK_B);
+ pthread_mutex_init(&LOCK_A, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_B, MY_MUTEX_INIT_FAST);
+
+ /* Start testing */
+ my_pthread_mutex_lock(&LOCK_A, MYF(MYF_NO_DEADLOCK_DETECTION));
+ pthread_mutex_lock(&LOCK_B);
+ pthread_mutex_unlock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_B);
+
+ pthread_mutex_lock(&LOCK_A);
+ my_pthread_mutex_lock(&LOCK_B, MYF(MYF_NO_DEADLOCK_DETECTION));
+ pthread_mutex_unlock(&LOCK_A);
+ pthread_mutex_unlock(&LOCK_B);
+
+ printf("Testing A -> C ; B -> C ; A->B\n");
+ fflush(stdout);
+ pthread_mutex_lock(&LOCK_A);
+ pthread_mutex_lock(&LOCK_C);
+ pthread_mutex_unlock(&LOCK_C);
+ pthread_mutex_unlock(&LOCK_A);
+
+ pthread_mutex_lock(&LOCK_B);
+ pthread_mutex_lock(&LOCK_C);
+ pthread_mutex_unlock(&LOCK_C);
+ pthread_mutex_unlock(&LOCK_B);
+
+ pthread_mutex_lock(&LOCK_A);
+ pthread_mutex_lock(&LOCK_B);
+ pthread_mutex_unlock(&LOCK_B);
+ pthread_mutex_unlock(&LOCK_A);
+
+ /* Cleanup */
+ pthread_mutex_destroy(&LOCK_A);
+ pthread_mutex_destroy(&LOCK_B);
+ pthread_mutex_destroy(&LOCK_C);
+ pthread_mutex_destroy(&LOCK_D);
+ pthread_mutex_destroy(&LOCK_E);
+ pthread_mutex_destroy(&LOCK_F);
+ pthread_mutex_destroy(&LOCK_G);
+ pthread_mutex_destroy(&LOCK_H);
+ pthread_mutex_destroy(&LOCK_I);
+
+ my_end(MY_DONT_FREE_DBUG);
+ exit(0);
+}
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index b13e8411771..a9ff1b05881 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -24,7 +24,7 @@ Locks are prioritized according to:
The current lock types are:
-TL_READ # Low priority read
+TL_READ # Low priority read
TL_READ_WITH_SHARED_LOCKS
TL_READ_HIGH_PRIORITY # High priority read
TL_READ_NO_INSERT # Read without concurrent inserts
@@ -57,17 +57,23 @@ check_status:
In MyISAM this is a simple check if the insert can be done
at the end of the datafile.
update_status:
- Before a write lock is released, this function is called.
- In MyISAM this functions updates the count and length of the datafile
+ in thr_reschedule_write_lock(), when an insert delayed thread
+ downgrades TL_WRITE lock to TL_WRITE_DELAYED, to allow SELECT
+ threads to proceed.
+ A storage engine should also call update_status internally
+ in the ::external_lock(F_UNLCK) method.
+ In MyISAM and CSV this functions updates the length of the datafile.
get_status:
When one gets a lock this functions is called.
In MyISAM this stores the number of rows and size of the datafile
for concurrent reads.
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
-TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
-multiple read locks.
+TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same
+time as multiple read locks.
+In addition, if lock->allow_multiple_concurrent_insert is set then there can
+be any number of TL_WRITE_CONCURRENT_INSERT locks aktive at the same time.
*/
#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
@@ -148,7 +154,8 @@ static int check_lock(struct st_lock_list *list, const char* lock_type,
}
if (same_owner &&
!thr_lock_owner_equal(data->owner, first_owner) &&
- last_lock_type != TL_WRITE_ALLOW_WRITE)
+ last_lock_type != TL_WRITE_ALLOW_WRITE &&
+ last_lock_type != TL_WRITE_CONCURRENT_INSERT)
{
fprintf(stderr,
"Warning: Found locks from different threads in %s: %s\n",
@@ -201,7 +208,7 @@ static void check_locks(THR_LOCK *lock, const char *where,
THR_LOCK_DATA *data;
for (data=lock->read.data ; data ; data=data->next)
{
- if ((int) data->type == (int) TL_READ_NO_INSERT)
+ if (data->type == TL_READ_NO_INSERT)
count++;
/* Protect against infinite loop. */
DBUG_ASSERT(count <= lock->read_no_write_count);
@@ -250,7 +257,22 @@ static void check_locks(THR_LOCK *lock, const char *where,
}
}
else
- { /* Have write lock */
+ {
+ /* We have at least one write lock */
+ if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT)
+ {
+ THR_LOCK_DATA *data;
+ for (data=lock->write.data->next ; data ; data=data->next)
+ {
+ if (data->type != TL_WRITE_CONCURRENT_INSERT)
+ {
+ fprintf(stderr,
+ "Warning at '%s': Found TL_WRITE_CONCURRENT_INSERT lock mixed with other write locks\n",
+ where);
+ break;
+ }
+ }
+ }
if (lock->write_wait.data)
{
if (!allow_no_locks &&
@@ -472,7 +494,8 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
{
result= THR_LOCK_SUCCESS;
if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, 0);
+ (*data->lock->get_status)(data->status_param,
+ data->type == TL_WRITE_CONCURRENT_INSERT);
check_locks(data->lock,"got wait_for_lock",0);
}
pthread_mutex_unlock(&data->lock->mutex);
@@ -511,7 +534,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
/* Request for READ lock */
if (lock->write.data)
{
- /* We can allow a read lock even if there is already a write lock
+ /*
+ We can allow a read lock even if there is already a write lock
on the table in one the following cases:
- This thread alread have a write lock on the table
- The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
@@ -555,11 +579,11 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
(*lock->read.last)=data; /* Add to running FIFO */
data->prev=lock->read.last;
lock->read.last= &data->next;
- if (lock->get_status)
- (*lock->get_status)(data->status_param, 0);
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count++;
check_locks(lock,"read lock with no write locks",0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, 0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
@@ -623,16 +647,18 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
The following test will not work if the old lock was a
TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
the same thread, but this will never happen within MySQL.
+
+ The idea is to allow us to get a lock at once if we already have
+ a write lock or if there is no pending write locks and if all
+ write locks are of the same type and are either
+ TL_WRITE_ALLOW_WRITE or TL_WRITE_CONCURRENT_INSERT
*/
if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
- (lock_type == TL_WRITE_ALLOW_WRITE &&
- !lock->write_wait.data &&
- lock->write.data->type == TL_WRITE_ALLOW_WRITE))
+ (!lock->write_wait.data && lock_type == lock->write.data->type &&
+ (lock_type == TL_WRITE_ALLOW_WRITE ||
+ (lock_type == TL_WRITE_CONCURRENT_INSERT &&
+ lock->allow_multiple_concurrent_insert))))
{
- /*
- We have already got a write lock or all locks are
- TL_WRITE_ALLOW_WRITE
- */
DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d",
(ulong) lock->write_wait.data,
lock->write.data->type));
@@ -641,8 +667,9 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
data->prev=lock->write.last;
lock->write.last= &data->next;
check_locks(lock,"second write lock",0);
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, 0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param,
+ lock_type == TL_WRITE_CONCURRENT_INSERT);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
}
@@ -675,8 +702,8 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
(*lock->write.last)=data; /* Add as current write lock */
data->prev=lock->write.last;
lock->write.last= &data->next;
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, concurrent_insert);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, concurrent_insert);
check_locks(lock,"only write lock",0);
statistic_increment(locks_immediate,&THR_LOCK_lock);
goto end;
@@ -784,16 +811,6 @@ void thr_unlock(THR_LOCK_DATA *data)
}
else
lock->write.last=data->prev;
- if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
- {
- if (lock->update_status)
- (*lock->update_status)(data->status_param);
- }
- else
- {
- if (lock->restore_status)
- (*lock->restore_status)(data->status_param);
- }
if (lock_type == TL_READ_NO_INSERT)
lock->read_no_write_count--;
data->type=TL_UNLOCK; /* Mark unlocked */
@@ -816,7 +833,6 @@ static void wake_up_waiters(THR_LOCK *lock)
{
THR_LOCK_DATA *data;
enum thr_lock_type lock_type;
-
DBUG_ENTER("wake_up_waiters");
if (!lock->write.data) /* If no active write locks */
@@ -1379,8 +1395,8 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
{
if (!lock->read.data) /* No read locks */
{ /* We have the lock */
- if (data->lock->get_status)
- (*data->lock->get_status)(data->status_param, 0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param, 0);
pthread_mutex_unlock(&lock->mutex);
DBUG_RETURN(0);
}
@@ -1518,7 +1534,7 @@ struct st_test {
enum thr_lock_type lock_type;
};
-THR_LOCK locks[5]; /* 4 locks */
+THR_LOCK locks[6]; /* Number of locks +1 */
struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
@@ -1538,9 +1554,20 @@ struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
-struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
- test_7,test_8,test_9,test_10,test_11,test_12,
- test_13,test_14,test_15,test_16};
+struct st_test test_17[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_18[] = {{5,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_19[] = {{5,TL_READ}};
+struct st_test test_20[] = {{5,TL_READ_NO_INSERT}};
+struct st_test test_21[] = {{5,TL_WRITE}};
+
+
+struct st_test *tests[]=
+{
+ test_0, test_1, test_2, test_3, test_4, test_5, test_6, test_7, test_8,
+ test_9, test_10, test_11, test_12, test_13, test_14, test_15, test_16,
+ test_17, test_18, test_19, test_20, test_21
+};
+
int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
sizeof(test_1)/sizeof(struct st_test),
sizeof(test_2)/sizeof(struct st_test),
@@ -1557,7 +1584,12 @@ int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
sizeof(test_13)/sizeof(struct st_test),
sizeof(test_14)/sizeof(struct st_test),
sizeof(test_15)/sizeof(struct st_test),
- sizeof(test_16)/sizeof(struct st_test)
+ sizeof(test_16)/sizeof(struct st_test),
+ sizeof(test_17)/sizeof(struct st_test),
+ sizeof(test_18)/sizeof(struct st_test),
+ sizeof(test_19)/sizeof(struct st_test),
+ sizeof(test_20)/sizeof(struct st_test),
+ sizeof(test_21)/sizeof(struct st_test)
};
@@ -1601,7 +1633,6 @@ static void *test_thread(void *arg)
printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
-
thr_lock_info_init(&lock_info);
thr_lock_owner_init(&owner, &lock_info);
for (i=0; i < lock_counts[param] ; i++)
@@ -1647,7 +1678,8 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
{
pthread_t tid;
pthread_attr_t thr_attr;
- int i,*param,error;
+ int *param,error;
+ uint i;
MY_INIT(argv[0]);
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
DBUG_PUSH(argv[1]+2);
@@ -1667,13 +1699,14 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
exit(1);
}
- for (i=0 ; i < (int) array_elements(locks) ; i++)
+ for (i=0 ; i < array_elements(locks) ; i++)
{
thr_lock_init(locks+i);
locks[i].check_status= test_check_status;
locks[i].update_status=test_update_status;
locks[i].copy_status= test_copy_status;
locks[i].get_status= test_get_status;
+ locks[i].allow_multiple_concurrent_insert= 1;
}
if ((error=pthread_attr_init(&thr_attr)))
{
@@ -1699,7 +1732,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
#ifdef HAVE_THR_SETCONCURRENCY
VOID(thr_setconcurrency(2));
#endif
- for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
+ for (i=0 ; i < array_elements(lock_counts) ; i++)
{
param=(int*) malloc(sizeof(int));
*param=i;
@@ -1731,7 +1764,7 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
}
if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
- for (i=0 ; i < (int) array_elements(locks) ; i++)
+ for (i=0 ; i < array_elements(locks) ; i++)
thr_lock_delete(locks+i);
#ifdef EXTRA_DEBUG
if (found_errors)
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
index 8f9928026ba..2fdf3d25a5c 100644
--- a/mysys/thr_mutex.c
+++ b/mysys/thr_mutex.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
+/* Copyright (C) 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
#include "mysys_priv.h"
#include "my_static.h"
#include <m_string.h>
+#include <hash.h>
#ifndef DO_NOT_REMOVE_THREAD_WRAPPERS
/* Remove wrappers */
@@ -34,34 +35,106 @@
#undef pthread_mutex_destroy
#undef pthread_cond_wait
#undef pthread_cond_timedwait
+#undef safe_mutex_free_deadlock_data
#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
-#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
+#define pthread_mutex_init(a,b) my_pthread_noposix_mutex_init((a),(b))
#endif
#endif /* DO_NOT_REMOVE_THREAD_WRAPPERS */
static pthread_mutex_t THR_LOCK_mutex;
static ulong safe_mutex_count= 0; /* Number of mutexes created */
+static ulong safe_mutex_id= 0;
+my_bool safe_mutex_deadlock_detector= 1; /* On by default */
+
#ifdef SAFE_MUTEX_DETECT_DESTROY
-static struct st_safe_mutex_info_t *safe_mutex_root= NULL;
+static struct st_safe_mutex_create_info_t *safe_mutex_create_root= NULL;
#endif
+static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
+ safe_mutex_deadlock_t *locked_mutex);
+static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
+ safe_mutex_t *current_mutex);
+static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
+ safe_mutex_t *delete_mutex);
+static my_bool remove_from_used_mutex(safe_mutex_deadlock_t *locked_mutex,
+ safe_mutex_t *mutex);
+static void print_deadlock_warning(safe_mutex_t *new_mutex,
+ safe_mutex_t *conflicting_mutex);
+
void safe_mutex_global_init(void)
{
pthread_mutex_init(&THR_LOCK_mutex,MY_MUTEX_INIT_FAST);
+ safe_mutex_id= safe_mutex_count= 0;
+ safe_mutex_deadlock_detector= 1;
+
+#ifdef SAFE_MUTEX_DETECT_DESTROY
+ safe_mutex_create_root= 0;
+#endif
+}
+
+static inline void remove_from_active_list(safe_mutex_t *mp)
+{
+ if (!(mp->active_flags & (MYF_NO_DEADLOCK_DETECTION | MYF_TRY_LOCK)))
+ {
+ /* Remove mutex from active mutex linked list */
+ if (mp->next)
+ mp->next->prev= mp->prev;
+ if (mp->prev)
+ mp->prev->next= mp->next;
+ else
+ *my_thread_var_mutex_in_use()= mp->next;
+ }
+ mp->prev= mp->next= 0;
}
int safe_mutex_init(safe_mutex_t *mp,
const pthread_mutexattr_t *attr __attribute__((unused)),
+ const char *name,
+ myf my_flags,
const char *file,
uint line)
{
+ DBUG_ENTER("safe_mutex_init");
+ DBUG_PRINT("enter",("mutex: 0x%lx name: %s", (ulong) mp, name));
bzero((char*) mp,sizeof(*mp));
pthread_mutex_init(&mp->global,MY_MUTEX_INIT_ERRCHK);
pthread_mutex_init(&mp->mutex,attr);
/* Mark that mutex is initialized */
mp->file= file;
mp->line= line;
+ /* Skip the very common '&' prefix from the autogenerated name */
+ mp->name= name[0] == '&' ? name + 1 : name;
+
+ if (safe_mutex_deadlock_detector && !( my_flags & MYF_NO_DEADLOCK_DETECTION))
+ {
+ if (!my_multi_malloc(MY_FAE | MY_WME,
+ &mp->locked_mutex, sizeof(*mp->locked_mutex),
+ &mp->used_mutex, sizeof(*mp->used_mutex), NullS))
+ {
+ /* Disable deadlock handling for this mutex */
+ my_flags|= MYF_NO_DEADLOCK_DETECTION;
+ }
+ else
+ {
+ pthread_mutex_lock(&THR_LOCK_mutex);
+ mp->id= ++safe_mutex_id;
+ pthread_mutex_unlock(&THR_LOCK_mutex);
+ hash_init(mp->locked_mutex, &my_charset_bin,
+ 1000,
+ offsetof(safe_mutex_deadlock_t, id),
+ sizeof(mp->id),
+ 0, 0, HASH_UNIQUE);
+ hash_init(mp->used_mutex, &my_charset_bin,
+ 1000,
+ offsetof(safe_mutex_t, id),
+ sizeof(mp->id),
+ 0, 0, HASH_UNIQUE);
+ }
+ }
+ else
+ my_flags|= MYF_NO_DEADLOCK_DETECTION;
+ mp->create_flags= my_flags;
#ifdef SAFE_MUTEX_DETECT_DESTROY
/*
@@ -70,7 +143,7 @@ int safe_mutex_init(safe_mutex_t *mp,
*/
if ((mp->info= (safe_mutex_info_t *) malloc(sizeof(safe_mutex_info_t))))
{
- struct st_safe_mutex_info_t *info =mp->info;
+ struct st_safe_mutex_info_t *info= mp->info;
info->init_file= file;
info->init_line= line;
@@ -78,22 +151,25 @@ int safe_mutex_init(safe_mutex_t *mp,
info->next= NULL;
pthread_mutex_lock(&THR_LOCK_mutex);
- if ((info->next= safe_mutex_root))
- safe_mutex_root->prev= info;
- safe_mutex_root= info;
+ if ((info->next= safe_mutex_create_root))
+ safe_mutex_create_root->prev= info;
+ safe_mutex_create_root= info;
safe_mutex_count++;
pthread_mutex_unlock(&THR_LOCK_mutex);
}
#else
thread_safe_increment(safe_mutex_count, &THR_LOCK_mutex);
#endif /* SAFE_MUTEX_DETECT_DESTROY */
- return 0;
+ DBUG_RETURN(0);
}
-int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line)
+int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
+ uint line)
{
int error;
+ DBUG_PRINT("mutex", ("%s (0x%lx) locking", mp->name ? mp->name : "Null",
+ (ulong) mp));
if (!mp->file)
{
fprintf(stderr,
@@ -106,12 +182,13 @@ int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint l
pthread_mutex_lock(&mp->global);
if (mp->count > 0)
{
- if (try_lock)
- {
- pthread_mutex_unlock(&mp->global);
- return EBUSY;
- }
- else if (pthread_equal(pthread_self(),mp->thread))
+ /*
+ Check that we are not trying to lock mutex twice. This is an error
+ even if we are using 'try_lock' as it's not portably what happens
+ if you lock the mutex many times and this is in any case bad
+ behaviour that should not be encouraged
+ */
+ if (pthread_equal(pthread_self(),mp->thread))
{
fprintf(stderr,
"safe_mutex: Trying to lock mutex at %s, line %d, when the"
@@ -139,7 +216,7 @@ int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint l
instead just return EBUSY, since this is the expected behaviour
of trylock().
*/
- if (try_lock)
+ if (my_flags & MYF_TRY_LOCK)
{
error= pthread_mutex_trylock(&mp->mutex);
if (error == EBUSY)
@@ -150,22 +227,109 @@ int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint l
if (error || (error=pthread_mutex_lock(&mp->global)))
{
- fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
- error, file, line);
+ fprintf(stderr,"Got error %d when trying to lock mutex %s at %s, line %d\n",
+ error, mp->name, file, line);
fflush(stderr);
abort();
}
mp->thread= pthread_self();
if (mp->count++)
{
- fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, \
-line %d more than 1 time\n", file,line);
+ fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex %s at %s, "
+ "line %d more than 1 time\n", mp->name, file,line);
fflush(stderr);
abort();
}
mp->file= file;
- mp->line=line;
+ mp->line= line;
+ mp->active_flags= mp->create_flags | my_flags;
pthread_mutex_unlock(&mp->global);
+
+ /* Deadlock detection */
+
+ mp->prev= mp->next= 0;
+ if (!(mp->active_flags & (MYF_TRY_LOCK | MYF_NO_DEADLOCK_DETECTION)))
+ {
+ safe_mutex_t **mutex_in_use= my_thread_var_mutex_in_use();
+
+ if (!mutex_in_use)
+ {
+ /* thread has not called my_thread_init() */
+ mp->active_flags|= MYF_NO_DEADLOCK_DETECTION;
+ }
+ else
+ {
+ safe_mutex_t *mutex_root;
+ if ((mutex_root= *mutex_in_use)) /* If not first locked */
+ {
+ /*
+ Protect locked_mutex against changes if a mutex is deleted
+ */
+ pthread_mutex_lock(&THR_LOCK_mutex);
+
+ if (!hash_search(mutex_root->locked_mutex, (uchar*) &mp->id, 0))
+ {
+ safe_mutex_deadlock_t *deadlock;
+ safe_mutex_t *mutex;
+
+ /* Create object to store mutex info */
+ if (!(deadlock= my_malloc(sizeof(*deadlock),
+ MYF(MY_ZEROFILL | MY_WME | MY_FAE))))
+ goto abort_loop;
+ deadlock->name= mp->name;
+ deadlock->id= mp->id;
+ deadlock->mutex= mp;
+ /* The following is useful for debugging wrong mutex usage */
+ deadlock->file= file;
+ deadlock->line= line;
+
+ /* Check if potential deadlock */
+ mutex= mutex_root;
+ do
+ {
+ if (hash_search(mp->locked_mutex, (uchar*) &mutex->id, 0))
+ {
+ print_deadlock_warning(mp, mutex);
+ /* Mark wrong usage to avoid future warnings for same error */
+ deadlock->warning_only= 1;
+ add_to_locked_mutex(deadlock, mutex_root);
+ DBUG_ASSERT(deadlock->count > 0);
+ goto abort_loop;
+ }
+ }
+ while ((mutex= mutex->next));
+
+ /*
+ Copy current mutex and all mutex that has been locked
+ after current mutex (mp->locked_mutex) to all mutex that
+ was locked before previous mutex (mutex_root->used_mutex)
+
+ For example if A->B would have been done before and we
+ are now locking (C) in B->C, then we would add C into
+ B->locked_mutex and A->locked_mutex
+ */
+ my_hash_iterate(mutex_root->used_mutex,
+ (my_hash_walk_action) add_used_to_locked_mutex,
+ deadlock);
+
+ /*
+ Copy all current mutex and all mutex locked after current one
+ into the prev mutex
+ */
+ add_used_to_locked_mutex(mutex_root, deadlock);
+ DBUG_ASSERT(deadlock->count > 0);
+ }
+ abort_loop:
+ pthread_mutex_unlock(&THR_LOCK_mutex);
+ }
+ /* Link mutex into mutex_in_use list */
+ if ((mp->next= *mutex_in_use))
+ (*mutex_in_use)->prev= mp;
+ *mutex_in_use= mp;
+ }
+ }
+
+ DBUG_PRINT("mutex", ("%s (0x%lx) locked", mp->name, (ulong) mp));
return error;
}
@@ -173,23 +337,34 @@ line %d more than 1 time\n", file,line);
int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
{
int error;
+ DBUG_PRINT("mutex", ("%s (0x%lx) unlocking", mp->name, (ulong) mp));
pthread_mutex_lock(&mp->global);
if (mp->count == 0)
{
- fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %d\n Last used at %s, line: %d\n",
- file,line,mp->file ? mp->file : "",mp->line);
+ fprintf(stderr,
+ "safe_mutex: Trying to unlock mutex %s that wasn't locked at "
+ "%s, line %d\n"
+ "Last used at %s, line: %d\n",
+ mp->name ? mp->name : "Null", file, line,
+ mp->file ? mp->file : "Null", mp->line);
fflush(stderr);
abort();
}
if (!pthread_equal(pthread_self(),mp->thread))
{
- fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
- file,line,mp->file,mp->line);
+ fprintf(stderr,
+ "safe_mutex: Trying to unlock mutex %s at %s, line %d that was "
+ "locked by "
+ "another thread at: %s, line: %d\n",
+ mp->name, file, line, mp->file, mp->line);
fflush(stderr);
abort();
}
mp->thread= 0;
mp->count--;
+
+ remove_from_active_list(mp);
+
#ifdef __WIN__
pthread_mutex_unlock(&mp->mutex);
error=0;
@@ -197,7 +372,9 @@ int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
error=pthread_mutex_unlock(&mp->mutex);
if (error)
{
- fprintf(stderr,"safe_mutex: Got error: %d (%d) when trying to unlock mutex at %s, line %d\n", error, errno, file, line);
+ fprintf(stderr,
+ "safe_mutex: Got error: %d (%d) when trying to unlock mutex "
+ "%s at %s, line %d\n", error, errno, mp->name, file, line);
fflush(stderr);
abort();
}
@@ -211,43 +388,62 @@ int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
uint line)
{
int error;
+ safe_mutex_t save_state;
+
pthread_mutex_lock(&mp->global);
if (mp->count == 0)
{
- fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %d\n",file,line);
+ fprintf(stderr,
+ "safe_mutex: Trying to cond_wait on a unlocked mutex %s at %s, "
+ "line %d\n",
+ mp->name ? mp->name : "Null", file, line);
fflush(stderr);
abort();
}
if (!pthread_equal(pthread_self(),mp->thread))
{
- fprintf(stderr,"safe_mutex: Trying to cond_wait on a mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
- file,line,mp->file,mp->line);
+ fprintf(stderr,
+ "safe_mutex: Trying to cond_wait on a mutex %s at %s, line %d "
+ "that was locked by another thread at: %s, line: %d\n",
+ mp->name, file, line, mp->file, mp->line);
fflush(stderr);
abort();
}
if (mp->count-- != 1)
{
- fprintf(stderr,"safe_mutex: Count was %d on locked mutex at %s, line %d\n",
- mp->count+1, file, line);
+ fprintf(stderr,
+ "safe_mutex: Count was %d on locked mutex %s at %s, line %d\n",
+ mp->count+1, mp->name, file, line);
fflush(stderr);
abort();
}
+ save_state= *mp;
+ remove_from_active_list(mp);
pthread_mutex_unlock(&mp->global);
error=pthread_cond_wait(cond,&mp->mutex);
pthread_mutex_lock(&mp->global);
+
if (error)
{
- fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_wait at %s, line %d\n", error, errno, file, line);
+ fprintf(stderr,
+ "safe_mutex: Got error: %d (%d) when doing a safe_mutex_wait on "
+ "%s at %s, line %d\n", error, errno, mp->name, file, line);
fflush(stderr);
abort();
}
- mp->thread=pthread_self();
+ /* Restore state as it was before */
+ mp->thread= save_state.thread;
+ mp->active_flags= save_state.active_flags;
+ mp->next= save_state.next;
+ mp->prev= save_state.prev;
+
if (mp->count++)
{
fprintf(stderr,
- "safe_mutex: Count was %d in thread 0x%lx when locking mutex at %s, line %d\n",
- mp->count-1, my_thread_dbug_id(), file, line);
+ "safe_mutex: Count was %d in thread 0x%lx when locking mutex %s "
+ "at %s, line %d\n",
+ mp->count-1, my_thread_dbug_id(), mp->name, file, line);
fflush(stderr);
abort();
}
@@ -263,29 +459,46 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
const char *file, uint line)
{
int error;
+ safe_mutex_t save_state;
+
pthread_mutex_lock(&mp->global);
if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
{
- fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutex\n",file,line);
+ fprintf(stderr,
+ "safe_mutex: Trying to cond_wait at %s, line %d on a not hold "
+ "mutex %s\n",
+ file, line, mp->name ? mp->name : "Null");
fflush(stderr);
abort();
}
mp->count--; /* Mutex will be released */
+ save_state= *mp;
+ remove_from_active_list(mp);
pthread_mutex_unlock(&mp->global);
error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
#ifdef EXTRA_DEBUG
if (error && (error != EINTR && error != ETIMEDOUT && error != ETIME))
{
- fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait at %s, line %d\n", error, errno, file, line);
+ fprintf(stderr,
+ "safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait "
+ "on %s at %s, line %d\n",
+ error, errno, mp->name, file, line);
}
#endif
pthread_mutex_lock(&mp->global);
- mp->thread=pthread_self();
+ /* Restore state as it was before */
+ mp->thread= save_state.thread;
+ mp->active_flags= save_state.active_flags;
+ mp->next= save_state.next;
+ mp->prev= save_state.prev;
+
if (mp->count++)
{
fprintf(stderr,
- "safe_mutex: Count was %d in thread 0x%lx when locking mutex at %s, line %d (error: %d (%d))\n",
- mp->count-1, my_thread_dbug_id(), file, line, error, error);
+ "safe_mutex: Count was %d in thread 0x%lx when locking mutex "
+ "%s at %s, line %d (error: %d (%d))\n",
+ mp->count-1, my_thread_dbug_id(), mp->name, file, line,
+ error, error);
fflush(stderr);
abort();
}
@@ -299,6 +512,8 @@ int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
{
int error=0;
+ DBUG_ENTER("safe_mutex_destroy");
+ DBUG_PRINT("enter", ("mutex: 0x%lx name: %s", (ulong) mp, mp->name));
if (!mp->file)
{
fprintf(stderr,
@@ -309,11 +524,17 @@ int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
}
if (mp->count != 0)
{
- fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %d\n",
- mp->file,mp->line, file, line);
+ fprintf(stderr,
+ "safe_mutex: Trying to destroy a mutex %s that was locked at %s, "
+ "line %d at %s, line %d\n",
+ mp->name, mp->file, mp->line, file, line);
fflush(stderr);
abort();
}
+
+ /* Free all entries that points to this one */
+ safe_mutex_free_deadlock_data(mp);
+
#ifdef __WIN__
pthread_mutex_destroy(&mp->global);
pthread_mutex_destroy(&mp->mutex);
@@ -334,7 +555,7 @@ int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
if (info->prev)
info->prev->next = info->next;
else
- safe_mutex_root = info->next;
+ safe_mutex_create_root = info->next;
if (info->next)
info->next->prev = info->prev;
safe_mutex_count--;
@@ -346,10 +567,38 @@ int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
#else
thread_safe_sub(safe_mutex_count, 1, &THR_LOCK_mutex);
#endif /* SAFE_MUTEX_DETECT_DESTROY */
- return error;
+ DBUG_RETURN(error);
}
+/**
+ Free all data related to deadlock detection
+
+ This is also useful together with safemalloc when you don't want to
+ have reports of not freed memory for mysys mutexes.
+*/
+
+void safe_mutex_free_deadlock_data(safe_mutex_t *mp)
+{
+ /* Free all entries that points to this one */
+ if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION))
+ {
+ pthread_mutex_lock(&THR_LOCK_mutex);
+ my_hash_iterate(mp->used_mutex,
+ (my_hash_walk_action) remove_from_locked_mutex,
+ mp);
+ my_hash_iterate(mp->locked_mutex,
+ (my_hash_walk_action) remove_from_used_mutex,
+ mp);
+ pthread_mutex_unlock(&THR_LOCK_mutex);
+
+ hash_free(mp->used_mutex);
+ hash_free(mp->locked_mutex);
+ my_free(mp->locked_mutex, 0);
+ mp->create_flags|= MYF_NO_DEADLOCK_DETECTION;
+ }
+}
+
/*
Free global resources and check that all mutex has been destroyed
@@ -380,16 +629,145 @@ void safe_mutex_end(FILE *file __attribute__((unused)))
}
{
struct st_safe_mutex_info_t *ptr;
- for (ptr= safe_mutex_root ; ptr ; ptr= ptr->next)
+ for (ptr= safe_mutex_create_root ; ptr ; ptr= ptr->next)
{
- fprintf(file, "\tMutex initiated at line %4u in '%s'\n",
- ptr->init_line, ptr->init_file);
+ fprintf(file, "\tMutex %s initiated at line %4u in '%s'\n",
+ ptr->name, ptr->init_line, ptr->init_file);
(void) fflush(file);
}
}
#endif /* SAFE_MUTEX_DETECT_DESTROY */
}
+
+static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
+ safe_mutex_deadlock_t *locked_mutex)
+{
+ /* Add mutex to all parent of the current mutex */
+ if (!locked_mutex->warning_only)
+ {
+ (void) my_hash_iterate(locked_mutex->mutex->locked_mutex,
+ (my_hash_walk_action) add_to_locked_mutex,
+ used_mutex);
+ /* mark that locked_mutex is locked after used_mutex */
+ (void) add_to_locked_mutex(locked_mutex, used_mutex);
+ }
+ return 0;
+}
+
+
+/**
+ register that locked_mutex was locked after current_mutex
+*/
+
+static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
+ safe_mutex_t *current_mutex)
+{
+ DBUG_ENTER("add_to_locked_mutex");
+ DBUG_PRINT("info", ("inserting 0x%lx into 0x%lx (id: %lu -> %lu)",
+ (ulong) locked_mutex, (long) current_mutex,
+ locked_mutex->id, current_mutex->id));
+ if (my_hash_insert(current_mutex->locked_mutex, (uchar*) locked_mutex))
+ {
+ /* Got mutex through two paths; ignore */
+ DBUG_RETURN(0);
+ }
+ locked_mutex->count++;
+ if (my_hash_insert(locked_mutex->mutex->used_mutex,
+ (uchar*) current_mutex))
+ {
+ DBUG_ASSERT(0);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Remove mutex from the locked mutex hash
+ @fn remove_from_used_mutex()
+ @param mp Mutex that has delete_mutex in it's locked_mutex hash
+ @param delete_mutex Mutex should be removed from the hash
+
+ @notes
+ safe_mutex_deadlock_t entries in the locked hash are shared.
+ When counter goes to 0, we delete the safe_mutex_deadlock_t entry.
+*/
+
+static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
+ safe_mutex_t *delete_mutex)
+{
+ safe_mutex_deadlock_t *found;
+ DBUG_ENTER("remove_from_locked_mutex");
+ DBUG_PRINT("enter", ("delete_mutex: 0x%lx mutex: 0x%lx (id: %lu <- %lu)",
+ (ulong) delete_mutex, (ulong) mp,
+ delete_mutex->id, mp->id));
+
+ found= (safe_mutex_deadlock_t *) hash_search(mp->locked_mutex,
+ (uchar*) &delete_mutex->id, 0);
+ DBUG_ASSERT(found);
+ if (found)
+ {
+ if (hash_delete(mp->locked_mutex, (uchar*) found))
+ {
+ DBUG_ASSERT(0);
+ }
+ if (!--found->count)
+ my_free(found, MYF(0));
+ }
+ DBUG_RETURN(0);
+}
+
+static my_bool remove_from_used_mutex(safe_mutex_deadlock_t *locked_mutex,
+ safe_mutex_t *mutex)
+{
+ DBUG_ENTER("remove_from_used_mutex");
+ DBUG_PRINT("enter", ("delete_mutex: 0x%lx mutex: 0x%lx (id: %lu <- %lu)",
+ (ulong) mutex, (ulong) locked_mutex,
+ mutex->id, locked_mutex->id));
+ if (hash_delete(locked_mutex->mutex->used_mutex, (uchar*) mutex))
+ {
+ DBUG_ASSERT(0);
+ }
+ if (!--locked_mutex->count)
+ my_free(locked_mutex, MYF(0));
+ DBUG_RETURN(0);
+}
+
+
+static void print_deadlock_warning(safe_mutex_t *new_mutex,
+ safe_mutex_t *parent_mutex)
+{
+ safe_mutex_t *mutex_root;
+ DBUG_ENTER("print_deadlock_warning");
+ DBUG_PRINT("enter", ("mutex: %s parent: %s",
+ new_mutex->name, parent_mutex->name));
+
+ fprintf(stderr, "safe_mutex: Found wrong usage of mutex "
+ "'%s' and '%s'\n",
+ parent_mutex->name, new_mutex->name);
+ DBUG_PRINT("info", ("safe_mutex: Found wrong usage of mutex "
+ "'%s' and '%s'",
+ parent_mutex->name, new_mutex->name));
+ fprintf(stderr, "Mutex currently locked (in reverse order):\n");
+ DBUG_PRINT("info", ("Mutex currently locked (in reverse order):"));
+ fprintf(stderr, "%-32.32s %s line %u\n", new_mutex->name, new_mutex->file,
+ new_mutex->line);
+ DBUG_PRINT("info", ("%-32.32s %s line %u\n", new_mutex->name,
+ new_mutex->file, new_mutex->line));
+ for (mutex_root= *my_thread_var_mutex_in_use() ;
+ mutex_root;
+ mutex_root= mutex_root->next)
+ {
+ fprintf(stderr, "%-32.32s %s line %u\n", mutex_root->name,
+ mutex_root->file, mutex_root->line);
+ DBUG_PRINT("info", ("%-32.32s %s line %u", mutex_root->name,
+ mutex_root->file, mutex_root->line));
+ }
+ fflush(stderr);
+ DBUG_VOID_RETURN;
+}
+
+
#endif /* THREAD && SAFE_MUTEX */
#if defined(THREAD) && defined(MY_PTHREAD_FASTMUTEX) && !defined(SAFE_MUTEX)
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
index 0aa4d3fc3c4..280a0ec19e7 100644
--- a/mysys/thr_rwlock.c
+++ b/mysys/thr_rwlock.c
@@ -89,7 +89,7 @@ int my_rw_rdlock(rw_lock_t *rwp)
pthread_mutex_lock(&rwp->lock);
/* active or queued writers */
- while (( rwp->state < 0 ) || rwp->waiters)
+ while ((rwp->state < 0 ) || rwp->waiters)
pthread_cond_wait( &rwp->readers, &rwp->lock);
rwp->state++;
diff --git a/mysys/waiting_threads.c b/mysys/waiting_threads.c
new file mode 100644
index 00000000000..732929f6d99
--- /dev/null
+++ b/mysys/waiting_threads.c
@@ -0,0 +1,1153 @@
+/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ @file
+
+ "waiting threads" subsystem - a unified interface for threads to wait
+ on each other, with built-in deadlock detection.
+
+ Main concepts
+ ^^^^^^^^^^^^^
+ a thread - is represented by a WT_THD structure. One physical thread
+ can have only one WT_THD descriptor at any given moment.
+
+ a resource - a thread does not wait for other threads directly,
+ instead it waits for a "resource", which is "owned" by other threads.
+ It waits, exactly, for all "owners" to "release" a resource.
+ It does not have to correspond to a physical resource. For example, it
+ may be convenient in certain cases to force resource == thread.
+ A resource is represented by a WT_RESOURCE structure.
+
+ a resource identifier - a pair of {resource type, value}. A value is
+ an ulonglong number. Represented by a WT_RESOURCE_ID structure.
+
+ a resource type - a pointer to a statically defined instance of
+ WT_RESOURCE_TYPE structure. This structure contains a pointer to
+ a function that knows how to compare values of this resource type.
+ In the simple case it could be wt_resource_id_memcmp().
+
+ a wait-for graph - a graph, that represenst "wait-for" relationships.
+ It has two types of nodes - threads and resources. There are directed
+ edges from a thread to a resource it is waiting for (WT_THD::waiting_for),
+ from a thread to resources that it "owns" (WT_THD::my_resources),
+ and from a resource to threads that "own" it (WT_RESOURCE::owners)
+
+ Graph completeness
+ ^^^^^^^^^^^^^^^^^^
+
+ For flawless deadlock detection wait-for graph must be complete.
+ It means that when a thread starts waiting it needs to know *all* its
+ blockers, and call wt_thd_will_wait_for() for every one of them.
+ Otherwise two phenomena should be expected:
+
+ 1. Fuzzy timeouts:
+
+ thread A needs to get a lock, and is blocked by a thread B.
+ it waits.
+ Just before the timeout thread B releases the lock.
+ thread A is ready to grab the lock but discovers that it is also
+ blocked by a thread C.
+ It waits and times out.
+
+ As a result thread A has waited two timeout intervals, instead of one.
+
+ 2. Unreliable cycle detection:
+
+ Thread A waits for threads B and C
+ Thread C waits for D
+ Thread D wants to start waiting for A
+
+ one can see immediately that thread D creates a cycle, and thus
+ a deadlock is detected.
+
+ But if thread A would only wait for B, and start waiting for C
+ when B would unlock, thread D would be allowed to wait, a deadlock
+ would be only detected when B unlocks or somebody times out.
+
+ These two phenomena don't affect a correctness, and strictly speaking,
+ the caller is not required to call wt_thd_will_wait_for() for *all*
+ blockers - it may optimize wt_thd_will_wait_for() calls. But they
+ may be perceived as bugs by users, it must be understood that such
+ an optimization comes with its price.
+
+ Usage
+ ^^^^^
+
+ First, the wt* subsystem must be initialized by calling
+ wt_init(). In the server you don't need to do it, it's done
+ in mysqld.cc.
+
+ Similarly, wt_end() frees wt* structures, should be called
+ at the end, but in the server mysqld.cc takes care of that.
+
+ Every WT_THD should be initialized with wt_thd_lazy_init().
+ After that they can be used in other wt_thd_* calls.
+ Before discarding, WT_THD should be free'd with
+ wt_thd_destroy(). In the server both are handled in sql_class.cc,
+ it's an error to try to do it manually.
+
+ To use the deadlock detection one needs to use this thread's WT_THD,
+ call wt_thd_will_wait_for() for every thread it needs to wait on,
+ then call wt_thd_cond_timedwait(). When thread releases a resource
+ it should call wt_thd_release() (or wt_thd_release_all()) - it will
+ notify (send a signal) threads waiting in wt_thd_cond_timedwait(),
+ if appropriate.
+
+ Just like with pthread's cond_wait, there could be spurious
+ wake-ups from wt_thd_cond_timedwait(). A caller is expected to
+ handle that (that is, to re-check the blocking criteria).
+
+ wt_thd_will_wait_for() and wt_thd_cond_timedwait() return either
+ WT_OK or WT_DEADLOCK. Additionally wt_thd_cond_timedwait() can return
+ WT_TIMEOUT. Out of memory and other fatal errors are reported as
+ WT_DEADLOCK - and a transaction must be aborted just the same.
+
+ Configuration
+ ^^^^^^^^^^^^^
+ There are four config variables. Two deadlock search depths - short and
+ long - and two timeouts. Deadlock search is performed with the short
+ depth on every wt_thd_will_wait_for() call. wt_thd_cond_timedwait()
+ waits with a short timeout, performs a deadlock search with the long
+ depth, and waits with a long timeout. As most deadlock cycles are supposed
+ to be short, most deadlocks will be detected at once, and waits will
+ rarely be necessary.
+
+ These config variables are thread-local. Different threads may have
+ different search depth and timeout values.
+
+ Also, deadlock detector supports different killing strategies, the victim
+ in a deadlock cycle is selected based on the "weight". See "weight"
+ description in waiting_threads.h for details. It's up to the caller to
+ set weights accordingly.
+
+ Status
+ ^^^^^^
+ We calculate the number of successfull waits (WT_OK returned from
+ wt_thd_cond_timedwait()), a number of timeouts, a deadlock cycle
+ length distribution - number of deadlocks with every length from
+ 1 to WT_CYCLE_STATS, and a wait time distribution - number
+ of waits with a time from 1 us to 1 min in WT_WAIT_STATS
+ intervals on a log e scale.
+*/
+
+/*
+ Note that if your lock system satisfy the following condition:
+
+ there exist four lock levels A, B, C, D, such as
+ A is compatible with B
+ A is not compatible with C
+ D is not compatible with B
+
+ (example A=IX, B=IS, C=S, D=X)
+
+ you need to include lock level in the resource identifier - a
+ thread waiting for lock of the type A on resource R and another
+ thread waiting for lock of the type B on resource R should wait on
+ different WT_RESOURCE structures, on different {lock, resource}
+ pairs. Otherwise the following is possible:
+
+ thread1> take S-lock on R
+ thread2> take IS-lock on R
+ thread3> wants X-lock on R, starts waiting for threads 1 and 2 on R.
+ thread3 is killed (or timeout or whatever)
+ WT_RESOURCE structure for R is still in the hash, as it has two owners
+ thread4> wants an IX-lock on R
+ WT_RESOURCE for R is found in the hash, thread4 starts waiting on it.
+ !! now thread4 is waiting for both thread1 and thread2
+ !! while, in fact, IX-lock and IS-lock are compatible and
+ !! thread4 should not wait for thread2.
+*/
+
+#include <waiting_threads.h>
+#include <m_string.h>
+
+/* status variables */
+
+/**
+ preset table of wait intervals
+*/
+ulonglong wt_wait_table[WT_WAIT_STATS];
+/**
+ wait time distribution (log e scale)
+*/
+uint32 wt_wait_stats[WT_WAIT_STATS+1];
+/**
+ distribution of cycle lengths
+ first column tells whether this was during short or long detection
+*/
+uint32 wt_cycle_stats[2][WT_CYCLE_STATS+1];
+uint32 wt_success_stats;
+
+static my_atomic_rwlock_t cycle_stats_lock, wait_stats_lock, success_stats_lock;
+
+#ifdef SAFE_STATISTICS
+#define incr(VAR, LOCK) \
+ do { \
+ my_atomic_rwlock_wrlock(&(LOCK)); \
+ my_atomic_add32(&(VAR), 1); \
+ my_atomic_rwlock_wrunlock(&(LOCK)); \
+ } while(0)
+#else
+#define incr(VAR,LOCK) do { (VAR)++; } while(0)
+#endif
+
+static void increment_success_stats()
+{
+ incr(wt_success_stats, success_stats_lock);
+}
+
+static void increment_cycle_stats(uint depth, uint slot)
+{
+ if (depth >= WT_CYCLE_STATS)
+ depth= WT_CYCLE_STATS;
+ incr(wt_cycle_stats[slot][depth], cycle_stats_lock);
+}
+
+static void increment_wait_stats(ulonglong waited,int ret)
+{
+ uint i;
+ if ((ret) == ETIMEDOUT)
+ i= WT_WAIT_STATS;
+ else
+ for (i= 0; i < WT_WAIT_STATS && waited/10 > wt_wait_table[i]; i++) ;
+ incr(wt_wait_stats[i], wait_stats_lock);
+}
+
+/*
+ 'lock' protects 'owners', 'state', and 'waiter_count'
+ 'id' is read-only
+
+ a resource is picked up from a hash in a lock-free manner
+ it's returned pinned, so it cannot be freed at once
+ but it may be freed right after the pin is removed
+ to free a resource it should
+ 1. have no owners
+ 2. have no waiters
+
+ two ways to access a resource:
+ 1. find it in a hash
+ - it's returned pinned.
+ a) take a lock in exclusive mode
+ b) check the state, it should be ACTIVE to be usable
+ c) unpin
+ 2. by a direct reference
+ - could only used if a resource cannot be freed
+ e.g. accessing a resource by thd->waiting_for is safe,
+ a resource cannot be freed as there's a thread waiting for it
+*/
+struct st_wt_resource {
+ WT_RESOURCE_ID id;
+ uint waiter_count;
+ enum { ACTIVE, FREE } state;
+#ifndef DBUG_OFF
+ pthread_mutex_t *cond_mutex; /* a mutex for the 'cond' below */
+#endif
+ /*
+ before the 'lock' all elements are mutable, after (and including) -
+ immutable in the sense that lf_hash_insert() won't memcpy() over them.
+ See wt_init().
+ */
+#ifdef WT_RWLOCKS_USE_MUTEXES
+ /*
+ we need a special rwlock-like 'lock' to allow readers bypass
+ waiting writers, otherwise readers can deadlock. For example:
+
+ A waits on resource x, owned by B, B waits on resource y, owned
+ by A, we have a cycle (A->x->B->y->A)
+ Both A and B start deadlock detection:
+
+ A locks x B locks y
+ A goes deeper B goes deeper
+ A locks y B locks x
+
+ with mutexes it would deadlock. With rwlocks it won't, as long
+ as both A and B are taking read locks (and they do).
+ But other threads may take write locks. Assume there's
+ C who wants to start waiting on x, and D who wants to start
+ waiting on y.
+
+ A read-locks x B read-locks y
+ A goes deeper B goes deeper
+ => C write-locks x (to add a new edge) D write-locks y
+ .. C is blocked D is blocked
+ A read-locks y B read-locks x
+
+ Now, if a read lock can bypass a pending wrote lock request, we're fine.
+ If it can not, we have a deadlock.
+
+ writer starvation is technically possible, but unlikely, because
+ the contention is expected to be low.
+ */
+ struct {
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+ uint readers: 16;
+ uint pending_writers: 15;
+ uint write_locked: 1;
+ } lock;
+#else
+ rw_lock_t lock;
+#endif
+ pthread_cond_t cond; /* the corresponding mutex is provided by the caller */
+ DYNAMIC_ARRAY owners;
+};
+
+#ifdef WT_RWLOCKS_USE_MUTEXES
+static void rc_rwlock_init(WT_RESOURCE *rc)
+{
+ pthread_cond_init(&rc->lock.cond, 0);
+ pthread_mutex_init(&rc->lock.mutex, MY_MUTEX_INIT_FAST);
+}
+static void rc_rwlock_destroy(WT_RESOURCE *rc)
+{
+ DBUG_ASSERT(rc->lock.write_locked == 0);
+ DBUG_ASSERT(rc->lock.readers == 0);
+ pthread_cond_destroy(&rc->lock.cond);
+ pthread_mutex_destroy(&rc->lock.mutex);
+}
+static void rc_rdlock(WT_RESOURCE *rc)
+{
+ DBUG_PRINT("wt", ("TRYLOCK resid=%ld for READ", (ulong)rc->id.value));
+ pthread_mutex_lock(&rc->lock.mutex);
+ while (rc->lock.write_locked)
+ pthread_cond_wait(&rc->lock.cond, &rc->lock.mutex);
+ rc->lock.readers++;
+ pthread_mutex_unlock(&rc->lock.mutex);
+ DBUG_PRINT("wt", ("LOCK resid=%ld for READ", (ulong)rc->id.value));
+}
+static void rc_wrlock(WT_RESOURCE *rc)
+{
+ DBUG_PRINT("wt", ("TRYLOCK resid=%ld for WRITE", (ulong)rc->id.value));
+ pthread_mutex_lock(&rc->lock.mutex);
+ while (rc->lock.write_locked || rc->lock.readers)
+ pthread_cond_wait(&rc->lock.cond, &rc->lock.mutex);
+ rc->lock.write_locked= 1;
+ pthread_mutex_unlock(&rc->lock.mutex);
+ DBUG_PRINT("wt", ("LOCK resid=%ld for WRITE", (ulong)rc->id.value));
+}
+static void rc_unlock(WT_RESOURCE *rc)
+{
+ DBUG_PRINT("wt", ("UNLOCK resid=%ld", (ulong)rc->id.value));
+ pthread_mutex_lock(&rc->lock.mutex);
+ if (rc->lock.write_locked)
+ {
+ rc->lock.write_locked= 0;
+ pthread_cond_broadcast(&rc->lock.cond);
+ }
+ else if (--rc->lock.readers == 0)
+ pthread_cond_broadcast(&rc->lock.cond);
+ pthread_mutex_unlock(&rc->lock.mutex);
+}
+#else
+static void rc_rwlock_init(WT_RESOURCE *rc)
+{
+ my_rwlock_init(&rc->lock, 0);
+}
+static void rc_rwlock_destroy(WT_RESOURCE *rc)
+{
+ rwlock_destroy(&rc->lock);
+}
+static void rc_rdlock(WT_RESOURCE *rc)
+{
+ DBUG_PRINT("wt", ("TRYLOCK resid=%ld for READ", (ulong)rc->id.value));
+ rw_rdlock(&rc->lock);
+ DBUG_PRINT("wt", ("LOCK resid=%ld for READ", (ulong)rc->id.value));
+}
+static void rc_wrlock(WT_RESOURCE *rc)
+{
+ DBUG_PRINT("wt", ("TRYLOCK resid=%ld for WRITE", (ulong)rc->id.value));
+ rw_wrlock(&rc->lock);
+ DBUG_PRINT("wt", ("LOCK resid=%ld for WRITE", (ulong)rc->id.value));
+}
+static void rc_unlock(WT_RESOURCE *rc)
+{
+ DBUG_PRINT("wt", ("UNLOCK resid=%ld", (ulong)rc->id.value));
+ rw_unlock(&rc->lock);
+}
+#endif
+
+/*
+ All resources are stored in a lock-free hash. Different threads
+ may add new resources and perform deadlock detection concurrently.
+*/
+static LF_HASH reshash;
+
+/**
+ WT_RESOURCE constructor
+
+ It's called from lf_hash and takes a pointer to an LF_SLIST instance.
+ WT_RESOURCE is located at arg+sizeof(LF_SLIST)
+*/
+static void wt_resource_init(uchar *arg)
+{
+ WT_RESOURCE *rc= (WT_RESOURCE*)(arg+LF_HASH_OVERHEAD);
+ DBUG_ENTER("wt_resource_init");
+
+ bzero(rc, sizeof(*rc));
+ rc_rwlock_init(rc);
+ pthread_cond_init(&rc->cond, 0);
+ my_init_dynamic_array(&rc->owners, sizeof(WT_THD *), 0, 5);
+ DBUG_VOID_RETURN;
+}
+
+/**
+ WT_RESOURCE destructor
+
+ It's called from lf_hash and takes a pointer to an LF_SLIST instance.
+ WT_RESOURCE is located at arg+sizeof(LF_SLIST)
+*/
+static void wt_resource_destroy(uchar *arg)
+{
+ WT_RESOURCE *rc= (WT_RESOURCE*)(arg+LF_HASH_OVERHEAD);
+ DBUG_ENTER("wt_resource_destroy");
+
+ DBUG_ASSERT(rc->owners.elements == 0);
+ rc_rwlock_destroy(rc);
+ pthread_cond_destroy(&rc->cond);
+ delete_dynamic(&rc->owners);
+ DBUG_VOID_RETURN;
+}
+
+void wt_init()
+{
+ DBUG_ENTER("wt_init");
+ DBUG_ASSERT(reshash.alloc.constructor != wt_resource_init);
+
+ lf_hash_init(&reshash, sizeof(WT_RESOURCE), LF_HASH_UNIQUE, 0,
+ sizeof_WT_RESOURCE_ID, 0, 0);
+ reshash.alloc.constructor= wt_resource_init;
+ reshash.alloc.destructor= wt_resource_destroy;
+ /*
+ Note a trick: we initialize the hash with the real element size,
+ but fix it later to a shortened element size. This way
+ the allocator will allocate elements correctly, but
+ lf_hash_insert() will only overwrite part of the element with memcpy().
+ lock, condition, and dynamic array will be intact.
+ */
+ reshash.element_size= offsetof(WT_RESOURCE, lock);
+ bzero(wt_wait_stats, sizeof(wt_wait_stats));
+ bzero(wt_cycle_stats, sizeof(wt_cycle_stats));
+ wt_success_stats= 0;
+ { /* initialize wt_wait_table[]. from 1 us to 1 min, log e scale */
+ int i;
+ double from= log(1); /* 1 us */
+ double to= log(60e6); /* 1 min */
+ for (i= 0; i < WT_WAIT_STATS; i++)
+ {
+ wt_wait_table[i]= (ulonglong)exp((to-from)/(WT_WAIT_STATS-1)*i+from);
+ DBUG_ASSERT(i == 0 || wt_wait_table[i-1] != wt_wait_table[i]);
+ }
+ }
+ my_atomic_rwlock_init(&cycle_stats_lock);
+ my_atomic_rwlock_init(&success_stats_lock);
+ my_atomic_rwlock_init(&wait_stats_lock);
+ DBUG_VOID_RETURN;
+}
+
+void wt_end()
+{
+ DBUG_ENTER("wt_end");
+
+ DBUG_ASSERT(reshash.count == 0);
+ lf_hash_destroy(&reshash);
+ my_atomic_rwlock_destroy(&cycle_stats_lock);
+ my_atomic_rwlock_destroy(&success_stats_lock);
+ my_atomic_rwlock_destroy(&wait_stats_lock);
+ DBUG_VOID_RETURN;
+}
+
+/**
+ Lazy WT_THD initialization
+
+ Cheap initialization of WT_THD. Only initialize fields that don't require
+ memory allocations - basically, it only does assignments. The rest of the
+ WT_THD structure will be initialized on demand, on the first use.
+ This allows one to initialize lazily all WT_THD structures, even if some
+ (or even most) of them will never be used for deadlock detection.
+
+ @param ds a pointer to deadlock search depth short value
+ @param ts a pointer to deadlock timeout short value
+ @param dl a pointer to deadlock search depth long value
+ @param tl a pointer to deadlock timeout long value
+
+ @note these are pointers to values, and WT_THD stores them as pointers.
+ It allows one later to change search depths and timeouts for existing
+ threads. It also means that the pointers must stay valid for the lifetime
+ of WT_THD.
+*/
+void wt_thd_lazy_init(WT_THD *thd, const ulong *ds, const ulong *ts,
+ const ulong *dl, const ulong *tl)
+{
+ DBUG_ENTER("wt_thd_lazy_init");
+ thd->waiting_for= 0;
+ thd->weight= 0;
+ thd->deadlock_search_depth_short= ds;
+ thd->timeout_short= ts;
+ thd->deadlock_search_depth_long= dl;
+ thd->timeout_long= tl;
+ /* dynamic array is also initialized lazily - without memory allocations */
+ my_init_dynamic_array(&thd->my_resources, sizeof(WT_RESOURCE *), 0, 5);
+#ifndef DBUG_OFF
+ thd->name= my_thread_name();
+#endif
+ DBUG_VOID_RETURN;
+}
+
+/**
+ Finalize WT_THD initialization
+
+ After lazy WT_THD initialization, parts of the structure are still
+ uninitialized. This function completes the initialization, allocating
+ memory, if necessary. It's called automatically on demand, when WT_THD
+ is about to be used.
+*/
+static int fix_thd_pins(WT_THD *thd)
+{
+ if (unlikely(thd->pins == 0))
+ {
+ thd->pins= lf_hash_get_pins(&reshash);
+#ifndef DBUG_OFF
+ thd->name= my_thread_name();
+#endif
+ }
+ return thd->pins == 0;
+}
+
+void wt_thd_destroy(WT_THD *thd)
+{
+ DBUG_ENTER("wt_thd_destroy");
+
+ DBUG_ASSERT(thd->my_resources.elements == 0);
+ DBUG_ASSERT(thd->waiting_for == 0);
+
+ if (thd->pins != 0)
+ lf_hash_put_pins(thd->pins);
+
+ delete_dynamic(&thd->my_resources);
+ DBUG_VOID_RETURN;
+}
+/**
+ Trivial resource id comparison function - bytewise memcmp.
+
+ It can be used in WT_RESOURCE_TYPE structures where bytewise
+ comparison of values is sufficient.
+*/
+my_bool wt_resource_id_memcmp(const void *a, const void *b)
+{
+ /* we use the fact that there's no padding in the middle of WT_RESOURCE_ID */
+ compile_time_assert(offsetof(WT_RESOURCE_ID, type) == sizeof(ulonglong));
+ return memcmp(a, b, sizeof_WT_RESOURCE_ID);
+}
+
+/**
+ arguments for the recursive deadlock_search function
+*/
+struct deadlock_arg {
+ WT_THD * const thd; /**< starting point of a search */
+ uint const max_depth; /**< search depth limit */
+ WT_THD *victim; /**< a thread to be killed to resolve a deadlock */
+ WT_RESOURCE *last_locked_rc; /**< see comment at the end of deadlock_search() */
+};
+
+/**
+ helper function to change the victim, according to the weight
+*/
+static void change_victim(WT_THD* found, struct deadlock_arg *arg)
+{
+ if (found->weight < arg->victim->weight)
+ {
+ if (arg->victim != arg->thd)
+ {
+ rc_unlock(arg->victim->waiting_for); /* release the previous victim */
+ DBUG_ASSERT(arg->last_locked_rc == found->waiting_for);
+ }
+ arg->victim= found;
+ arg->last_locked_rc= 0;
+ }
+}
+
+/**
+ recursive loop detection in a wait-for graph with a limited search depth
+*/
+static int deadlock_search(struct deadlock_arg *arg, WT_THD *blocker,
+ uint depth)
+{
+ WT_RESOURCE *rc, *volatile *shared_ptr= &blocker->waiting_for;
+ WT_THD *cursor;
+ uint i;
+ int ret= WT_OK;
+ DBUG_ENTER("deadlock_search");
+ DBUG_PRINT("wt", ("enter: thd=%s, blocker=%s, depth=%u",
+ arg->thd->name, blocker->name, depth));
+
+ LF_REQUIRE_PINS(1);
+
+ arg->last_locked_rc= 0;
+
+ if (depth > arg->max_depth)
+ {
+ DBUG_PRINT("wt", ("exit: WT_DEPTH_EXCEEDED (early)"));
+ DBUG_RETURN(WT_DEPTH_EXCEEDED);
+ }
+
+retry:
+ /*
+ safe dereference as explained in lf_alloc-pin.c
+ (in short: protects against lf_alloc_free() in lf_hash_delete())
+ */
+ do
+ {
+ rc= *shared_ptr;
+ lf_pin(arg->thd->pins, 0, rc);
+ } while (rc != *shared_ptr && LF_BACKOFF);
+
+ if (rc == 0)
+ {
+ DBUG_PRINT("wt", ("exit: OK (early)"));
+ DBUG_RETURN(0);
+ }
+
+ rc_rdlock(rc);
+ if (rc->state != ACTIVE || *shared_ptr != rc)
+ {
+ /* blocker is not waiting on this resource anymore */
+ rc_unlock(rc);
+ lf_unpin(arg->thd->pins, 0);
+ goto retry;
+ }
+ /* as the state is locked, we can unpin now */
+ lf_unpin(arg->thd->pins, 0);
+
+ /*
+ Below is not a pure depth-first search. It's a depth-first with a
+ slightest hint of breadth-first. Depth-first is:
+
+ check(element, X):
+ foreach current in element->nodes[] do:
+ if current == X return error;
+ check(current, X);
+
+ while we do
+
+ check(element, X):
+ foreach current in element->nodes[] do:
+ if current == X return error;
+ foreach current in element->nodes[] do:
+ check(current, X);
+
+ preferring shorter deadlocks over longer ones.
+ */
+ for (i= 0; i < rc->owners.elements; i++)
+ {
+ cursor= *dynamic_element(&rc->owners, i, WT_THD**);
+ /*
+ We're only looking for (and detecting) cycles that include 'arg->thd'.
+ That is, only deadlocks that *we* have created. For example,
+ thd->A->B->thd
+ (thd waits for A, A waits for B, while B is waiting for thd).
+ While walking the graph we can encounter other cicles, e.g.
+ thd->A->B->C->A
+ This will not be detected. Instead we will walk it in circles until
+ the search depth limit is reached (the latter guarantees that an
+ infinite loop is impossible). We expect the thread that has created
+ the cycle (one of A, B, and C) to detect its deadlock.
+ */
+ if (cursor == arg->thd)
+ {
+ ret= WT_DEADLOCK;
+ increment_cycle_stats(depth, arg->max_depth ==
+ *arg->thd->deadlock_search_depth_long);
+ arg->victim= cursor;
+ goto end;
+ }
+ }
+ for (i= 0; i < rc->owners.elements; i++)
+ {
+ cursor= *dynamic_element(&rc->owners, i, WT_THD**);
+ switch (deadlock_search(arg, cursor, depth+1)) {
+ case WT_OK:
+ break;
+ case WT_DEPTH_EXCEEDED:
+ ret= WT_DEPTH_EXCEEDED;
+ break;
+ case WT_DEADLOCK:
+ ret= WT_DEADLOCK;
+ change_victim(cursor, arg); /* also sets arg->last_locked_rc to 0 */
+ i= rc->owners.elements; /* jump out of the loop */
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ if (arg->last_locked_rc)
+ rc_unlock(arg->last_locked_rc);
+ }
+end:
+ /*
+ Note that 'rc' is locked in this function, but it's never unlocked here.
+ Instead it's saved in arg->last_locked_rc and the *caller* is
+ expected to unlock it. It's done to support different killing
+ strategies. This is how it works:
+ Assuming a graph
+
+ thd->A->B->C->thd
+
+ deadlock_search() function starts from thd, locks it (in fact it locks not
+ a thd, but a resource it is waiting on, but below, for simplicity, I'll
+ talk about "locking a thd"). Then it goes down recursively, locks A, and so
+ on. Goes down recursively, locks B. Goes down recursively, locks C.
+ Notices that C is waiting on thd. Deadlock detected. Sets arg->victim=thd.
+ Returns from the last deadlock_search() call. C stays locked!
+ Now it checks whether C is a more appropriate victim than 'thd'.
+ If yes - arg->victim=C, otherwise C is unlocked. Returns. B stays locked.
+ Now it checks whether B is a more appropriate victim than arg->victim.
+ If yes - old arg->victim is unlocked and arg->victim=B,
+ otherwise B is unlocked. Return.
+ And so on.
+
+ In short, a resource is locked in a frame. But it's not unlocked in the
+ same frame, it's unlocked by the caller, and only after the caller checks
+ that it doesn't need to use current WT_THD as a victim. If it does - the
+ lock is kept and the old victim's resource is unlocked. When the recursion
+ is unrolled and we are back to deadlock() function, there are only two
+ locks left - on thd and on the victim.
+ */
+ arg->last_locked_rc= rc;
+ DBUG_PRINT("wt", ("exit: %s",
+ ret == WT_DEPTH_EXCEEDED ? "WT_DEPTH_EXCEEDED" :
+ ret ? "WT_DEADLOCK" : "OK"));
+ DBUG_RETURN(ret);
+}
+
+/**
+ Deadlock detection in a wait-for graph
+
+ A wrapper for recursive deadlock_search() - prepares deadlock_arg structure,
+ invokes deadlock_search(), increments statistics, notifies the victim.
+
+ @param thd thread that is going to wait. Deadlock is detected
+ if, while walking the graph, we reach a thread that
+ is waiting on thd
+ @param blocker starting point of a search. In wt_thd_cond_timedwait()
+ it's thd, in wt_thd_will_wait_for() it's a thread that
+ thd is going to wait for
+ @param depth starting search depth. In general it's the number of
+ edges in the wait-for graph between thd and the
+ blocker. Practically only two values are used (and
+ supported) - when thd == blocker it's 0, when thd
+ waits directly for blocker, it's 1
+ @param max_depth search depth limit
+*/
+static int deadlock(WT_THD *thd, WT_THD *blocker, uint depth,
+ uint max_depth)
+{
+ struct deadlock_arg arg= {thd, max_depth, 0, 0};
+ int ret;
+ DBUG_ENTER("deadlock");
+ DBUG_ASSERT(depth < 2);
+ ret= deadlock_search(&arg, blocker, depth);
+ if (ret == WT_DEPTH_EXCEEDED)
+ {
+ increment_cycle_stats(WT_CYCLE_STATS, max_depth ==
+ *thd->deadlock_search_depth_long);
+ ret= WT_OK;
+ }
+ /*
+ if we started with depth==1, blocker was never considered for a victim
+ in deadlock_search(). Do it here.
+ */
+ if (ret == WT_DEADLOCK && depth)
+ change_victim(blocker, &arg);
+ if (arg.last_locked_rc)
+ {
+ /*
+ Special return code if there's nobody to wait for.
+
+ depth == 0 means that we start the search from thd (thd == blocker).
+ ret == WT_OK means that no cycle was found and
+ arg.last_locked_rc == thd->waiting_for.
+ and arg.last_locked_rc->owners.elements == 0 means that
+ (applying the rule above) thd->waiting_for->owners.elements == 0,
+ and thd doesn't have anybody to wait for.
+ */
+ if (depth == 0 && ret == WT_OK && arg.last_locked_rc->owners.elements == 0)
+ {
+ DBUG_ASSERT(thd == blocker);
+ DBUG_ASSERT(arg.last_locked_rc == thd->waiting_for);
+ ret= WT_FREE_TO_GO;
+ }
+ rc_unlock(arg.last_locked_rc);
+ }
+ /* notify the victim, if appropriate */
+ if (ret == WT_DEADLOCK && arg.victim != thd)
+ {
+ DBUG_PRINT("wt", ("killing %s", arg.victim->name));
+ arg.victim->killed= 1;
+ pthread_cond_broadcast(&arg.victim->waiting_for->cond);
+ rc_unlock(arg.victim->waiting_for);
+ ret= WT_OK;
+ }
+ DBUG_RETURN(ret);
+}
+
+
+/**
+ Delete an element from reshash if it has no waiters or owners
+
+ rc->lock must be locked by the caller and it's unlocked on return.
+*/
+static int unlock_lock_and_free_resource(WT_THD *thd, WT_RESOURCE *rc)
+{
+ uint keylen;
+ const void *key;
+ DBUG_ENTER("unlock_lock_and_free_resource");
+
+ DBUG_ASSERT(rc->state == ACTIVE);
+
+ if (rc->owners.elements || rc->waiter_count)
+ {
+ DBUG_PRINT("wt", ("nothing to do, %u owners, %u waiters",
+ rc->owners.elements, rc->waiter_count));
+ rc_unlock(rc);
+ DBUG_RETURN(0);
+ }
+
+ if (fix_thd_pins(thd))
+ {
+ rc_unlock(rc);
+ DBUG_RETURN(1);
+ }
+
+ /* XXX if (rc->id.type->make_key) key= rc->id.type->make_key(&rc->id, &keylen); else */
+ {
+ key= &rc->id;
+ keylen= sizeof_WT_RESOURCE_ID;
+ }
+
+ /*
+ To free the element correctly we need to:
+ 1. take its lock (already done).
+ 2. set the state to FREE
+ 3. release the lock
+ 4. remove from the hash
+ */
+ rc->state= FREE;
+ rc_unlock(rc);
+ DBUG_RETURN(lf_hash_delete(&reshash, thd->pins, key, keylen) == -1);
+}
+
+
+/**
+ register the fact that thd is not waiting anymore
+
+ decrease waiter_count, clear waiting_for, free the resource if appropriate.
+ thd->waiting_for must be locked!
+*/
+static int stop_waiting_locked(WT_THD *thd)
+{
+ int ret;
+ WT_RESOURCE *rc= thd->waiting_for;
+ DBUG_ENTER("stop_waiting_locked");
+
+ DBUG_ASSERT(rc->waiter_count);
+ DBUG_ASSERT(rc->state == ACTIVE);
+ rc->waiter_count--;
+ thd->waiting_for= 0;
+ ret= unlock_lock_and_free_resource(thd, rc);
+ DBUG_RETURN((thd->killed || ret) ? WT_DEADLOCK : WT_OK);
+}
+
+/**
+ register the fact that thd is not waiting anymore
+
+ locks thd->waiting_for and calls stop_waiting_locked().
+*/
+static int stop_waiting(WT_THD *thd)
+{
+ int ret;
+ WT_RESOURCE *rc= thd->waiting_for;
+ DBUG_ENTER("stop_waiting");
+
+ if (!rc)
+ DBUG_RETURN(WT_OK);
+ /*
+ nobody's trying to free the resource now,
+ as its waiter_count is guaranteed to be non-zero
+ */
+ rc_wrlock(rc);
+ ret= stop_waiting_locked(thd);
+ DBUG_RETURN(ret);
+}
+
+/**
+ notify the system that a thread needs to wait for another thread
+
+ called by a *waiter* to declare that it (thd) will wait for another
+ thread (blocker) on a specific resource (resid).
+ can be called many times, if many blockers own a blocking resource.
+ but must always be called with the same resource id - a thread cannot
+ wait for more than one resource at a time.
+
+ @return WT_OK or WT_DEADLOCK
+
+ As a new edge is added to the wait-for graph, a deadlock detection is
+ performed for this new edge.
+*/
+int wt_thd_will_wait_for(WT_THD *thd, WT_THD *blocker,
+ const WT_RESOURCE_ID *resid)
+{
+ uint i;
+ WT_RESOURCE *rc;
+ DBUG_ENTER("wt_thd_will_wait_for");
+
+ LF_REQUIRE_PINS(3);
+
+ DBUG_PRINT("wt", ("enter: thd=%s, blocker=%s, resid=%lu",
+ thd->name, blocker->name, (ulong)resid->value));
+
+ if (fix_thd_pins(thd))
+ DBUG_RETURN(WT_DEADLOCK);
+
+ if (thd->waiting_for == 0)
+ {
+ uint keylen;
+ const void *key;
+ /* XXX if (restype->make_key) key= restype->make_key(resid, &keylen); else */
+ {
+ key= resid;
+ keylen= sizeof_WT_RESOURCE_ID;
+ }
+
+ DBUG_PRINT("wt", ("first blocker"));
+
+retry:
+ while ((rc= lf_hash_search(&reshash, thd->pins, key, keylen)) == 0)
+ {
+ WT_RESOURCE tmp;
+
+ DBUG_PRINT("wt", ("failed to find rc in hash, inserting"));
+ bzero(&tmp, sizeof(tmp));
+ tmp.id= *resid;
+ tmp.state= ACTIVE;
+
+ if (lf_hash_insert(&reshash, thd->pins, &tmp) == -1) /* if OOM */
+ DBUG_RETURN(WT_DEADLOCK);
+ /*
+ Two cases: either lf_hash_insert() failed - because another thread
+ has just inserted a resource with the same id - and we need to retry.
+ Or lf_hash_insert() succeeded, and then we need to repeat
+ lf_hash_search() to find a real address of the newly inserted element.
+ That is, we don't care what lf_hash_insert() has returned.
+ And we need to repeat the loop anyway.
+ */
+ }
+ if (rc == MY_ERRPTR)
+ DBUG_RETURN(WT_DEADLOCK);
+
+ DBUG_PRINT("wt", ("found in hash rc=%p", rc));
+
+ rc_wrlock(rc);
+ if (rc->state != ACTIVE)
+ {
+ DBUG_PRINT("wt", ("but it's not active, retrying"));
+ /* Somebody has freed the element while we weren't looking */
+ rc_unlock(rc);
+ lf_hash_search_unpin(thd->pins);
+ goto retry;
+ }
+
+ lf_hash_search_unpin(thd->pins); /* the element cannot go away anymore */
+ thd->waiting_for= rc;
+ rc->waiter_count++;
+ thd->killed= 0;
+ }
+ else
+ {
+ DBUG_ASSERT(thd->waiting_for->id.type == resid->type);
+ DBUG_ASSERT(resid->type->compare(&thd->waiting_for->id, resid) == 0);
+ DBUG_PRINT("wt", ("adding another blocker"));
+
+ /*
+ we can safely access the resource here, it's in the hash as it has
+ non-zero waiter_count
+ */
+ rc= thd->waiting_for;
+ rc_wrlock(rc);
+ DBUG_ASSERT(rc->waiter_count);
+ DBUG_ASSERT(rc->state == ACTIVE);
+
+ if (thd->killed)
+ {
+ stop_waiting_locked(thd);
+ DBUG_RETURN(WT_DEADLOCK);
+ }
+ }
+ /*
+ Another thread could be waiting on this resource for this very 'blocker'.
+ In this case we should not add it to the list for the second time.
+ */
+ for (i= 0; i < rc->owners.elements; i++)
+ if (*dynamic_element(&rc->owners, i, WT_THD**) == blocker)
+ break;
+ if (i >= rc->owners.elements)
+ {
+ if (push_dynamic(&blocker->my_resources, (void*)&rc))
+ {
+ stop_waiting_locked(thd);
+ DBUG_RETURN(WT_DEADLOCK); /* deadlock and OOM use the same error code */
+ }
+ if (push_dynamic(&rc->owners, (void*)&blocker))
+ {
+ pop_dynamic(&blocker->my_resources);
+ stop_waiting_locked(thd);
+ DBUG_RETURN(WT_DEADLOCK);
+ }
+ }
+ rc_unlock(rc);
+
+ if (deadlock(thd, blocker, 1, *thd->deadlock_search_depth_short) != WT_OK)
+ {
+ stop_waiting(thd);
+ DBUG_RETURN(WT_DEADLOCK);
+ }
+ DBUG_RETURN(WT_OK);
+}
+
+/**
+ called by a *waiter* (thd) to start waiting
+
+ It's supposed to be a drop-in replacement for
+ pthread_cond_timedwait(), and it takes mutex as an argument.
+
+ @return one of WT_TIMEOUT, WT_DEADLOCK, WT_OK
+*/
+int wt_thd_cond_timedwait(WT_THD *thd, pthread_mutex_t *mutex)
+{
+ int ret= WT_TIMEOUT;
+ struct timespec timeout;
+ ulonglong before, after, starttime;
+ WT_RESOURCE *rc= thd->waiting_for;
+ DBUG_ENTER("wt_thd_cond_timedwait");
+ DBUG_PRINT("wt", ("enter: thd=%s, rc=%p", thd->name, rc));
+
+#ifndef DBUG_OFF
+ if (rc->cond_mutex)
+ DBUG_ASSERT(rc->cond_mutex == mutex);
+ else
+ rc->cond_mutex= mutex;
+ safe_mutex_assert_owner(mutex);
+#endif
+
+ before= starttime= my_getsystime();
+
+#ifdef __WIN__
+ /*
+ only for the sake of Windows we distinguish between
+ 'before' and 'starttime':
+
+ my_getsystime() returns high-resolution value, that cannot be used for
+ waiting (it doesn't follow system clock changes), but is good for time
+ intervals.
+
+ GetSystemTimeAsFileTime() follows system clock, but is low-resolution
+ and will result in lousy intervals.
+ */
+ GetSystemTimeAsFileTime((PFILETIME)&starttime);
+#endif
+
+ rc_wrlock(rc);
+ if (rc->owners.elements == 0)
+ ret= WT_OK;
+ rc_unlock(rc);
+
+ set_timespec_time_nsec(timeout, starttime, (*thd->timeout_short)*ULL(1000));
+ if (ret == WT_TIMEOUT && !thd->killed)
+ ret= pthread_cond_timedwait(&rc->cond, mutex, &timeout);
+ if (ret == WT_TIMEOUT && !thd->killed)
+ {
+ int r= deadlock(thd, thd, 0, *thd->deadlock_search_depth_long);
+ if (r == WT_FREE_TO_GO)
+ ret= WT_OK;
+ else if (r != WT_OK)
+ ret= WT_DEADLOCK;
+ else if (*thd->timeout_long > *thd->timeout_short)
+ {
+ set_timespec_time_nsec(timeout, starttime, (*thd->timeout_long)*ULL(1000));
+ if (!thd->killed)
+ ret= pthread_cond_timedwait(&rc->cond, mutex, &timeout);
+ }
+ }
+ after= my_getsystime();
+ if (stop_waiting(thd) == WT_DEADLOCK) /* if we're killed */
+ ret= WT_DEADLOCK;
+ increment_wait_stats(after-before, ret);
+ if (ret == WT_OK)
+ increment_success_stats();
+ DBUG_RETURN(ret);
+}
+
+/**
+ called by a *blocker* when it releases a resource
+
+ it's conceptually similar to pthread_cond_broadcast, and must be done
+ under the same mutex as wt_thd_cond_timedwait().
+
+ @param resid a resource to release. 0 to release all resources
+*/
+
+void wt_thd_release(WT_THD *thd, const WT_RESOURCE_ID *resid)
+{
+ uint i;
+ DBUG_ENTER("wt_thd_release");
+
+ for (i= 0; i < thd->my_resources.elements; i++)
+ {
+ WT_RESOURCE *rc= *dynamic_element(&thd->my_resources, i, WT_RESOURCE**);
+ if (!resid || (resid->type->compare(&rc->id, resid) == 0))
+ {
+ uint j;
+
+ rc_wrlock(rc);
+ /*
+ nobody's trying to free the resource now,
+ as its owners[] array is not empty (at least thd must be there)
+ */
+ DBUG_ASSERT(rc->state == ACTIVE);
+ for (j= 0; j < rc->owners.elements; j++)
+ if (*dynamic_element(&rc->owners, j, WT_THD**) == thd)
+ break;
+ DBUG_ASSERT(j < rc->owners.elements);
+ delete_dynamic_element(&rc->owners, j);
+ if (rc->owners.elements == 0)
+ {
+ pthread_cond_broadcast(&rc->cond);
+#ifndef DBUG_OFF
+ if (rc->cond_mutex)
+ safe_mutex_assert_owner(rc->cond_mutex);
+#endif
+ }
+ unlock_lock_and_free_resource(thd, rc);
+ if (resid)
+ {
+ delete_dynamic_element(&thd->my_resources, i);
+ DBUG_VOID_RETURN;
+ }
+ }
+ }
+ if (!resid)
+ reset_dynamic(&thd->my_resources);
+ DBUG_VOID_RETURN;
+}
+
diff --git a/mysys/wqueue.c b/mysys/wqueue.c
new file mode 100644
index 00000000000..fcc0a39725d
--- /dev/null
+++ b/mysys/wqueue.c
@@ -0,0 +1,225 @@
+
+#include <wqueue.h>
+
+#define STRUCT_PTR(TYPE, MEMBER, a) \
+ (TYPE *) ((char *) (a) - offsetof(TYPE, MEMBER))
+/*
+ Link a thread into double-linked queue of waiting threads.
+
+ SYNOPSIS
+ wqueue_link_into_queue()
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be added to the queue
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ Queue is represented by a circular list of the thread structures
+ The list is double-linked of the type (**prev,*next), accessed by
+ a pointer to the last element.
+*/
+
+void wqueue_link_into_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
+{
+ struct st_my_thread_var *last;
+ if (!(last= wqueue->last_thread))
+ {
+ /* Queue is empty */
+ thread->next= thread;
+ thread->prev= &thread->next;
+ }
+ else
+ {
+ thread->prev= last->next->prev;
+ last->next->prev= &thread->next;
+ thread->next= last->next;
+ last->next= thread;
+ }
+ wqueue->last_thread= thread;
+}
+
+
+/*
+ Add a thread to single-linked queue of waiting threads
+
+ SYNOPSIS
+ wqueue_add_to_queue()
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be added to the queue
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ Queue is represented by a circular list of the thread structures
+ The list is single-linked of the type (*next), accessed by a pointer
+ to the last element.
+*/
+
+void wqueue_add_to_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
+{
+ struct st_my_thread_var *last;
+ if (!(last= wqueue->last_thread))
+ thread->next= thread;
+ else
+ {
+ thread->next= last->next;
+ last->next= thread;
+ }
+#ifndef DBUG_OFF
+ thread->prev= NULL; /* force segfault if used */
+#endif
+ wqueue->last_thread= thread;
+}
+
+/*
+ Unlink a thread from double-linked queue of waiting threads
+
+ SYNOPSIS
+ wqueue_unlink_from_queue()
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be removed from the queue
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ See NOTES for link_into_queue
+*/
+
+void wqueue_unlink_from_queue(WQUEUE *wqueue, struct st_my_thread_var *thread)
+{
+ if (thread->next == thread)
+ /* The queue contains only one member */
+ wqueue->last_thread= NULL;
+ else
+ {
+ thread->next->prev= thread->prev;
+ *thread->prev= thread->next;
+ if (wqueue->last_thread == thread)
+ wqueue->last_thread= STRUCT_PTR(struct st_my_thread_var, next,
+ thread->prev);
+ }
+ thread->next= NULL;
+}
+
+
+/*
+ Remove all threads from queue signaling them to proceed
+
+ SYNOPSIS
+ wqueue_realease_queue()
+ wqueue pointer to the queue structure
+ thread pointer to the thread to be added to the queue
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ See notes for add_to_queue
+ When removed from the queue each thread is signaled via condition
+ variable thread->suspend.
+*/
+
+void wqueue_release_queue(WQUEUE *wqueue)
+{
+ struct st_my_thread_var *last= wqueue->last_thread;
+ struct st_my_thread_var *next= last->next;
+ struct st_my_thread_var *thread;
+ do
+ {
+ thread= next;
+ pthread_cond_signal(&thread->suspend);
+ next= thread->next;
+ thread->next= NULL;
+ }
+ while (thread != last);
+ wqueue->last_thread= NULL;
+}
+
+
+/**
+ @brief Removes all threads waiting for read or first one waiting for write.
+
+ @param wqueue pointer to the queue structure
+ @param thread pointer to the thread to be added to the queue
+
+ @note This function is applicable only to single linked lists.
+*/
+
+void wqueue_release_one_locktype_from_queue(WQUEUE *wqueue)
+{
+ struct st_my_thread_var *last= wqueue->last_thread;
+ struct st_my_thread_var *next= last->next;
+ struct st_my_thread_var *thread;
+ struct st_my_thread_var *new_list= NULL;
+ uint first_type= next->lock_type;
+ if (first_type == MY_PTHREAD_LOCK_WRITE)
+ {
+ /* release first waiting for write lock */
+ pthread_cond_signal(&next->suspend);
+ if (next == last)
+ wqueue->last_thread= NULL;
+ else
+ last->next= next->next;
+ next->next= NULL;
+ return;
+ }
+ do
+ {
+ thread= next;
+ next= thread->next;
+ if (thread->lock_type == MY_PTHREAD_LOCK_WRITE)
+ {
+ /* skip waiting for write lock */
+ if (new_list)
+ {
+ thread->next= new_list->next;
+ new_list= new_list->next= thread;
+ }
+ else
+ new_list= thread->next= thread;
+ }
+ else
+ {
+ /* release waiting for read lock */
+ pthread_cond_signal(&thread->suspend);
+ thread->next= NULL;
+ }
+ } while (thread != last);
+ wqueue->last_thread= new_list;
+}
+
+
+/*
+ Add thread and wait
+
+ SYNOPSYS
+ wqueue_add_and_wait()
+ wqueue queue to add to
+ thread thread which is waiting
+ lock mutex need for the operation
+*/
+
+void wqueue_add_and_wait(WQUEUE *wqueue,
+ struct st_my_thread_var *thread,
+ pthread_mutex_t *lock)
+{
+ DBUG_ENTER("wqueue_add_and_wait");
+ DBUG_PRINT("enter",
+ ("thread: 0x%lx cond: 0x%lx mutex: 0x%lx",
+ (ulong) thread, (ulong) &thread->suspend, (ulong) lock));
+ wqueue_add_to_queue(wqueue, thread);
+ do
+ {
+ DBUG_PRINT("info", ("wait... cond: 0x%lx mutex: 0x%lx",
+ (ulong) &thread->suspend, (ulong) lock));
+ pthread_cond_wait(&thread->suspend, lock);
+ DBUG_PRINT("info", ("wait done cond: 0x%lx mutex: 0x%lx next: 0x%lx",
+ (ulong) &thread->suspend, (ulong) lock,
+ (ulong) thread->next));
+ }
+ while (thread->next);
+ DBUG_VOID_RETURN;
+}
diff --git a/plugin/daemon_example/daemon_example.cc b/plugin/daemon_example/daemon_example.cc
index af585bb4302..e683bf7ab7a 100644
--- a/plugin/daemon_example/daemon_example.cc
+++ b/plugin/daemon_example/daemon_example.cc
@@ -81,7 +81,7 @@ pthread_handler_t mysql_heartbeat(void *p)
1 failure (cannot happen)
*/
-static int daemon_example_plugin_init(void *p)
+static int daemon_example_plugin_init(void *p __attribute__ ((unused)))
{
DBUG_ENTER("daemon_example_plugin_init");
@@ -147,7 +147,7 @@ static int daemon_example_plugin_init(void *p)
*/
-static int daemon_example_plugin_deinit(void *p)
+static int daemon_example_plugin_deinit(void *p __attribute__ ((unused)))
{
DBUG_ENTER("daemon_example_plugin_deinit");
char buffer[HEART_STRING_BUFFER];
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 0292617c7a5..b74e7b8df8b 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -90,7 +90,8 @@ CLEANFILES = @server_scripts@ \
mysql_find_rows \
mysqlhotcopy \
mysqldumpslow \
- mysqld_multi
+ mysqld_multi \
+ $(EXTRA_PROGRAMS)
pkgplugindir = $(pkglibdir)/plugin
diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh
index 3b179957932..aaf0553151f 100644
--- a/scripts/mysql_fix_privilege_tables.sh
+++ b/scripts/mysql_fix_privilege_tables.sh
@@ -94,7 +94,7 @@ parse_arguments() {
# [mysql_install_db], and then merge with the command line arguments
print_defaults=my_print_defaults
-for dir in ./bin @bindir@ @bindir@ extra $print_defaults_bindir/../bin $print_defaults_bindir/../extra
+for dir in ./extra ./bin @bindir@ @bindir@ $print_defaults_bindir/../bin $print_defaults_bindir/../extra
do
if test -x $dir/my_print_defaults
then
@@ -117,7 +117,7 @@ dirname=`dirname "$0"`
if test -z "$bindir"
then
- for i in @bindir@ $basedir/bin "$dirname/../client"
+ for i in "$dirname/../client" $basedir/bin @bindir@
do
if test -f $i/mysql
then
@@ -149,8 +149,8 @@ then
fi
# Find where first mysql_fix_privilege_tables.sql is located
-for i in $basedir/support-files $basedir/share $basedir/share/mysql \
- $basedir/scripts $pkgdatadir . "$dirname"
+for i in "$dirname" $basedir/support-files $basedir/share \
+ $basedir/share/mysql $basedir/scripts $pkgdatadir .
do
if test -f $i/$file
then
diff --git a/server-tools/instance-manager/CMakeLists.txt b/server-tools/instance-manager/CMakeLists.txt
index 2b9bce56ff7..4b9c386afe1 100755
--- a/server-tools/instance-manager/CMakeLists.txt
+++ b/server-tools/instance-manager/CMakeLists.txt
@@ -25,7 +25,7 @@ ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instanc
instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc
mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc
thread_registry.cc user_map.cc IMService.cpp WindowsService.cpp
- user_management_commands.cc
+ user_management_commands.cc ../../mysys/my_rnd.c
../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c
../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c
../../libmysql/errmsg.c)
diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc
index 4d8a33e7db1..4c32d10ab09 100644
--- a/server-tools/instance-manager/listener.cc
+++ b/server-tools/instance-manager/listener.cc
@@ -17,12 +17,12 @@
#pragma implementation
#endif
-#include "listener.h"
-
#include <my_global.h>
#include <mysql.h>
-#include <violite.h>
+#include <my_sys.h>
+#include "listener.h"
+#include <violite.h>
#include <sys/stat.h>
#ifndef __WIN__
#include <sys/un.h>
diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc
index bf08f963aa3..de611878bb4 100644
--- a/server-tools/instance-manager/mysql_connection.cc
+++ b/server-tools/instance-manager/mysql_connection.cc
@@ -17,13 +17,12 @@
#pragma implementation
#endif
-#include "mysql_connection.h"
-
-#include <m_string.h>
-#include <m_string.h>
#include <my_global.h>
#include <mysql.h>
#include <my_sys.h>
+#include "mysql_connection.h"
+
+#include <m_string.h>
#include <violite.h>
#include "command.h"
@@ -88,7 +87,7 @@ bool Mysql_connection::init()
{
ulong seed1= (ulong) &rand_st + rand();
ulong seed2= (ulong) rand() + (ulong) time(0);
- randominit(&rand_st, seed1, seed2);
+ my_rnd_init(&rand_st, seed1, seed2);
}
/* Fill scramble - server's random message used for handshake */
diff --git a/server-tools/instance-manager/mysql_connection.h b/server-tools/instance-manager/mysql_connection.h
index 56bbf76e146..933dd820372 100644
--- a/server-tools/instance-manager/mysql_connection.h
+++ b/server-tools/instance-manager/mysql_connection.h
@@ -17,7 +17,6 @@
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
#include "thread_registry.h"
-#include <mysql_com.h>
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
#pragma interface
@@ -55,7 +54,7 @@ private:
Thread_registry *thread_registry;
User_map *user_map;
NET net;
- struct rand_struct rand_st;
+ struct my_rnd_struct rand_st;
char scramble[SCRAMBLE_LENGTH + 1];
uint status;
ulong client_capabilities;
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc
index cd20e3bc7ab..8647432a7e4 100644
--- a/server-tools/instance-manager/parse.cc
+++ b/server-tools/instance-manager/parse.cc
@@ -78,7 +78,7 @@ Named_value_arr::Named_value_arr() :
bool Named_value_arr::init()
{
- if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32))
+ if (my_init_dynamic_array(&arr, sizeof(Named_value), 32, 32))
return TRUE;
initialized= TRUE;
diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc
index 489caa0aaa8..087f16dc956 100644
--- a/server-tools/instance-manager/thread_registry.cc
+++ b/server-tools/instance-manager/thread_registry.cc
@@ -21,6 +21,7 @@
#include <thr_alarm.h>
#include <signal.h>
#include "log.h"
+#include <my_sys.h>
#ifndef __WIN__
/* Kick-off signal handler */
diff --git a/sql-bench/example b/sql-bench/example
index df2a9b8be69..877fd080ac5 100644
--- a/sql-bench/example
+++ b/sql-bench/example
@@ -6,15 +6,14 @@ machine="Linux-x64"
# InnoDB tests
-./run-all-tests --suffix=-innodb --comments="Engine=InnoDB --innodb_log_file_size=100M" --create-options="ENGINE=InnoDB" --hw="$hw" --optimization="$optimization" --machine="$machine" --log
-
-./run-all-tests --suffix=_fast-innodb --comments="Engine=InnoDB --innodb_log_file_size=100M" --create-options="ENGINE=InnoDB" --hw="$hw" --optimization="$optimization" --machine="$machine" --fast --log
+./run-all-tests --suffix=-innodb --comments="Engine=InnoDB --innodb_buffer_pool_size=256M --innodb_additional_mem_pool_size=20M --innodb_log_file_size=1000M --innodb_log_buffer_size=16M --innodb_lock_wait_timeout=50 --innodb_flush_log_at_trx_commit=1 --innodb_flush_method=O_DIRECT --innodb_log_files_in_group=2 --skip-innodb-doublewrite" --create-options="ENGINE=InnoDB" --hw="$hw" --optimization="$optimization" --machine="$machine" --log
+./run-all-tests --suffix=_fast-innodb --comments="Engine=InnoDB --innodb_buffer_pool_size=256M --innodb_additional_mem_pool_size=20M --innodb_log_file_size=1000M --innodb_log_buffer_size=16M --innodb_lock_wait_timeout=50 --innodb_flush_log_at_trx_commit=1 --innodb_flush_method=O_DIRECT --innodb_log_files_in_group=2 --skip-innodb-doublewrite" --create-options="ENGINE=InnoDB" --hw="$hw" --optimization="$optimization" --machine="$machine" --fast --log
# MyISAM tests
-./run-all-tests --suffix=-myisam --comments="Engine=MyISAM key_buffer_size=16M" --create-options="ENGINE=myisam" --hw="$hw" --optimization="$optimization" --machine="$machine" --log
+./run-all-tests --suffix=-myisam --comments="Engine=MyISAM key_buffer_size=256M" --create-options="ENGINE=myisam" --hw="$hw" --optimization="$optimization" --machine="$machine" --log
-./run-all-tests --suffix=_fast-myisam --comments="Engine=MyISAM key_buffer_size=16M" --create-options="ENGINE=myisam" --hw="$hw" --optimization="$optimization" --machine="$machine" --fast --log
+./run-all-tests --suffix=_fast-myisam --comments="Engine=MyISAM key_buffer_size=256M" --create-options="ENGINE=myisam" --hw="$hw" --optimization="$optimization" --machine="$machine" --fast --log
compare-results --relative output/RUN-mysql-myisam-* output/RUN-mysql_fast-myisam* output/RUN-mysql*
diff --git a/sql-bench/myisam.cnf b/sql-bench/myisam.cnf
new file mode 100644
index 00000000000..4229f56cefb
--- /dev/null
+++ b/sql-bench/myisam.cnf
@@ -0,0 +1,3 @@
+[mysqld]
+data=/data
+key_buffer_size=256M
diff --git a/sql-common/client.c b/sql-common/client.c
index 63c746a3f5a..51744484623 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -996,7 +996,7 @@ static int add_init_command(struct st_mysql_options *options, const char *cmd)
{
options->init_commands= (DYNAMIC_ARRAY*)my_malloc(sizeof(DYNAMIC_ARRAY),
MYF(MY_WME));
- init_dynamic_array(options->init_commands,sizeof(char*),0,5 CALLER_INFO);
+ init_dynamic_array(options->init_commands,sizeof(char*),5,5 CALLER_INFO);
}
if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index cfd049e1864..83872803dd4 100755
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -119,6 +119,9 @@ ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
IF(WITH_INNOBASE_STORAGE_ENGINE)
TARGET_LINK_LIBRARIES(mysqld innobase)
ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
+IF(WITH_MARIA_STORAGE_ENGINE)
+ TARGET_LINK_LIBRARIES(mysqld maria)
+ENDIF(WITH_MARIA_STORAGE_ENGINE)
ADD_DEPENDENCIES(mysqld GenError)
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index ea3c9f17e23..b98922e2408 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -727,7 +727,6 @@ bool get_next_time(const Time_zone *time_zone, my_time_t *next,
would give an error then.
*/
DBUG_RETURN(1);
- break;
case INTERVAL_LAST:
DBUG_ASSERT(0);
}
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 04d4f858b43..d68dc8ef479 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -94,7 +94,12 @@ Event_queue::Event_queue()
mutex_queue_data_attempting_lock(FALSE),
waiting_on_cond(FALSE)
{
- pthread_mutex_init(&LOCK_event_queue, MY_MUTEX_INIT_FAST);
+ /*
+ Inconsisent usage between LOCK_event_queue and LOCK_scheduler_state and
+ LOCK_open
+ */
+ my_pthread_mutex_init(&LOCK_event_queue, MY_MUTEX_INIT_FAST,
+ "LOCK_event_queue", MYF_NO_DEADLOCK_DETECTION);
pthread_cond_init(&COND_queue_state, NULL);
}
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index d9d010783e8..7a668e2e2d7 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -337,6 +337,14 @@ Event_scheduler::Event_scheduler(Event_queue *queue_arg)
{
pthread_mutex_init(&LOCK_scheduler_state, MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_state, NULL);
+
+#ifdef SAFE_MUTEX
+ /* Ensure right mutex order */
+ pthread_mutex_lock(&LOCK_scheduler_state);
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ pthread_mutex_unlock(&LOCK_scheduler_state);
+#endif
}
diff --git a/sql/events.cc b/sql/events.cc
index e24d51628c0..73c76688eb7 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -319,7 +319,6 @@ common_1_lev_code:
case INTERVAL_MICROSECOND:
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
return 1;
- break;
case INTERVAL_QUARTER:
expr/= 3;
close_quote= FALSE;
@@ -996,7 +995,12 @@ Events::deinit()
void
Events::init_mutexes()
{
- pthread_mutex_init(&LOCK_event_metadata, MY_MUTEX_INIT_FAST);
+ /*
+ Inconsisent usage between LOCK_event_metadata and LOCK_scheduler_state
+ and LOCK_open
+ */
+ my_pthread_mutex_init(&LOCK_event_metadata, MY_MUTEX_INIT_FAST,
+ "LOCK_event_metadata", MYF_NO_DEADLOCK_DETECTION);
}
diff --git a/sql/field.cc b/sql/field.cc
index 973170223e4..379d58e1d24 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2953,18 +2953,18 @@ int Field_tiny::store(double nr)
}
else if (nr > 255.0)
{
- *ptr=(char) 255;
+ *ptr= (uchar) 255;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
else
- *ptr=(char) nr;
+ *ptr= (uchar) nr;
}
else
{
if (nr < -128.0)
{
- *ptr= (char) -128;
+ *ptr= (uchar) -128;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
}
@@ -2975,7 +2975,7 @@ int Field_tiny::store(double nr)
error= 1;
}
else
- *ptr=(char) (int) nr;
+ *ptr=(uchar) (int) nr;
}
return error;
}
@@ -5393,7 +5393,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
int Field_year::store(double nr)
{
- if (nr < 0.0 || nr >= 2155.0)
+ if (nr < 0.0 || nr > 2155.0)
{
(void) Field_year::store((longlong) -1, FALSE);
return 1;
@@ -5514,7 +5514,6 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
int Field_date::store(double nr)
{
longlong tmp;
- int error= 0;
if (nr >= 19000000000000.0 && nr <= 99991231235959.0)
nr=floor(nr/1000000.0); // Timestamp to date
if (nr < 0.0 || nr > 99991231.0)
@@ -5523,7 +5522,6 @@ int Field_date::store(double nr)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
nr, MYSQL_TIMESTAMP_DATE);
- error= 1;
}
else
tmp= (longlong) rint(nr);
@@ -9782,9 +9780,8 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
}
break;
case MYSQL_TYPE_DATE:
- /* Old date type. */
- if (protocol_version != PROTOCOL_VERSION-1)
- sql_type= MYSQL_TYPE_NEWDATE;
+ /* We don't support creation of MYSQL_TYPE_DATE anymore */
+ sql_type= MYSQL_TYPE_NEWDATE;
/* fall trough */
case MYSQL_TYPE_NEWDATE:
length= 10;
diff --git a/sql/field.h b/sql/field.h
index 5136f760fc1..ac8e7dae3c5 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -250,11 +250,11 @@ public:
return test(record[(uint) (null_ptr -table->record[0])] &
null_bit);
}
- inline bool is_null_in_record_with_offset(my_ptrdiff_t offset)
+ inline bool is_null_in_record_with_offset(my_ptrdiff_t col_offset)
{
if (!null_ptr)
return 0;
- return test(null_ptr[offset] & null_bit);
+ return test(null_ptr[col_offset] & null_bit);
}
inline void set_null(my_ptrdiff_t row_offset= 0)
{ if (null_ptr) null_ptr[row_offset]|= null_bit; }
@@ -350,7 +350,7 @@ public:
Number of copied bytes (excluding padded zero bytes -- see above).
*/
- virtual uint get_key_image(uchar *buff, uint length, imagetype type)
+ virtual uint get_key_image(uchar *buff, uint length, imagetype type_arg)
{
get_image(buff, length, &my_charset_bin);
return length;
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 5d8b4e869c8..dc59f1c8fcd 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -525,7 +525,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
ref_pos= ref_buff;
quick_select=select && select->quick;
record=0;
- flag= ((!indexfile && file->ha_table_flags() & HA_REC_NOT_IN_SEQ)
+ flag= ((!indexfile && (file->ha_table_flags() & HA_REC_NOT_IN_SEQ))
|| quick_select);
if (indexfile || flag)
ref_pos= &file->ref[0];
@@ -1212,7 +1212,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
offset= rec_length-res_length;
maxcount= (ulong) (param->keys/((uint) (Tb-Fb) +1));
to_start_filepos= my_b_tell(to_file);
- strpos= (uchar*) sort_buffer;
+ strpos= sort_buffer;
org_max_rows=max_rows= param->max_rows;
/* The following will fire if there is not enough space in sort_buffer */
@@ -1236,7 +1236,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
buffpek->base= strpos;
buffpek->max_keys= maxcount;
strpos+= (uint) (error= (int) read_to_buffer(from_file, buffpek,
- rec_length));
+ rec_length));
if (error == -1)
goto err; /* purecov: inspected */
buffpek->max_keys= buffpek->mem_count; // If less data in buffers than expected
@@ -1325,7 +1325,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
}
}
buffpek= (BUFFPEK*) queue_top(&queue);
- buffpek->base= sort_buffer;
+ buffpek->base= (uchar*) sort_buffer;
buffpek->max_keys= param->keys;
/*
@@ -1365,7 +1365,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
strpos != end ;
strpos+= rec_length)
{
- if (my_b_write(to_file, (uchar *) strpos, res_length))
+ if (my_b_write(to_file, strpos, res_length))
{
error=1; goto err;
}
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 3454f3558e8..1932a9ccec4 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -4230,11 +4230,11 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows)
/**
End of an insert.
*/
-int ha_ndbcluster::end_bulk_insert()
+int ha_ndbcluster::end_bulk_insert(bool abort)
{
int error= 0;
-
DBUG_ENTER("end_bulk_insert");
+
// Check if last inserts need to be flushed
if (m_bulk_insert_not_flushed)
{
@@ -4586,7 +4586,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
Thd_ndb *thd_ndb= get_thd_ndb(thd);
Ndb *ndb= thd_ndb->ndb;
- DBUG_PRINT("enter", ("this: 0x%lx thd: 0x%lx thd_ndb: %lx "
+ DBUG_PRINT("enter", ("this: 0x%lx thd: 0x%lx thd_ndb: 0x%lx "
"thd_ndb->lock_count: %d",
(long) this, (long) thd, (long) thd_ndb,
thd_ndb->lock_count));
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index a17323d3fd6..f3651ebeca9 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -322,7 +322,7 @@ class ha_ndbcluster: public handler
double scan_time();
ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool abort);
static Thd_ndb* seize_thd_ndb();
static void release_thd_ndb(Thd_ndb* thd_ndb);
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index baf86d739eb..4f25068feb8 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -1549,7 +1549,9 @@ end:
dict->forceGCPWait();
int max_timeout= opt_ndb_sync_timeout;
- (void) pthread_mutex_lock(&ndb_schema_object->mutex);
+ /* Inconsistent usage of ndb_schema_object->mutex and LOCK_open */
+ (void) my_pthread_mutex_lock(&ndb_schema_object->mutex,
+ MYF_NO_DEADLOCK_DETECTION);
if (have_lock_open)
{
safe_mutex_assert_owner(&LOCK_open);
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 0e36a868b3e..e0bd3e6fb7e 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -994,7 +994,7 @@ static bool print_admin_msg(THD* thd, const char* msg_type,
va_list args;
Protocol *protocol= thd->protocol;
uint length, msg_length;
- char msgbuf[MI_MAX_MSG_BUF];
+ char msgbuf[HA_MAX_MSG_BUF];
char name[NAME_LEN*2+2];
va_start(args, fmt);
@@ -3235,13 +3235,14 @@ void ha_partition::start_bulk_insert(ha_rows rows)
SYNOPSIS
end_bulk_insert()
+ abort 1 if table will be deleted (error condition)
RETURN VALUE
>0 Error code
0 Success
*/
-int ha_partition::end_bulk_insert()
+int ha_partition::end_bulk_insert(bool abort)
{
int error= 0;
handler **file;
@@ -3251,7 +3252,7 @@ int ha_partition::end_bulk_insert()
do
{
int tmp;
- if ((tmp= (*file)->ha_end_bulk_insert()))
+ if ((tmp= (*file)->ha_end_bulk_insert(abort)))
error= tmp;
} while (*(++file));
DBUG_RETURN(error);
@@ -4973,7 +4974,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info,
stat_info->update_time= file->stats.update_time;
stat_info->check_time= file->stats.check_time;
stat_info->check_sum= 0;
- if (file->ha_table_flags() & HA_HAS_CHECKSUM)
+ if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
stat_info->check_sum= file->checksum();
return;
}
@@ -5293,6 +5294,7 @@ int ha_partition::extra(enum ha_extra_function operation)
case HA_EXTRA_KEYREAD:
case HA_EXTRA_NO_KEYREAD:
case HA_EXTRA_FLUSH:
+ case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
DBUG_RETURN(loop_extra(operation));
/* Category 2), used by non-MyISAM handlers */
@@ -5308,7 +5310,6 @@ int ha_partition::extra(enum ha_extra_function operation)
/* Category 3), used by MyISAM handlers */
case HA_EXTRA_PREPARE_FOR_RENAME:
DBUG_RETURN(prepare_for_rename());
- break;
case HA_EXTRA_NORMAL:
case HA_EXTRA_QUICK:
case HA_EXTRA_PREPARE_FOR_UPDATE:
@@ -5316,8 +5317,7 @@ int ha_partition::extra(enum ha_extra_function operation)
case HA_EXTRA_PREPARE_FOR_DROP:
case HA_EXTRA_FLUSH_CACHE:
{
- if (m_myisam)
- DBUG_RETURN(loop_extra(operation));
+ DBUG_RETURN(loop_extra(operation));
break;
}
case HA_EXTRA_NO_READCHECK:
@@ -5519,8 +5519,8 @@ int ha_partition::loop_extra(enum ha_extra_function operation)
DBUG_ENTER("ha_partition::loop_extra()");
/*
- TODO, 5.2: this is where you could possibly add optimisations to add the bitmap
- _if_ a SELECT.
+ TODO, 5.2: this is where you could possibly add optimisations to add the
+ bitmap _if_ a SELECT.
*/
for (file= m_file; *file; file++)
{
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 8a81a759e2a..3a7084c87ed 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -360,7 +360,7 @@ public:
virtual int delete_row(const uchar * buf);
virtual int delete_all_rows(void);
virtual void start_bulk_insert(ha_rows rows);
- virtual int end_bulk_insert();
+ virtual int end_bulk_insert(bool);
virtual bool is_fatal_error(int error, uint flags)
{
diff --git a/sql/handler.cc b/sql/handler.cc
index 948cb08b13f..ca04398aa35 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -26,7 +26,7 @@
#include "mysql_priv.h"
#include "rpl_filter.h"
#include <myisampack.h>
-#include <errno.h>
+#include "myisam.h"
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
@@ -1158,7 +1158,7 @@ int ha_commit_trans(THD *thd, bool all)
}
status_var_increment(thd->status_var.ha_prepare_count);
}
- DBUG_EXECUTE_IF("crash_commit_after_prepare", abort(););
+ DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_ABORT(););
if (error || (is_real_trans && xid &&
(error= !(cookie= tc_log->log_xid(thd, xid)))))
{
@@ -1166,13 +1166,13 @@ int ha_commit_trans(THD *thd, bool all)
error= 1;
goto end;
}
- DBUG_EXECUTE_IF("crash_commit_after_log", abort(););
+ DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_ABORT(););
}
error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
- DBUG_EXECUTE_IF("crash_commit_before_unlog", abort(););
+ DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_ABORT(););
if (cookie)
tc_log->unlog(cookie, xid);
- DBUG_EXECUTE_IF("crash_commit_after", abort(););
+ DBUG_EXECUTE_IF("crash_commit_after", DBUG_ABORT(););
end:
if (rw_trans)
start_waiting_global_read_lock(thd);
@@ -1482,7 +1482,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
while ((got= hton->recover(hton, info->list, info->len)) > 0 )
{
sql_print_information("Found %d prepared transaction(s) in %s",
- got, ha_resolve_storage_engine_name(hton));
+ got, hton_name(hton)->str);
for (int i=0; i < got; i ++)
{
my_xid x=info->list[i].get_my_xid();
@@ -2583,11 +2583,14 @@ void handler::print_error(int error, myf errflag)
break;
case HA_ERR_FOUND_DUPP_KEY:
{
- uint key_nr=get_dup_key(error);
- if ((int) key_nr >= 0)
+ if (table)
{
- print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME));
- DBUG_VOID_RETURN;
+ uint key_nr=get_dup_key(error);
+ if ((int) key_nr >= 0)
+ {
+ print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME));
+ DBUG_VOID_RETURN;
+ }
}
textno=ER_DUP_KEY;
break;
@@ -3486,7 +3489,7 @@ void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info,
stat_info->update_time= stats.update_time;
stat_info->check_time= stats.check_time;
stat_info->check_sum= 0;
- if (table_flags() & (ulong) HA_HAS_CHECKSUM)
+ if (table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_OLD_CHECKSUM))
stat_info->check_sum= checksum();
return;
}
@@ -3607,7 +3610,6 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
void st_ha_check_opt::init()
{
flags= sql_flags= 0;
- sort_buffer_size = current_thd->variables.myisam_sort_buff_size;
}
@@ -4359,7 +4361,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
{
if (db_type->state != SHOW_OPTION_YES)
{
- const LEX_STRING *name=&hton2plugin[db_type->slot]->name;
+ const LEX_STRING *name= hton_name(db_type);
result= stat_print(thd, name->str, name->length,
"", 0, "DISABLED", 8) ? 1 : 0;
}
diff --git a/sql/handler.h b/sql/handler.h
index d43fc4725dd..02fef2760f1 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -107,7 +107,8 @@
#define HA_CAN_FULLTEXT (1 << 21)
#define HA_CAN_SQL_HANDLER (1 << 22)
#define HA_NO_AUTO_INCREMENT (1 << 23)
-#define HA_HAS_CHECKSUM (1 << 24)
+/* Has automatic checksums and uses the old checksum format */
+#define HA_HAS_OLD_CHECKSUM (1 << 24)
/* Table data are stored in separate files (for lower_case_table_names) */
#define HA_FILE_BASED (1 << 26)
#define HA_NO_VARCHAR (1 << 27)
@@ -124,6 +125,8 @@
*/
#define HA_BINLOG_ROW_CAPABLE (LL(1) << 34)
#define HA_BINLOG_STMT_CAPABLE (LL(1) << 35)
+/* Has automatic checksums and uses the new checksum format */
+#define HA_HAS_NEW_CHECKSUM (LL(1) << 36)
/*
Set of all binlog flags. Currently only contain the capabilities
@@ -237,8 +240,6 @@
#define HA_LEX_CREATE_TMP_TABLE 1
#define HA_LEX_CREATE_IF_NOT_EXISTS 2
#define HA_LEX_CREATE_TABLE_LIKE 4
-#define HA_OPTION_NO_CHECKSUM (1L << 17)
-#define HA_OPTION_NO_DELAY_KEY_WRITE (1L << 18)
#define HA_MAX_REC_LENGTH 65535
/* Table caching type */
@@ -712,6 +713,12 @@ struct handlerton
};
+inline LEX_STRING *hton_name(const handlerton *hton)
+{
+ return &(hton2plugin[hton->slot]->name);
+}
+
+
/* Possible flags of a handlerton (there can be 32 of them) */
#define HTON_NO_FLAGS 0
#define HTON_CLOSE_CURSORS_AT_COMMIT (1 << 0)
@@ -763,6 +770,7 @@ struct THD_TRANS
bool modified_non_trans_table;
void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; }
+ THD_TRANS() {} /* Remove gcc warning */
};
@@ -992,10 +1000,9 @@ typedef class Item COND;
typedef struct st_ha_check_opt
{
st_ha_check_opt() {} /* Remove gcc warning */
- ulong sort_buffer_size;
uint flags; /* isam layer flags (e.g. for myisamchk) */
uint sql_flags; /* sql layer flags - for something myisamchk cannot do */
- KEY_CACHE *key_cache; /* new key cache when changing key cache */
+ KEY_CACHE *key_cache; /* new key cache when changing key cache */
void init();
} HA_CHECK_OPT;
@@ -1224,10 +1231,10 @@ public:
estimation_rows_to_insert= rows;
start_bulk_insert(rows);
}
- int ha_end_bulk_insert()
+ int ha_end_bulk_insert(bool abort)
{
estimation_rows_to_insert= 0;
- return end_bulk_insert();
+ return end_bulk_insert(abort);
}
int ha_bulk_update_row(const uchar *old_data, uchar *new_data,
uint *dup_key_found);
@@ -1447,14 +1454,18 @@ public:
}
virtual int read_first_row(uchar *buf, uint primary_key);
/**
- The following function is only needed for tables that may be temporary
- tables during joins.
+ The following 3 function is only needed for tables that may be
+ internal temporary tables during joins.
*/
- virtual int restart_rnd_next(uchar *buf, uchar *pos)
+ virtual int remember_rnd_pos()
+ { return HA_ERR_WRONG_COMMAND; }
+ virtual int restart_rnd_next(uchar *buf)
{ return HA_ERR_WRONG_COMMAND; }
virtual int rnd_same(uchar *buf, uint inx)
{ return HA_ERR_WRONG_COMMAND; }
- virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key)
+
+ virtual ha_rows records_in_range(uint inx, key_range *min_key,
+ key_range *max_key)
{ return (ha_rows) 10; }
virtual void position(const uchar *record)=0;
virtual int info(uint)=0; // see my_base.h for full description
@@ -1566,7 +1577,8 @@ public:
*/
virtual const char **bas_ext() const =0;
- virtual int get_default_no_partitions(HA_CREATE_INFO *info) { return 1;}
+ virtual int get_default_no_partitions(HA_CREATE_INFO *create_info)
+ { return 1;}
virtual void set_auto_partitions(partition_info *part_info) { return; }
virtual bool get_no_parts(const char *name,
uint *no_parts)
@@ -1609,13 +1621,11 @@ public:
virtual bool is_crashed() const { return 0; }
virtual bool auto_repair() const { return 0; }
-
#define CHF_CREATE_FLAG 0
#define CHF_DELETE_FLAG 1
#define CHF_RENAME_FLAG 2
#define CHF_INDEX_FLAG 3
-
/**
@note lock_count() can return > 1 if the table is MERGE or partitioned.
*/
@@ -1743,6 +1753,8 @@ public:
return 0;
}
+ LEX_STRING *engine_name() { return hton_name(ht); }
+
protected:
/* Service methods for use by storage engines. */
void ha_statistic_increment(ulong SSV::*offset) const;
@@ -1762,6 +1774,7 @@ protected:
tables.
*/
virtual int delete_table(const char *name);
+
private:
/* Private helpers */
inline void mark_trx_read_write();
@@ -1848,7 +1861,7 @@ private:
virtual int repair(THD* thd, HA_CHECK_OPT* check_opt)
{ return HA_ADMIN_NOT_IMPLEMENTED; }
virtual void start_bulk_insert(ha_rows rows) {}
- virtual int end_bulk_insert() { return 0; }
+ virtual int end_bulk_insert(bool abort) { return 0; }
virtual int index_read(uchar * buf, const uchar * key, uint key_len,
enum ha_rkey_function find_flag)
{ return HA_ERR_WRONG_COMMAND; }
@@ -1960,7 +1973,7 @@ static inline enum legacy_db_type ha_legacy_type(const handlerton *db_type)
static inline const char *ha_resolve_storage_engine_name(const handlerton *db_type)
{
- return db_type == NULL ? "UNKNOWN" : hton2plugin[db_type->slot]->name.str;
+ return db_type == NULL ? "UNKNOWN" : hton_name(db_type)->str;
}
static inline bool ha_check_storage_engine_flag(const handlerton *db_type, uint32 flag)
diff --git a/sql/item.cc b/sql/item.cc
index 6b786549dfc..f74d8df1045 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -255,11 +255,9 @@ my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value)
my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
{
String *res;
- char *end_ptr;
if (!(res= val_str(&str_value)))
return 0; // NULL or EOM
- end_ptr= (char*) res->ptr()+ res->length();
if (str2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM,
res->ptr(), res->length(), res->charset(),
decimal_value) & E_DEC_BAD_NUM)
@@ -383,7 +381,7 @@ Item::Item():
maybe_null=null_value=with_sum_func=unsigned_flag=0;
decimals= 0; max_length= 0;
with_subselect= 0;
- cmp_context= (Item_result)-1;
+ cmp_context= IMPOSSIBLE_RESULT;
/* Put item in free list so that we can free all items at end */
THD *thd= current_thd;
@@ -1476,7 +1474,9 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
if (collation == &my_charset_bin)
{
if (derivation <= dt.derivation)
- ; // Do nothing
+ {
+ /* Do nothing */
+ }
else
{
set(dt);
@@ -1488,15 +1488,11 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
set(dt);
}
- else
- {
- // Do nothing
- }
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
left_is_superset(this, &dt))
{
- // Do nothing
+ /* Do nothing */
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
left_is_superset(&dt, this))
@@ -1507,7 +1503,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
derivation < dt.derivation &&
dt.derivation >= DERIVATION_SYSCONST)
{
- // Do nothing;
+ /* Do nothing */
}
else if ((flags & MY_COLL_ALLOW_COERCIBLE_CONV) &&
dt.derivation < derivation &&
@@ -1524,7 +1520,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
}
else if (derivation < dt.derivation)
{
- // Do nothing
+ /* Do nothing */
}
else if (dt.derivation < derivation)
{
@@ -1534,7 +1530,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
if (collation == dt.collation)
{
- // Do nothing
+ /* Do nothing */
}
else
{
@@ -4362,7 +4358,7 @@ Item *Item_field::equal_fields_propagator(uchar *arg)
DATE/TIME represented as an int and as a string.
*/
if (!item ||
- (cmp_context != (Item_result)-1 && item->cmp_context != cmp_context))
+ (cmp_context != IMPOSSIBLE_RESULT && item->cmp_context != cmp_context))
item= this;
else if (field && (field->flags & ZEROFILL_FLAG) && IS_NUM(field->type()))
{
@@ -4426,7 +4422,7 @@ Item *Item_field::replace_equal_field(uchar *arg)
Item *const_item= item_equal->get_const();
if (const_item)
{
- if (cmp_context != (Item_result)-1 &&
+ if (cmp_context != IMPOSSIBLE_RESULT &&
const_item->cmp_context != cmp_context)
return this;
return const_item;
diff --git a/sql/item.h b/sql/item.h
index be9daf672f0..e90cdbbc8f8 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1029,6 +1029,7 @@ public:
if (orig_name)
name= orig_name;
}
+ Item_basic_constant() {} /* Remove gcc warning */
};
@@ -2012,9 +2013,9 @@ public:
class Item_partition_func_safe_string: public Item_string
{
public:
- Item_partition_func_safe_string(const char *name, uint length,
+ Item_partition_func_safe_string(const char *name_arg, uint length,
CHARSET_INFO *cs= NULL):
- Item_string(name, length, cs)
+ Item_string(name_arg, length, cs)
{}
};
@@ -2034,8 +2035,8 @@ public:
class Item_blob :public Item_partition_func_safe_string
{
public:
- Item_blob(const char *name, uint length) :
- Item_partition_func_safe_string(name, length, &my_charset_bin)
+ Item_blob(const char *name_arg, uint length) :
+ Item_partition_func_safe_string(name_arg, length, &my_charset_bin)
{ max_length= length; }
enum Type type() const { return TYPE_HOLDER; }
enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
@@ -2063,8 +2064,8 @@ class Item_return_int :public Item_int
enum_field_types int_field_type;
public:
Item_return_int(const char *name_arg, uint length,
- enum_field_types field_type_arg, longlong value= 0)
- :Item_int(name_arg, value, length), int_field_type(field_type_arg)
+ enum_field_types field_type_arg, longlong value_arg= 0)
+ :Item_int(name_arg, value_arg, length), int_field_type(field_type_arg)
{
unsigned_flag=1;
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index bd90dd81365..cad3bb29961 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -844,12 +844,11 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2,
Item_result type)
{
- enum enum_date_cmp_type cmp_type;
ulonglong const_value= (ulonglong)-1;
a= a1;
b= a2;
- if ((cmp_type= can_compare_as_dates(*a, *b, &const_value)))
+ if (can_compare_as_dates(*a, *b, &const_value))
{
thd= current_thd;
owner= owner_arg;
@@ -5239,6 +5238,7 @@ void Item_equal::update_used_tables()
not_null_tables_cache= used_tables_cache= 0;
if ((const_item_cache= cond_false))
return;
+ const_item_cache= 1;
while ((item=li++))
{
item->update_used_tables();
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 349c47816ad..4a440c00da5 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -5118,7 +5118,7 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type,
CHARSET_INFO *real_cs= (cs ? cs : thd->variables.collation_connection);
if (c_len == NULL)
{
- len= LL(-1);
+ len= (ulong) -1L;
}
else
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 34cb50ee7fa..55ed5604301 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -450,7 +450,6 @@ Field *Item_func::tmp_table_field(TABLE *table)
break;
case STRING_RESULT:
return make_string_field(table);
- break;
case DECIMAL_RESULT:
field= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
decimals,
@@ -2120,7 +2119,7 @@ void Item_func_rand::seed_random(Item *arg)
args[0] is a constant.
*/
uint32 tmp= (uint32) arg->val_int();
- randominit(rand, (uint32) (tmp*0x10001L+55555555L),
+ my_rnd_init(rand, (uint32) (tmp*0x10001L+55555555L),
(uint32) (tmp*0x10000001L));
}
@@ -2140,7 +2139,7 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
No need to send a Rand log event if seed was given eg: RAND(seed),
as it will be replicated in the query as such.
*/
- if (!rand && !(rand= (struct rand_struct*)
+ if (!rand && !(rand= (struct my_rnd_struct*)
thd->stmt_arena->alloc(sizeof(*rand))))
return TRUE;
@@ -2713,8 +2712,7 @@ longlong Item_func_find_in_set::val_int()
}
null_value=0;
- int diff;
- if ((diff=buffer->length() - find->length()) >= 0)
+ if ((int) (buffer->length() - find->length()) >= 0)
{
my_wc_t wc;
CHARSET_INFO *cs= cmp_collation.collation;
@@ -4022,7 +4020,8 @@ double user_var_entry::val_real(my_bool *null_value)
case STRING_RESULT:
return my_atof(value); // This is null terminated
case ROW_RESULT:
- DBUG_ASSERT(1); // Impossible
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // Impossible
break;
}
return 0.0; // Impossible
@@ -4053,7 +4052,8 @@ longlong user_var_entry::val_int(my_bool *null_value) const
return my_strtoll10(value, (char**) 0, &error);// String is null terminated
}
case ROW_RESULT:
- DBUG_ASSERT(1); // Impossible
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // Impossible
break;
}
return LL(0); // Impossible
@@ -4084,8 +4084,10 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
case STRING_RESULT:
if (str->copy(value, length, collation.collation))
str= 0; // EOM error
+ break;
case ROW_RESULT:
- DBUG_ASSERT(1); // Impossible
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // Impossible
break;
}
return(str);
@@ -4112,7 +4114,8 @@ my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val)
str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val);
break;
case ROW_RESULT:
- DBUG_ASSERT(1); // Impossible
+ case IMPOSSIBLE_RESULT:
+ DBUG_ASSERT(0); // Impossible
break;
}
return(val);
@@ -6093,12 +6096,13 @@ void uuid_short_init()
(((ulonglong) server_start_time) << 24));
}
+pthread_mutex_t LOCK_uuid_short;
longlong Item_func_uuid_short::val_int()
{
ulonglong val;
- pthread_mutex_lock(&LOCK_uuid_generator);
+ pthread_mutex_lock(&LOCK_uuid_short);
val= uuid_value++;
- pthread_mutex_unlock(&LOCK_uuid_generator);
+ pthread_mutex_unlock(&LOCK_uuid_short);
return (longlong) val;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index d23d821baf6..b843a974da5 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -695,7 +695,7 @@ public:
class Item_func_rand :public Item_real_func
{
- struct rand_struct *rand;
+ struct my_rnd_struct *rand;
public:
Item_func_rand(Item *a) :Item_real_func(a), rand(0) {}
Item_func_rand() :Item_real_func() {}
@@ -1489,7 +1489,6 @@ public:
/* for fulltext search */
-#include <ft_global.h>
class Item_func_match :public Item_real_func
{
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index fc9375e68a5..669d160d322 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -3360,156 +3360,17 @@ err:
}
#endif
-/*
- UUID, as in
- DCE 1.1: Remote Procedure Call,
- Open Group Technical Standard Document Number C706, October 1997,
- (supersedes C309 DCE: Remote Procedure Call 8/1994,
- which was basis for ISO/IEC 11578:1996 specification)
-*/
-
-static struct rand_struct uuid_rand;
-static uint nanoseq;
-static ulonglong uuid_time=0;
-static char clock_seq_and_node_str[]="-0000-000000000000";
-
-/**
- number of 100-nanosecond intervals between
- 1582-10-15 00:00:00.00 and 1970-01-01 00:00:00.00.
-*/
-#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * \
- 1000 * 1000 * 10)
-
-#define UUID_VERSION 0x1000
-#define UUID_VARIANT 0x8000
-
-static void tohex(char *to, uint from, uint len)
-{
- to+= len;
- while (len--)
- {
- *--to= _dig_vec_lower[from & 15];
- from >>= 4;
- }
-}
-
-static void set_clock_seq_str()
-{
- uint16 clock_seq= ((uint)(my_rnd(&uuid_rand)*16383)) | UUID_VARIANT;
- tohex(clock_seq_and_node_str+1, clock_seq, 4);
- nanoseq= 0;
-}
String *Item_func_uuid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- char *s;
- THD *thd= current_thd;
-
- pthread_mutex_lock(&LOCK_uuid_generator);
- if (! uuid_time) /* first UUID() call. initializing data */
- {
- ulong tmp=sql_rnd_with_mutex();
- uchar mac[6];
- int i;
- if (my_gethwaddr(mac))
- {
- /* purecov: begin inspected */
- /*
- generating random "hardware addr"
- and because specs explicitly specify that it should NOT correlate
- with a clock_seq value (initialized random below), we use a separate
- randominit() here
- */
- randominit(&uuid_rand, tmp + (ulong) thd, tmp + (ulong)global_query_id);
- for (i=0; i < (int)sizeof(mac); i++)
- mac[i]=(uchar)(my_rnd(&uuid_rand)*255);
- /* purecov: end */
- }
- s=clock_seq_and_node_str+sizeof(clock_seq_and_node_str)-1;
- for (i=sizeof(mac)-1 ; i>=0 ; i--)
- {
- *--s=_dig_vec_lower[mac[i] & 15];
- *--s=_dig_vec_lower[mac[i] >> 4];
- }
- randominit(&uuid_rand, tmp + (ulong) server_start_time,
- tmp + (ulong) thd->status_var.bytes_sent);
- set_clock_seq_str();
- }
+ uchar guid[MY_UUID_SIZE];
- ulonglong tv= my_getsystime() + UUID_TIME_OFFSET + nanoseq;
-
- if (likely(tv > uuid_time))
- {
- /*
- Current time is ahead of last timestamp, as it should be.
- If we "borrowed time", give it back, just as long as we
- stay ahead of the previous timestamp.
- */
- if (nanoseq)
- {
- DBUG_ASSERT((tv > uuid_time) && (nanoseq > 0));
- /*
- -1 so we won't make tv= uuid_time for nanoseq >= (tv - uuid_time)
- */
- ulong delta= min(nanoseq, (ulong) (tv - uuid_time -1));
- tv-= delta;
- nanoseq-= delta;
- }
- }
- else
- {
- if (unlikely(tv == uuid_time))
- {
- /*
- For low-res system clocks. If several requests for UUIDs
- end up on the same tick, we add a nano-second to make them
- different.
- ( current_timestamp + nanoseq * calls_in_this_period )
- may end up > next_timestamp; this is OK. Nonetheless, we'll
- try to unwind nanoseq when we get a chance to.
- If nanoseq overflows, we'll start over with a new numberspace
- (so the if() below is needed so we can avoid the ++tv and thus
- match the follow-up if() if nanoseq overflows!).
- */
- if (likely(++nanoseq))
- ++tv;
- }
-
- if (unlikely(tv <= uuid_time))
- {
- /*
- If the admin changes the system clock (or due to Daylight
- Saving Time), the system clock may be turned *back* so we
- go through a period once more for which we already gave out
- UUIDs. To avoid duplicate UUIDs despite potentially identical
- times, we make a new random component.
- We also come here if the nanoseq "borrowing" overflows.
- In either case, we throw away any nanoseq borrowing since it's
- irrelevant in the new numberspace.
- */
- set_clock_seq_str();
- tv= my_getsystime() + UUID_TIME_OFFSET;
- nanoseq= 0;
- DBUG_PRINT("uuid",("making new numberspace"));
- }
- }
-
- uuid_time=tv;
- pthread_mutex_unlock(&LOCK_uuid_generator);
-
- uint32 time_low= (uint32) (tv & 0xFFFFFFFF);
- uint16 time_mid= (uint16) ((tv >> 32) & 0xFFFF);
- uint16 time_hi_and_version= (uint16) ((tv >> 48) | UUID_VERSION);
-
- str->realloc(UUID_LENGTH+1);
- str->length(UUID_LENGTH);
+ str->realloc(MY_UUID_STRING_LENGTH+1);
+ str->length(MY_UUID_STRING_LENGTH);
str->set_charset(system_charset_info);
- s=(char *) str->ptr();
- s[8]=s[13]='-';
- tohex(s, time_low, 8);
- tohex(s+9, time_mid, 4);
- tohex(s+14, time_hi_and_version, 4);
- strmov(s+18, clock_seq_and_node_str);
+ my_uuid(guid);
+ my_uuid2str(guid, (char *)str->ptr());
+
return str;
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 81baf9a4c5f..daf384236a5 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -815,7 +815,7 @@ public:
String *val_str(String *) ZLIB_DEPENDED_FUNCTION
};
-#define UUID_LENGTH (8+1+4+1+4+1+4+1+12)
+
class Item_func_uuid: public Item_str_func
{
public:
@@ -827,7 +827,7 @@ public:
charset when hex(), format(), md5(), etc, and implicit
number-to-string conversion will use 'ascii'
*/
- max_length= UUID_LENGTH * system_charset_info->mbmaxlen;
+ max_length= MY_UUID_STRING_LENGTH * system_charset_info->mbmaxlen;
}
const char *func_name() const{ return "uuid"; }
String *val_str(String *);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 3981b91a27c..dcb2a364996 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1047,9 +1047,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
- SELECT_LEX *current= thd->lex->current_select, *up;
+ SELECT_LEX *current= thd->lex->current_select;
- thd->lex->current_select= up= current->return_after_parsing();
+ thd->lex->current_select= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd, 0))
{
@@ -1270,8 +1270,8 @@ Item_in_subselect::row_value_transformer(JOIN *join)
SELECT_LEX_UNIT *master_unit= select_lex->master_unit();
substitution= optimizer;
- SELECT_LEX *current= thd->lex->current_select, *up;
- thd->lex->current_select= up= current->return_after_parsing();
+ SELECT_LEX *current= thd->lex->current_select;
+ thd->lex->current_select= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd, 0))
{
@@ -1517,7 +1517,7 @@ Item_subselect::trans_res
Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func)
{
Query_arena *arena, backup;
- SELECT_LEX *current= thd->lex->current_select, *up;
+ SELECT_LEX *current= thd->lex->current_select;
const char *save_where= thd->where;
Item_subselect::trans_res res= RES_ERROR;
bool result;
@@ -1559,7 +1559,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func)
goto err;
}
- thd->lex->current_select= up= current->return_after_parsing();
+ thd->lex->current_select= current->return_after_parsing();
result= (!left_expr->fixed &&
left_expr->fix_fields(thd, optimizer->arguments()));
/* fix_fields can change reference to left_expr, we need reassign it */
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 68d85418324..0e13830a3b1 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -2024,8 +2024,8 @@ static int my_xpath_parse_OrExpr(MY_XPATH *xpath)
Item *prev= xpath->item;
if (!my_xpath_parse_AndExpr(xpath))
{
- return 0;
xpath->error= 1;
+ return 0;
}
xpath->item= new Item_cond_or(nodeset2bool(xpath, prev),
nodeset2bool(xpath, xpath->item));
diff --git a/sql/lex.h b/sql/lex.h
index acb81dcf717..c2ee1c020b3 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -387,7 +387,7 @@ static SYMBOL symbols[] = {
{ "PACK_KEYS", SYM(PACK_KEYS_SYM)},
{ "PARSER", SYM(PARSER_SYM)},
{ "PAGE", SYM(PAGE_SYM)},
- { "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)},
+ { "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)},
{ "PARTIAL", SYM(PARTIAL)},
{ "PARTITION", SYM(PARTITION_SYM)},
{ "PARTITIONING", SYM(PARTITIONING_SYM)},
diff --git a/sql/lock.cc b/sql/lock.cc
index f36e8d605d3..8f58dd6ee86 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -34,8 +34,8 @@
This is followed by a call to thr_multi_lock() for all tables.
- When statement is done, we call mysql_unlock_tables().
- This will call thr_multi_unlock() followed by
- table_handler->external_lock(thd, F_UNLCK) for each table.
+ table_handler->external_lock(thd, F_UNLCK) followed by
+ thr_multi_unlock() for each table.
- Note that mysql_unlock_tables() may be called several times as
MySQL in some cases can free some tables earlier than others.
@@ -385,10 +385,10 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
{
DBUG_ENTER("mysql_unlock_tables");
- if (sql_lock->lock_count)
- thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
if (sql_lock->table_count)
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
+ if (sql_lock->lock_count)
+ thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
my_free((uchar*) sql_lock,MYF(0));
DBUG_VOID_RETURN;
}
diff --git a/sql/log.cc b/sql/log.cc
index 74dc75702ae..d0ba1ec90c3 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1495,12 +1495,19 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
YESNO(in_transaction),
YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table)));
- if (!in_transaction || all)
+ if (thd->options & OPTION_BIN_LOG)
{
- Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
- qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
- error= binlog_end_trans(thd, trx_data, &qev, all);
- goto end;
+ if (!in_transaction || all)
+ {
+ Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
+ qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
+ error= binlog_end_trans(thd, trx_data, &qev, all);
+ goto end;
+ }
+ }
+ else
+ {
+ trx_data->reset();
}
end:
@@ -2351,7 +2358,12 @@ void MYSQL_BIN_LOG::init_pthread_objects()
DBUG_ASSERT(inited == 0);
inited= 1;
(void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
+ /*
+ LOCK_index and LOCK_log are taken in wrong order
+ Can be seen with 'mysql-test-run ndb.ndb_binlog_basic'
+ */
+ (void) my_pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW, "LOCK_index",
+ MYF_NO_DEADLOCK_DETECTION);
(void) pthread_cond_init(&update_cond, 0);
}
@@ -4405,7 +4417,7 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
goto err;
if (flush_and_sync())
goto err;
- DBUG_EXECUTE_IF("half_binlogged_transaction", abort(););
+ DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_ABORT(););
if (cache->error) // Error on read
{
sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
@@ -4774,10 +4786,12 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer)
int vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
{
char buff[1024];
- size_t length;
DBUG_ENTER("vprint_msg_to_log");
- length= my_vsnprintf(buff, sizeof(buff), format, args);
+#ifdef __NT__
+ size_t length=
+#endif
+ my_vsnprintf(buff, sizeof(buff), format, args);
print_buffer_to_file(level, buff);
#ifdef __NT__
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 0f980f1808d..250cfd8da4e 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -5222,8 +5222,9 @@ void User_var_log_event::pack_info(Protocol* protocol)
}
break;
case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
default:
- DBUG_ASSERT(1);
+ DBUG_ASSERT(0);
return;
}
}
@@ -5312,8 +5313,9 @@ bool User_var_log_event::write(IO_CACHE* file)
pos= (uchar*) val;
break;
case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
default:
- DBUG_ASSERT(1);
+ DBUG_ASSERT(0);
return 0;
}
int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
@@ -5431,7 +5433,7 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
break;
case ROW_RESULT:
default:
- DBUG_ASSERT(1);
+ DBUG_ASSERT(0);
return;
}
}
@@ -5493,8 +5495,9 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
it= new Item_string(val, val_len, charset);
break;
case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
default:
- DBUG_ASSERT(1);
+ DBUG_ASSERT(0);
return 0;
}
}
@@ -8161,7 +8164,7 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *
ultimately. Still todo: fix
*/
}
- if ((local_error= m_table->file->ha_end_bulk_insert()))
+ if ((local_error= m_table->file->ha_end_bulk_insert(0)))
{
m_table->file->print_error(local_error, MYF(0));
}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 75aa8722aa9..6ee2a4549e6 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -943,7 +943,7 @@ int Write_rows_log_event_old::do_after_row_operations(TABLE *table, int error)
fires bug#27077
todo: explain or fix
*/
- if ((local_error= table->file->ha_end_bulk_insert()))
+ if ((local_error= table->file->ha_end_bulk_insert(0)))
{
table->file->print_error(local_error, MYF(0));
}
@@ -2631,7 +2631,7 @@ Write_rows_log_event_old::do_after_row_operations(const Slave_reporting_capabili
fires bug#27077
todo: explain or fix
*/
- if ((local_error= m_table->file->ha_end_bulk_insert()))
+ if ((local_error= m_table->file->ha_end_bulk_insert(0)))
{
m_table->file->print_error(local_error, MYF(0));
}
diff --git a/sql/my_lock.c b/sql/my_lock.c
index f66d7282f72..276259b106a 100644
--- a/sql/my_lock.c
+++ b/sql/my_lock.c
@@ -25,7 +25,15 @@
#include <thr_alarm.h>
#include <errno.h>
- /* Lock a part of a file */
+/**
+ @breif Lock a part of a file
+
+ @note
+ This works like mysys/my_lock.c, with the exception that this function
+ uses the thr_alarm() to break long lock statements.
+ (mysys can't use thr_alarm() as by default the alarm handling doesn't
+ exists)
+*/
int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags)
{
@@ -36,29 +44,34 @@ int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags)
DBUG_ENTER("my_lock");
DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
fd,locktype,(ulong) start,(ulong) length,MyFlags));
- if (my_disable_locking)
+ if (my_disable_locking && ! (MyFlags & MY_FORCE_LOCK))
DBUG_RETURN(0); /* purecov: inspected */
+
m_lock.l_type=(short) locktype;
m_lock.l_whence=0L;
m_lock.l_start=(long) start;
m_lock.l_len=(long) length;
- wait_for_alarm=(MyFlags & MY_DONT_WAIT ? MY_HOW_OFTEN_TO_ALARM :
- (uint) 12*60*60);
if (fcntl(fd,F_SETLK,&m_lock) != -1) /* Check if we can lock */
DBUG_RETURN(0); /* Ok, file locked */
- DBUG_PRINT("info",("Was locked, trying with alarm"));
- if (!thr_alarm(&alarmed,wait_for_alarm,&alarm_buff))
- {
- int value;
- while ((value=fcntl(fd,F_SETLKW,&m_lock)) && !thr_got_alarm(&alarmed) &&
- errno == EINTR) ;
- thr_end_alarm(&alarmed);
- if (value != -1)
- DBUG_RETURN(0);
- }
- else
+
+ if (!(MyFlags & MY_NO_WAIT))
{
- errno=EINTR;
+ wait_for_alarm= (MyFlags & MY_SHORT_WAIT ? MY_HOW_OFTEN_TO_ALARM :
+ (uint) 12*60*60);
+ DBUG_PRINT("info",("Was locked, trying with alarm"));
+ if (!thr_alarm(&alarmed,wait_for_alarm,&alarm_buff))
+ {
+ int value;
+ while ((value=fcntl(fd,F_SETLKW,&m_lock)) && !thr_got_alarm(&alarmed) &&
+ errno == EINTR) ;
+ thr_end_alarm(&alarmed);
+ if (value != -1)
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ errno=EINTR;
+ }
}
if (errno == EINTR || errno == EACCES)
my_errno=EAGAIN; /* Easier to check for this */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 9ce8077249c..42131340d6d 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -622,7 +622,6 @@ enum enum_parsing_place
struct st_table;
-#define thd_proc_info(thd, msg) set_thd_proc_info(thd, msg, __func__, __FILE__, __LINE__)
class THD;
enum enum_check_fields
@@ -632,7 +631,6 @@ enum enum_check_fields
CHECK_FIELD_ERROR_FOR_NULL
};
-
/** Struct to handle simple linked lists. */
typedef struct st_sql_list {
uint elements;
@@ -936,7 +934,7 @@ inline bool check_and_unset_keyword(const char *dbug_str)
{
const char *extra_str= "-d,";
char total_str[200];
- if (_db_strict_keyword_ (dbug_str))
+ if (_db_keyword_ (0, dbug_str, 1))
{
strxmov(total_str, extra_str, dbug_str, NullS);
DBUG_SET(total_str);
@@ -996,7 +994,7 @@ check_and_unset_inject_value(int value)
#define SET_ERROR_INJECT_VALUE(x) \
current_thd->error_inject_value= (x)
#define ERROR_INJECT_CRASH(code) \
- DBUG_EVALUATE_IF(code, (abort(), 0), 0)
+ DBUG_EVALUATE_IF(code, (DBUG_ABORT(), 0), 0)
#define ERROR_INJECT_ACTION(code, action) \
(check_and_unset_keyword(code) ? ((action), 0) : 0)
#define ERROR_INJECT(code) \
@@ -1006,7 +1004,7 @@ check_and_unset_inject_value(int value)
#define ERROR_INJECT_VALUE_ACTION(value,action) \
(check_and_unset_inject_value(value) ? (action) : 0)
#define ERROR_INJECT_VALUE_CRASH(value) \
- ERROR_INJECT_VALUE_ACTION(value, (abort(), 0))
+ ERROR_INJECT_VALUE_ACTION(value, (DBUG_ABORT(), 0))
#endif
@@ -1243,6 +1241,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
List<List_item> &values, List<Item> &update_fields,
List<Item> &update_values, enum_duplicates flag,
bool ignore);
+void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type,
+ enum_duplicates duplic,
+ bool is_multi_insert);
int check_that_all_fields_are_given_values(THD *thd, TABLE *entry,
TABLE_LIST *table_list);
void prepare_triggers_for_insert_stmt(TABLE *table);
@@ -1995,7 +1996,8 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_lock_db,
LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
LOCK_global_system_variables, LOCK_user_conn,
LOCK_prepared_stmt_count,
- LOCK_bytes_sent, LOCK_bytes_received, LOCK_connection_count;
+ LOCK_bytes_sent, LOCK_bytes_received, LOCK_connection_count,
+ LOCK_uuid_short;
#ifdef HAVE_OPENSSL
extern pthread_mutex_t LOCK_des_key_file;
#endif
@@ -2020,7 +2022,10 @@ extern struct system_variables global_system_variables;
#ifdef MYSQL_SERVER
extern struct system_variables max_system_variables;
extern struct system_status_var global_status_var;
-extern struct rand_struct sql_rand;
+extern struct my_rnd_struct sql_rand;
+
+extern handlerton *maria_hton; /* @todo remove, make it static in ha_maria.cc
+ currently it's needed for sql_delete.cc */
extern const char *opt_date_time_formats[];
extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
@@ -2038,10 +2043,11 @@ extern uint sql_command_flags[];
extern TYPELIB log_output_typelib;
/* optional things, have_* variables */
+extern SHOW_COMP_OPTION have_maria_db;
extern SHOW_COMP_OPTION have_community_features;
-
extern handlerton *partition_hton;
extern handlerton *myisam_hton;
+extern handlerton *maria_hton;
extern handlerton *heap_hton;
extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index a2ccbc42e77..4df499bf978 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#include "mysqld_suffix.h"
#include "mysys_err.h"
#include "events.h"
+#include <waiting_threads.h>
#include "../storage/myisam/ha_myisam.h"
@@ -166,7 +167,7 @@ static void registerwithneb();
static void getvolumename();
static void getvolumeID(BYTE *volumeName);
#endif /* __NETWARE__ */
-
+
#ifdef _AIX41
int initgroups(const char *,unsigned int);
@@ -345,7 +346,7 @@ arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
const char *log_output_names[] = { "NONE", "FILE", "TABLE", NullS};
static const unsigned int log_output_names_len[]= { 4, 4, 5, 0 };
TYPELIB log_output_typelib= {array_elements(log_output_names)-1,"",
- log_output_names,
+ log_output_names,
(unsigned int *) log_output_names_len};
/* static variables */
@@ -357,7 +358,7 @@ static bool volatile ready_to_exit;
static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
static my_bool opt_short_log_format= 0;
static uint kill_cached_threads, wake_thread;
-static ulong killed_threads, thread_created;
+static ulong thread_created;
static ulong max_used_connections;
static ulong my_bind_addr; /**< the address we bind to */
static volatile ulong cached_thread_count= 0;
@@ -368,11 +369,12 @@ static char *default_character_set_name;
static char *character_set_filesystem_name;
static char *lc_time_names_name;
static char *my_bind_addr_str;
-static char *default_collation_name;
+static char *default_collation_name;
static char *default_storage_engine_str;
static char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME;
static I_List<THD> thread_cache;
static double long_query_time;
+static ulong opt_my_crc_dbug_check;
static pthread_cond_t COND_thread_cache, COND_flush_thread_cache;
@@ -395,7 +397,7 @@ bool volatile shutdown_in_progress;
@brief 'grant_option' is used to indicate if privileges needs
to be checked, in which case the lock, LOCK_grant, is used
to protect access to the grant table.
- @note This flag is dropped in 5.1
+ @note This flag is dropped in 5.1
@see grant_init()
*/
bool volatile grant_option;
@@ -407,7 +409,7 @@ my_bool opt_local_infile, opt_slave_compressed_protocol;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0;
-bool slave_warning_issued = false;
+bool slave_warning_issued = false;
/*
Legacy global handlerton. These will be removed (please do not add more).
@@ -589,11 +591,11 @@ pthread_key(MEM_ROOT**,THR_MALLOC);
pthread_key(THD*, THR_THD);
pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_mapped_file, LOCK_status, LOCK_global_read_lock,
- LOCK_error_log, LOCK_uuid_generator,
+ LOCK_error_log,
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
LOCK_global_system_variables,
- LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
+ LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
LOCK_connection_count;
/**
The below lock protects access to two global server variables:
@@ -647,12 +649,11 @@ static char **defaults_argv;
static char *opt_bin_logname;
static my_socket unix_sock,ip_sock;
-struct rand_struct sql_rand; ///< used by sql_class.cc:THD::THD()
+struct my_rnd_struct sql_rand; ///< used by sql_class.cc:THD::THD()
#ifndef EMBEDDED_LIBRARY
struct passwd *user_info;
static pthread_t select_thread;
-static uint thr_kill_signal;
#endif
/* OS specific variables */
@@ -762,6 +763,7 @@ static ulong find_bit_type_or_exit(const char *x, TYPELIB *bit_lib,
const char *option);
static void clean_up(bool print_message);
static int test_if_case_insensitive(const char *dir_name);
+static void register_mutex_order();
#ifndef EMBEDDED_LIBRARY
static void usage(void);
@@ -816,7 +818,7 @@ static void close_connections(void)
break;
}
#ifdef EXTRA_DEBUG
- if (error != 0 && !count++)
+ if (error != 0 && error != ETIMEDOUT && !count++)
sql_print_error("Got error %d from pthread_cond_timedwait",error);
#endif
close_server_sock();
@@ -897,9 +899,19 @@ static void close_connections(void)
pthread_mutex_lock(&tmp->mysys_var->mutex);
if (tmp->mysys_var->current_cond)
{
- pthread_mutex_lock(tmp->mysys_var->current_mutex);
- pthread_cond_broadcast(tmp->mysys_var->current_cond);
- pthread_mutex_unlock(tmp->mysys_var->current_mutex);
+ uint i;
+ for (i=0; i < 2; i++)
+ {
+ int ret= pthread_mutex_trylock(tmp->mysys_var->current_mutex);
+ pthread_cond_broadcast(tmp->mysys_var->current_cond);
+ if (!ret)
+ {
+ /* Thread has surely got the signal, unlock and abort */
+ pthread_mutex_unlock(tmp->mysys_var->current_mutex);
+ break;
+ }
+ sleep(1);
+ }
}
pthread_mutex_unlock(&tmp->mysys_var->mutex);
}
@@ -1084,18 +1096,18 @@ static void __cdecl kill_server(int sig_ptr)
else
sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
-#if defined(HAVE_SMEM) && defined(__WIN__)
- /*
- Send event to smem_event_connect_request for aborting
- */
- if (!SetEvent(smem_event_connect_request))
- {
- DBUG_PRINT("error",
- ("Got error: %ld from SetEvent of smem_event_connect_request",
- GetLastError()));
- }
-#endif
-
+#if defined(HAVE_SMEM) && defined(__WIN__)
+ /*
+ Send event to smem_event_connect_request for aborting
+ */
+ if (!SetEvent(smem_event_connect_request))
+ {
+ DBUG_PRINT("error",
+ ("Got error: %ld from SetEvent of smem_event_connect_request",
+ GetLastError()));
+ }
+#endif
+
close_connections();
if (sig != MYSQL_KILL_SIGNAL &&
sig != 0)
@@ -1237,8 +1249,10 @@ void clean_up(bool print_message)
if (tc_log)
tc_log->close();
xid_cache_free();
+ wt_end();
delete_elements(&key_caches, (void (*)(const char*, uchar*)) free_key_cache);
multi_keycache_free();
+ sp_cache_end();
free_status_vars();
end_thr_alarm(1); /* Free allocated memory */
my_free_open_file_info();
@@ -1295,6 +1309,7 @@ void clean_up(bool print_message)
/* do the broadcast inside the lock to ensure that my_end() is not called */
(void) pthread_cond_broadcast(&COND_thread_count);
(void) pthread_mutex_unlock(&LOCK_thread_count);
+ my_uuid_end();
/*
The following lines may never be executed as the main thread may have
@@ -1330,6 +1345,7 @@ static void wait_for_signal_thread_to_end()
static void clean_up_mutexes()
{
+ DBUG_ENTER("clean_up_mutexes");
(void) pthread_mutex_destroy(&LOCK_mysql_create_db);
(void) pthread_mutex_destroy(&LOCK_lock_db);
(void) pthread_mutex_destroy(&LOCK_Acl);
@@ -1361,13 +1377,15 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_rpl_status);
(void) pthread_cond_destroy(&COND_rpl_status);
#endif
+ (void) pthread_mutex_destroy(&LOCK_server_started);
+ (void) pthread_cond_destroy(&COND_server_started);
(void) pthread_mutex_destroy(&LOCK_active_mi);
(void) rwlock_destroy(&LOCK_sys_init_connect);
(void) rwlock_destroy(&LOCK_sys_init_slave);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
+ (void) pthread_mutex_destroy(&LOCK_uuid_short);
(void) rwlock_destroy(&LOCK_system_variables_hash);
(void) pthread_mutex_destroy(&LOCK_global_read_lock);
- (void) pthread_mutex_destroy(&LOCK_uuid_generator);
(void) pthread_mutex_destroy(&LOCK_prepared_stmt_count);
(void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh);
@@ -1375,11 +1393,35 @@ static void clean_up_mutexes()
(void) pthread_cond_destroy(&COND_thread_cache);
(void) pthread_cond_destroy(&COND_flush_thread_cache);
(void) pthread_cond_destroy(&COND_manager);
+ DBUG_VOID_RETURN;
}
#endif /*EMBEDDED_LIBRARY*/
+/**
+ Register order of mutex for wrong mutex deadlock detector
+
+ By aquiring all mutex in order here, the mutex order detector in
+ mysys/thr_mutex.c, will give a warning on first wrong mutex usage!
+*/
+
+static void register_mutex_order()
+{
+#ifdef SAFE_MUTEX
+ /*
+ We must have LOCK_open before LOCK_global_system_variables because
+ LOCK_open is hold while sql_plugin.c::intern_sys_var_ptr() is called.
+ */
+ pthread_mutex_lock(&LOCK_open);
+ pthread_mutex_lock(&LOCK_global_system_variables);
+
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ pthread_mutex_unlock(&LOCK_open);
+#endif
+}
+
+
/****************************************************************************
** Init IP and UNIX socket
****************************************************************************/
@@ -1631,7 +1673,7 @@ static void network_init(void)
if (Service.IsNT() && mysqld_unix_port[0] && !opt_bootstrap &&
opt_enable_named_pipe)
{
-
+
pipe_name[sizeof(pipe_name)-1]= 0; /* Safety if too long string */
strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\",
mysqld_unix_port, NullS);
@@ -1759,17 +1801,12 @@ void close_connection(THD *thd, uint errcode, bool lock)
#endif /* EMBEDDED_LIBRARY */
-/** Called when a thread is aborted. */
+/** Called when mysqld is aborted with ^C */
/* ARGSUSED */
-extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
+extern "C" sig_handler end_mysqld_signal(int sig __attribute__((unused)))
{
- THD *thd=current_thd;
- DBUG_ENTER("end_thread_signal");
- if (thd && ! thd->bootstrap)
- {
- statistic_increment(killed_threads, &LOCK_status);
- thread_scheduler.end_thread(thd,0); /* purecov: inspected */
- }
+ DBUG_ENTER("end_mysqld_signal");
+ kill_mysql(); // Take down mysqld nicely
DBUG_VOID_RETURN; /* purecov: deadcode */
}
@@ -1877,6 +1914,8 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
{
DBUG_ENTER("one_thread_per_connection_end");
unlink_thd(thd);
+ /* Mark that current_thd is not valid anymore */
+ my_pthread_setspecific_ptr(THR_THD, 0);
if (put_in_cache)
put_in_cache= cache_thread();
pthread_mutex_unlock(&LOCK_thread_count);
@@ -2176,7 +2215,7 @@ static void registerwithneb()
{
ConsumerRegistrationInfo reg_info;
-
+
/* Clear NEB registration structure */
bzero((char*) &reg_info, sizeof(struct ConsumerRegistrationInfo));
@@ -2192,7 +2231,7 @@ static void registerwithneb()
reg_info.CRIOwnerID= (LoadDefinitionStructure *)getnlmhandle();
reg_info.CRIConsumerESR= NULL; // No consumer ESR required
reg_info.CRISecurityToken= 0; // No security token for the event
- reg_info.CRIConsumerFlags= 0; // SMP_ENABLED_BIT;
+ reg_info.CRIConsumerFlags= 0; // SMP_ENABLED_BIT;
reg_info.CRIFilterName= 0; // No event filtering
reg_info.CRIFilterDataLength= 0; // No filtering data
reg_info.CRIFilterData= 0; // No filtering data
@@ -2217,7 +2256,7 @@ static void registerwithneb()
Get the NSS volume ID of the MySQL Data volume.
Volume ID is stored in a global variable
*/
- getvolumeID((BYTE*) datavolname);
+ getvolumeID((BYTE*) datavolname);
}
@@ -2281,7 +2320,7 @@ static void getvolumeID(BYTE *volumeName)
strxmov(path, (const char *) ADMIN_VOL_PATH, (const char *) volumeName,
NullS);
- if ((status= zOpen(rootKey, zNSS_TASK, zNSPACE_LONG|zMODE_UTF8,
+ if ((status= zOpen(rootKey, zNSS_TASK, zNSPACE_LONG|zMODE_UTF8,
(BYTE *) path, zRR_READ_ACCESS, &fileKey)) != zOK)
{
consoleprintf("\nGetNSSVolumeProperties - Failed to get file, status: %d\n.", (int) status);
@@ -2289,7 +2328,7 @@ static void getvolumeID(BYTE *volumeName)
}
getInfoMask= zGET_IDS | zGET_VOLUME_INFO ;
- if ((status= zGetInfo(fileKey, getInfoMask, sizeof(info),
+ if ((status= zGetInfo(fileKey, getInfoMask, sizeof(info),
zINFO_VERSION_A, &info)) != zOK)
{
consoleprintf("\nGetNSSVolumeProperties - Failed in zGetInfo, status: %d\n.", (int) status);
@@ -2485,7 +2524,7 @@ You should either build a dynamically-linked binary, or force LinuxThreads\n\
to be used with the LD_ASSUME_KERNEL environment variable. Please consult\n\
the documentation for your distribution on how to do that.\n");
#endif
-
+
if (locked_in_memory)
{
fprintf(stderr, "\n\
@@ -2587,12 +2626,13 @@ static void init_signals(void)
sigaddset(&set,THR_SERVER_ALARM);
if (test_flags & TEST_SIGINT)
{
- my_sigset(thr_kill_signal, end_thread_signal);
- // May be SIGINT
- sigdelset(&set, thr_kill_signal);
+ /* Allow SIGINT to break mysqld. This is for debugging with --gdb */
+ my_sigset(SIGINT, end_mysqld_signal);
+ sigdelset(&set, SIGINT);
}
else
sigaddset(&set,SIGINT);
+
sigprocmask(SIG_SETMASK,&set,NULL);
pthread_sigmask(SIG_SETMASK,&set,NULL);
DBUG_VOID_RETURN;
@@ -2654,10 +2694,11 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
*/
init_thr_alarm(thread_scheduler.max_threads +
global_system_variables.max_insert_delayed_threads + 10);
- if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT))
+ if (test_flags & TEST_SIGINT)
{
- (void) sigemptyset(&set); // Setup up SIGINT for debug
- (void) sigaddset(&set,SIGINT); // For debugging
+ /* Allow SIGINT to break mysqld. This is for debugging with --gdb */
+ (void) sigemptyset(&set);
+ (void) sigaddset(&set,SIGINT);
(void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
}
(void) sigemptyset(&set); // Setup up SIGINT for debug
@@ -2795,6 +2836,8 @@ extern "C" int my_message_sql(uint error, const char *str, myf MyFlags);
int my_message_sql(uint error, const char *str, myf MyFlags)
{
THD *thd;
+ MYSQL_ERROR::enum_warning_level level;
+ sql_print_message_func func;
DBUG_ENTER("my_message_sql");
DBUG_PRINT("error", ("error: %u message: '%s'", error, str));
@@ -2808,24 +2851,44 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
TODO:
DBUG_ASSERT(error != 0);
*/
-
if (error == 0)
{
/* At least, prevent new abuse ... */
- DBUG_ASSERT(strncmp(str, "MyISAM table", 12) == 0);
+ DBUG_ASSERT(strncmp(str, "MyISAM table", 12) == 0 ||
+ strncmp(str, "MARIA table", 11) == 0);
error= ER_UNKNOWN_ERROR;
}
+ if (MyFlags & ME_JUST_INFO)
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_NOTE;
+ func= sql_print_information;
+ }
+ else if (MyFlags & ME_JUST_WARNING)
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_WARN;
+ func= sql_print_warning;
+ }
+ else
+ {
+ level= MYSQL_ERROR::WARN_LEVEL_ERROR;
+ func= sql_print_error;
+ }
+
if ((thd= current_thd))
{
/*
TODO: There are two exceptions mechanism (THD and sp_rcontext),
this could be improved by having a common stack of handlers.
*/
- if (thd->handle_error(error, str,
- MYSQL_ERROR::WARN_LEVEL_ERROR))
+ if (thd->handle_error(error, str, level))
DBUG_RETURN(0);
+ if (level == MYSQL_ERROR::WARN_LEVEL_WARN)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error, str);
+ if (level != MYSQL_ERROR::WARN_LEVEL_ERROR)
+ goto to_error_log;
+
thd->is_slave_error= 1; // needed to catch query errors during replication
/*
@@ -2877,8 +2940,9 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
thd->no_warnings_for_error= FALSE;
}
}
- if (!thd || MyFlags & ME_NOREFRESH)
- sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
+to_error_log:
+ if (!thd || (MyFlags & ME_NOREFRESH))
+ (*func)("%s: %s", my_progname_short, str); /* purecov: inspected */
DBUG_RETURN(0);
}
@@ -3355,7 +3419,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
global_system_variables.character_set_results= default_charset_info;
global_system_variables.character_set_client= default_charset_info;
- if (!(character_set_filesystem=
+ if (!(character_set_filesystem=
get_charset_by_csname(character_set_filesystem_name,
MY_CS_PRIMARY, MYF(MY_WME))))
return 1;
@@ -3368,7 +3432,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
return 1;
}
global_system_variables.lc_time_names= my_default_lc_time_names;
-
+
sys_init_connect.value_length= 0;
if ((sys_init_connect.value= opt_init_connect))
sys_init_connect.value_length= strlen(opt_init_connect);
@@ -3384,23 +3448,23 @@ static int init_common_variables(const char *conf_file_name, int argc,
sys_init_slave.is_os_charset= TRUE;
/* check log options and issue warnings if needed */
- if (opt_log && opt_logname && !(log_output_options & LOG_FILE) &&
- !(log_output_options & LOG_NONE))
+ if (opt_log && opt_logname && *opt_logname &&
+ !(log_output_options & (LOG_FILE | LOG_NONE)))
sql_print_warning("Although a path was specified for the "
"--log option, log tables are used. "
"To enable logging to files use the --log-output option.");
- if (opt_slow_log && opt_slow_logname && !(log_output_options & LOG_FILE)
- && !(log_output_options & LOG_NONE))
+ if (opt_slow_log && opt_slow_logname && *opt_slow_logname &&
+ !(log_output_options & (LOG_FILE | LOG_NONE)))
sql_print_warning("Although a path was specified for the "
"--log_slow_queries option, log tables are used. "
"To enable logging to files use the --log-output=file option.");
- s= opt_logname ? opt_logname : make_default_log_name(buff, ".log");
+ s= opt_logname && *opt_logname ? opt_logname : make_default_log_name(buff, ".log");
sys_var_general_log_path.value= my_strdup(s, MYF(0));
sys_var_general_log_path.value_length= strlen(s);
- s= opt_slow_logname ? opt_slow_logname : make_default_log_name(buff, "-slow.log");
+ s= opt_slow_logname && *opt_slow_logname ? opt_slow_logname : make_default_log_name(buff, "-slow.log");
sys_var_slow_log_path.value= my_strdup(s, MYF(0));
sys_var_slow_log_path.value_length= strlen(s);
@@ -3489,7 +3553,7 @@ static int init_thread_environment()
(void) my_rwlock_init(&LOCK_system_variables_hash, NULL);
(void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_uuid_short, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_connection_count, MY_MUTEX_INIT_FAST);
#ifdef HAVE_OPENSSL
(void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
@@ -3497,7 +3561,7 @@ static int init_thread_environment()
openssl_stdlocks= (openssl_lock_t*) OPENSSL_malloc(CRYPTO_num_locks() *
sizeof(openssl_lock_t));
for (int i= 0; i < CRYPTO_num_locks(); ++i)
- (void) my_rwlock_init(&openssl_stdlocks[i].lock, NULL);
+ (void) my_rwlock_init(&openssl_stdlocks[i].lock, NULL);
CRYPTO_set_dynlock_create_callback(openssl_dynlock_create);
CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy);
CRYPTO_set_dynlock_lock_callback(openssl_lock);
@@ -3538,26 +3602,27 @@ static int init_thread_environment()
sql_print_error("Can't create thread-keys");
return 1;
}
+ register_mutex_order();
return 0;
}
#if defined(HAVE_OPENSSL) && !defined(HAVE_YASSL)
static unsigned long openssl_id_function()
-{
+{
return (unsigned long) pthread_self();
-}
+}
static openssl_lock_t *openssl_dynlock_create(const char *file, int line)
-{
+{
openssl_lock_t *lock= new openssl_lock_t;
my_rwlock_init(&lock->lock, NULL);
return lock;
}
-static void openssl_dynlock_destroy(openssl_lock_t *lock, const char *file,
+static void openssl_dynlock_destroy(openssl_lock_t *lock, const char *file,
int line)
{
rwlock_destroy(&lock->lock);
@@ -3577,7 +3642,7 @@ static void openssl_lock_function(int mode, int n, const char *file, int line)
}
-static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
+static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
int line)
{
int err;
@@ -3602,7 +3667,7 @@ static void openssl_lock(int mode, openssl_lock_t *lock, const char *file,
sql_print_error("Fatal: OpenSSL interface problem (mode=0x%x)", mode);
abort();
}
- if (err)
+ if (err)
{
sql_print_error("Fatal: can't %s OpenSSL lock", what);
abort();
@@ -3668,12 +3733,14 @@ static int init_server_components()
query_cache_set_min_res_unit(query_cache_min_res_unit);
query_cache_init();
query_cache_resize(query_cache_size);
- randominit(&sql_rand,(ulong) server_start_time,(ulong) server_start_time/2);
+ my_rnd_init(&sql_rand,(ulong) server_start_time,(ulong) server_start_time/2);
set_proper_floating_point_mode();
init_thr_lock();
+ my_uuid_init((ulong) (my_rnd(&sql_rand))*12345,12345);
#ifdef HAVE_REPLICATION
init_slave_list();
#endif
+ wt_init();
/* Setup logs */
@@ -3701,6 +3768,12 @@ static int init_server_components()
}
}
+ /* set up the hook before initializing plugins which may use it */
+ error_handler_hook= my_message_sql;
+ proc_info_hook= (const char *(*)(void *, const char *, const char *,
+ const char *, const unsigned int))
+ set_thd_proc_info;
+
if (xid_cache_init())
{
sql_print_error("Out of memory");
@@ -3786,7 +3859,7 @@ with --log-bin instead.");
if (opt_binlog_format_id == BINLOG_FORMAT_UNSPEC)
global_system_variables.binlog_format= BINLOG_FORMAT_STMT;
else
- {
+ {
DBUG_ASSERT(global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC);
}
@@ -3943,7 +4016,7 @@ server.");
strlen(default_storage_engine_str) };
plugin_ref plugin;
handlerton *hton;
-
+
if ((plugin= ha_resolve_by_name(0, &name)))
hton= plugin_data(plugin, handlerton*);
else
@@ -3965,13 +4038,20 @@ server.");
else
{
/*
- Need to unlock as global_system_variables.table_plugin
+ Need to unlock as global_system_variables.table_plugin
was acquired during plugin_init()
*/
plugin_unlock(0, global_system_variables.table_plugin);
global_system_variables.table_plugin= plugin;
}
}
+#if defined(WITH_MARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES)
+ if (!ha_storage_engine_is_enabled(maria_hton) && !opt_bootstrap)
+ {
+ sql_print_error("Maria engine is not enabled or did not start. The Maria engine must be enabled to continue as mysqld was configured with --with-maria-tmp-tables");
+ unireg_abort(1);
+ }
+#endif
tc_log= (total_ha_2pc > 1 ? (opt_bin_log ?
(TC_LOG *) &mysql_bin_log :
@@ -4107,7 +4187,7 @@ static void handle_connections_methods()
handler_count--;
}
}
-#endif
+#endif
while (handler_count > 0)
pthread_cond_wait(&COND_handler_count,&LOCK_thread_count);
@@ -4120,7 +4200,7 @@ void decrement_handler_count()
pthread_mutex_lock(&LOCK_thread_count);
handler_count--;
pthread_cond_signal(&COND_handler_count);
- pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_mutex_unlock(&LOCK_thread_count);
my_thread_end();
}
#else
@@ -4176,13 +4256,6 @@ int main(int argc, char **argv)
MY_INIT(argv[0]); // init my_sys library & pthreads
/* nothing should come before this line ^^^ */
- /* Set signal used to kill MySQL */
-#if defined(SIGUSR2)
- thr_kill_signal= thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2;
-#else
- thr_kill_signal= SIGINT;
-#endif
-
/*
Perform basic logger initialization logger. Should be called after
MY_INIT, as it initializes mutexes. Log tables are inited later.
@@ -4336,7 +4409,6 @@ we force server id to 2, but this MySQL server will not act as a slave.");
init signals & alarm
After this we can't quit by a simple unireg_abort
*/
- error_handler_hook= my_message_sql;
start_signal_handler(); // Creates pidfile
if (mysql_rm_tmp_tables() || acl_init(opt_noacl) ||
@@ -4431,7 +4503,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
#endif /* __NT__ */
/* (void) pthread_attr_destroy(&connection_attrib); */
-
+
DBUG_PRINT("quit",("Exiting main thread"));
#ifndef __WIN__
@@ -4733,7 +4805,7 @@ static bool read_init_file(char *file_name)
When we enter this function, LOCK_thread_count is hold!
*/
-
+
void handle_connection_in_main_thread(THD *thd)
{
safe_mutex_assert_owner(&LOCK_thread_count);
@@ -4974,7 +5046,7 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused)))
size_socket length=sizeof(struct sockaddr_in);
new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr),
&length);
-#ifdef __NETWARE__
+#ifdef __NETWARE__
// TODO: temporary fix, waiting for TCP/IP fix - DEFECT000303149
if ((new_sock == INVALID_SOCKET) && (socket_errno == EINVAL))
{
@@ -5378,7 +5450,7 @@ errorconn:
NullS);
sql_perror(buff);
}
- if (handle_client_file_map)
+ if (handle_client_file_map)
CloseHandle(handle_client_file_map);
if (handle_client_map)
UnmapViewOfFile(handle_client_map);
@@ -5426,8 +5498,8 @@ error:
enum options_mysqld
{
- OPT_ISAM_LOG=256, OPT_SKIP_NEW,
- OPT_SKIP_GRANT, OPT_SKIP_LOCK,
+ OPT_ISAM_LOG=256, OPT_SKIP_NEW,
+ OPT_SKIP_GRANT, OPT_SKIP_LOCK,
OPT_ENABLE_LOCK, OPT_USE_LOCKING,
OPT_SOCKET, OPT_UPDATE_LOG,
OPT_BIN_LOG, OPT_SKIP_RESOLVE,
@@ -5456,18 +5528,18 @@ enum options_mysqld
#ifndef DBUG_OFF
OPT_BINLOG_SHOW_XID,
#endif
- OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
+ OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
OPT_WANT_CORE, OPT_CONCURRENT_INSERT,
OPT_MEMLOCK, OPT_MYISAM_RECOVER,
OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID,
- OPT_SKIP_SLAVE_START, OPT_SAFE_SHOW_DB,
+ OPT_SKIP_SLAVE_START, OPT_SAFE_SHOW_DB,
OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
OPT_REPLICATE_WILD_IGNORE_TABLE, OPT_REPLICATE_SAME_SERVER_ID,
OPT_DISCONNECT_SLAVE_EVENT_COUNT, OPT_TC_HEURISTIC_RECOVER,
OPT_ABORT_SLAVE_EVENT_COUNT,
OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
- OPT_ENGINE_CONDITION_PUSHDOWN, OPT_NDB_CONNECTSTRING,
+ OPT_ENGINE_CONDITION_PUSHDOWN, OPT_NDB_CONNECTSTRING,
OPT_NDB_USE_EXACT_COUNT, OPT_NDB_USE_TRANSACTIONS,
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME,
@@ -5478,7 +5550,7 @@ enum options_mysqld
OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP,
OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE,
OPT_NDB_USE_COPYING_ALTER_TABLE,
- OPT_SKIP_SAFEMALLOC,
+ OPT_SKIP_SAFEMALLOC, OPT_MUTEX_DEADLOCK_DETECTOR,
OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
@@ -5512,10 +5584,15 @@ enum options_mysqld
OPT_MAX_LENGTH_FOR_SORT_DATA,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
+
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
OPT_MYISAM_USE_MMAP, OPT_MYISAM_REPAIR_THREADS,
OPT_MYISAM_STATS_METHOD,
+
+ OPT_PAGECACHE_BUFFER_SIZE,
+ OPT_PAGECACHE_DIVISION_LIMIT, OPT_PAGECACHE_AGE_THRESHOLD,
+
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT,
OPT_OPEN_FILES_LIMIT,
@@ -5582,8 +5659,12 @@ enum options_mysqld
OPT_SECURE_FILE_PRIV,
OPT_MIN_EXAMINED_ROW_LIMIT,
OPT_LOG_SLOW_SLAVE_STATEMENTS,
- OPT_OLD_MODE,
+ OPT_DEBUG_CRC, OPT_DEBUG_ON, OPT_OLD_MODE,
OPT_SLAVE_EXEC_MODE,
+ OPT_DEADLOCK_SEARCH_DEPTH_SHORT,
+ OPT_DEADLOCK_SEARCH_DEPTH_LONG,
+ OPT_DEADLOCK_TIMEOUT_SHORT,
+ OPT_DEADLOCK_TIMEOUT_LONG,
OPT_GENERAL_LOG_FILE,
OPT_SLOW_QUERY_LOG_FILE
};
@@ -5593,7 +5674,7 @@ enum options_mysqld
struct my_option my_long_options[] =
{
- {"help", '?', "Display this help and exit.",
+ {"help", '?', "Display this help and exit.",
(uchar**) &opt_help, (uchar**) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
#ifdef HAVE_REPLICATION
@@ -5659,11 +5740,12 @@ struct my_option my_long_options[] =
"The maximum size of a row-based binary log event in bytes. Rows will be "
"grouped into events smaller than this size if possible. "
"The value has to be a multiple of 256.",
- (uchar**) &opt_binlog_rows_event_max_size,
- (uchar**) &opt_binlog_rows_event_max_size, 0,
- GET_ULONG, REQUIRED_ARG,
- /* def_value */ 1024, /* min_value */ 256, /* max_value */ ULONG_MAX,
- /* sub_size */ 0, /* block_size */ 256,
+ (uchar**) &opt_binlog_rows_event_max_size,
+ (uchar**) &opt_binlog_rows_event_max_size, 0,
+ GET_ULONG, REQUIRED_ARG,
+ /* def_value */ 1024, /* min_value */ 256,
+ /* max_value */ (longlong) ULONG_MAX,
+ /* sub_size */ 0, /* block_size */ 256,
/* app_type */ 0
},
#ifndef DISABLE_GRANT_OPTIONS
@@ -5707,9 +5789,33 @@ struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
{"datadir", 'h', "Path to the database root.", (uchar**) &mysql_data_home,
(uchar**) &mysql_data_home, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"deadlock-search-depth-short", OPT_DEADLOCK_SEARCH_DEPTH_SHORT,
+ "Short search depth for the two-step deadlock detection",
+ (uchar**) &global_system_variables.wt_deadlock_search_depth_short,
+ (uchar**) &max_system_variables.wt_deadlock_search_depth_short,
+ 0, GET_ULONG, REQUIRED_ARG, 4, 0, 32, 0, 0, 0},
+ {"deadlock-search-depth-long", OPT_DEADLOCK_SEARCH_DEPTH_LONG,
+ "Long search depth for the two-step deadlock detection",
+ (uchar**) &global_system_variables.wt_deadlock_search_depth_long,
+ (uchar**) &max_system_variables.wt_deadlock_search_depth_long,
+ 0, GET_ULONG, REQUIRED_ARG, 15, 0, 33, 0, 0, 0},
+ {"deadlock-timeout-short", OPT_DEADLOCK_TIMEOUT_SHORT,
+ "Short timeout for the two-step deadlock detection (in microseconds)",
+ (uchar**) &global_system_variables.wt_timeout_short,
+ (uchar**) &max_system_variables.wt_timeout_short,
+ 0, GET_ULONG, REQUIRED_ARG, 10000, 0, ULONG_MAX, 0, 0, 0},
+ {"deadlock-timeout-long", OPT_DEADLOCK_TIMEOUT_LONG,
+ "Long timeout for the two-step deadlock detection (in microseconds)",
+ (uchar**) &global_system_variables.wt_timeout_long,
+ (uchar**) &max_system_variables.wt_timeout_long,
+ 0, GET_ULONG, REQUIRED_ARG, 50000000, 0, ULONG_MAX, 0, 0, 0},
#ifndef DBUG_OFF
{"debug", '#', "Debug log.", (uchar**) &default_dbug_option,
(uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug-crc-break", OPT_DEBUG_CRC,
+ "Call my_debug_put_break_here() if crc matches this number (for debug).",
+ (uchar**) &opt_my_crc_dbug_check, (uchar**) &opt_my_crc_dbug_check,
+ 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~(ulong) 0L, 0, 0, 0},
#endif
{"default-character-set", 'C', "Set the default character set (deprecated option, use --character-set-server instead).",
(uchar**) &default_character_set_name, (uchar**) &default_character_set_name,
@@ -5866,7 +5972,7 @@ Disable with --skip-large-pages.",
(uchar**) &myisam_log_filename, (uchar**) &myisam_log_filename, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-long-format", '0',
- "Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.",
+ "Log some extra information to update log. Please note that this option is deprecated; see --log-short-format option.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef WITH_CSV_STORAGE_ENGINE
{"log-output", OPT_LOG_OUTPUT,
@@ -5916,7 +6022,7 @@ Disable with --skip-large-pages.",
#ifdef HAVE_MMAP
{"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.",
(uchar**) &opt_tc_log_size, (uchar**) &opt_tc_log_size, 0, GET_ULONG,
- REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ULONG_MAX, 0,
+ REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, (longlong) ULONG_MAX, 0,
TC_LOG_PAGE_SIZE, 0},
#endif
{"log-update", OPT_UPDATE_LOG,
@@ -5995,6 +6101,13 @@ master-ssl",
#endif /* HAVE_REPLICATION */
{"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", (uchar**) &locked_in_memory,
(uchar**) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef SAFE_MUTEX
+ {"mutex-deadlock-detector", OPT_MUTEX_DEADLOCK_DETECTOR,
+ "Enable checking of wrong mutex usage.",
+ (uchar**) &safe_mutex_deadlock_detector,
+ (uchar**) &safe_mutex_deadlock_detector,
+ 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+#endif
{"myisam-recover", OPT_MYISAM_RECOVER,
"Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
(uchar**) &myisam_recover_options_str, (uchar**) &myisam_recover_options_str, 0,
@@ -6101,7 +6214,7 @@ master-ssl",
"Force ndbcluster to always copy tables at alter table (should only be used if on-line alter table fails).",
(uchar**) &global_system_variables.ndb_use_copying_alter_table,
(uchar**) &global_system_variables.ndb_use_copying_alter_table,
- 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"new", 'n', "Use very new possible 'unsafe' functions.",
(uchar**) &global_system_variables.new_mode,
(uchar**) &max_system_variables.new_mode,
@@ -6360,7 +6473,7 @@ log and this option does nothing anymore.",
{"timed_mutexes", OPT_TIMED_MUTEXES,
"Specify whether to time mutexes (only InnoDB mutexes are currently supported)",
- (uchar**) &timed_mutexes, (uchar**) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0,
+ (uchar**) &timed_mutexes, (uchar**) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0,
0, 0, 0, 0, 0},
{"tmpdir", 't',
"Path for temporary files. Several paths may be specified, separated by a "
@@ -6388,7 +6501,7 @@ log and this option does nothing anymore.",
{"warnings", 'W', "Deprecated; use --log-warnings instead.",
(uchar**) &global_system_variables.log_warnings,
(uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG,
- 1, 0, ULONG_MAX, 0, 0, 0},
+ 1, 0, (longlong) ULONG_MAX, 0, 0, 0},
{ "back_log", OPT_BACK_LOG,
"The number of outstanding connection requests MySQL can have. This comes into play when the main MySQL thread gets very many connection requests in a very short time.",
(uchar**) &back_log, (uchar**) &back_log, 0, GET_ULONG,
@@ -6396,12 +6509,12 @@ log and this option does nothing anymore.",
{"binlog_cache_size", OPT_BINLOG_CACHE_SIZE,
"The size of the cache to hold the SQL statements for the binary log during a transaction. If you often use big, multi-statement transactions you can increase this to get more performance.",
(uchar**) &binlog_cache_size, (uchar**) &binlog_cache_size, 0, GET_ULONG,
- REQUIRED_ARG, 32*1024L, IO_SIZE, ULONG_MAX, 0, IO_SIZE, 0},
+ REQUIRED_ARG, 32*1024L, IO_SIZE, (longlong) ULONG_MAX, 0, IO_SIZE, 0},
{"bulk_insert_buffer_size", OPT_BULK_INSERT_BUFFER_SIZE,
"Size of tree cache used in bulk insert optimisation. Note that this is a limit per thread!",
(uchar**) &global_system_variables.bulk_insert_buff_size,
(uchar**) &max_system_variables.bulk_insert_buff_size,
- 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 0, ULONG_MAX, 0, 1, 0},
+ 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 0, (longlong) ULONG_MAX, 0, 1, 0},
{"connect_timeout", OPT_CONNECT_TIMEOUT,
"The number of seconds the mysqld server is waiting for a connect packet before responding with 'Bad handshake'.",
(uchar**) &connect_timeout, (uchar**) &connect_timeout,
@@ -6424,7 +6537,7 @@ log and this option does nothing anymore.",
{"delayed_insert_limit", OPT_DELAYED_INSERT_LIMIT,
"After inserting delayed_insert_limit rows, the INSERT DELAYED handler will check if there are any SELECT statements pending. If so, it allows these to execute before continuing.",
(uchar**) &delayed_insert_limit, (uchar**) &delayed_insert_limit, 0, GET_ULONG,
- REQUIRED_ARG, DELAYED_LIMIT, 1, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, DELAYED_LIMIT, 1, (longlong) ULONG_MAX, 0, 1, 0},
{"delayed_insert_timeout", OPT_DELAYED_INSERT_TIMEOUT,
"How long a INSERT DELAYED thread should wait for INSERT statements before terminating.",
(uchar**) &delayed_insert_timeout, (uchar**) &delayed_insert_timeout, 0,
@@ -6432,7 +6545,7 @@ log and this option does nothing anymore.",
{ "delayed_queue_size", OPT_DELAYED_QUEUE_SIZE,
"What size queue (in rows) should be allocated for handling INSERT DELAYED. If the queue becomes full, any client that does INSERT DELAYED will wait until there is room in the queue again.",
(uchar**) &delayed_queue_size, (uchar**) &delayed_queue_size, 0, GET_ULONG,
- REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, (longlong) ULONG_MAX, 0, 1, 0},
{"div_precision_increment", OPT_DIV_PRECINCREMENT,
"Precision of the result of '/' operator will be increased on that value.",
(uchar**) &global_system_variables.div_precincrement,
@@ -6472,7 +6585,7 @@ log and this option does nothing anymore.",
"The maximum length of the result of function group_concat.",
(uchar**) &global_system_variables.group_concat_max_len,
(uchar**) &max_system_variables.group_concat_max_len, 0, GET_ULONG,
- REQUIRED_ARG, 1024, 4, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, 1024, 4, (longlong) ULONG_MAX, 0, 1, 0},
{"interactive_timeout", OPT_INTERACTIVE_TIMEOUT,
"The number of seconds the server waits for activity on an interactive connection before closing it.",
(uchar**) &global_system_variables.net_interactive_timeout,
@@ -6482,7 +6595,7 @@ log and this option does nothing anymore.",
"The size of the buffer that is used for full joins.",
(uchar**) &global_system_variables.join_buff_size,
(uchar**) &max_system_variables.join_buff_size, 0, GET_ULONG,
- REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ULONG_MAX,
+ REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, (longlong) ULONG_MAX,
MALLOC_OVERHEAD, IO_SIZE, 0},
{"keep_files_on_create", OPT_KEEP_FILES_ON_CREATE,
"Don't overwrite stale .MYD and .MYI even if no directory is specified.",
@@ -6500,8 +6613,8 @@ log and this option does nothing anymore.",
"This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache",
(uchar**) &dflt_key_cache_var.param_age_threshold,
(uchar**) 0,
- 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG,
- 300, 100, ULONG_MAX, 0, 100, 0},
+ 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG,
+ 300, 100, (longlong) ULONG_MAX, 0, 100, 0},
{"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE,
"The default size of key cache blocks",
(uchar**) &dflt_key_cache_var.param_block_size,
@@ -6533,11 +6646,12 @@ log and this option does nothing anymore.",
"Max packetlength to send/receive from to server.",
(uchar**) &global_system_variables.max_allowed_packet,
(uchar**) &max_system_variables.max_allowed_packet, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
+ REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, 0, 1024, 0},
{"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE,
"Can be used to restrict the total size used to cache a multi-transaction query.",
(uchar**) &max_binlog_cache_size, (uchar**) &max_binlog_cache_size, 0,
- GET_ULONG, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONG_MAX, 0, IO_SIZE, 0},
+ GET_ULONG, REQUIRED_ARG, (longlong) ULONG_MAX, IO_SIZE,
+ (longlong) ULONG_MAX, 0, IO_SIZE, 0},
{"max_binlog_size", OPT_MAX_BINLOG_SIZE,
"Binary log will be rotated automatically when the size exceeds this \
value. Will also apply to relay logs if max_relay_log_size is 0. \
@@ -6547,7 +6661,7 @@ The minimum value for this variable is 4096.",
{"max_connect_errors", OPT_MAX_CONNECT_ERRORS,
"If there is more than this number of interrupted connections from a host this host will be blocked from further connections.",
(uchar**) &max_connect_errors, (uchar**) &max_connect_errors, 0, GET_ULONG,
- REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, (longlong) ULONG_MAX, 0, 1, 0},
// Default max_connections of 151 is larger than Apache's default max
// children, to avoid "too many connections" error in a common setup
{"max_connections", OPT_MAX_CONNECTIONS,
@@ -6574,7 +6688,7 @@ The minimum value for this variable is 4096.",
"Joins that are probably going to read more than max_join_size records return an error.",
(uchar**) &global_system_variables.max_join_size,
(uchar**) &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG,
- ~0L, 1, ~0L, 0, 1, 0},
+ HA_POS_ERROR, 1, HA_POS_ERROR, 0, 1, 0},
{"max_length_for_sort_data", OPT_MAX_LENGTH_FOR_SORT_DATA,
"Max number of bytes in sorted records.",
(uchar**) &global_system_variables.max_length_for_sort_data,
@@ -6592,7 +6706,7 @@ The minimum value for this variable is 4096.",
"Limit assumed max number of seeks when looking up rows based on a key",
(uchar**) &global_system_variables.max_seeks_for_key,
(uchar**) &max_system_variables.max_seeks_for_key, 0, GET_ULONG,
- REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 },
+ REQUIRED_ARG, (longlong) ULONG_MAX, 1, (longlong) ULONG_MAX, 0, 1, 0 },
{"max_sort_length", OPT_MAX_SORT_LENGTH,
"The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).",
(uchar**) &global_system_variables.max_sort_length,
@@ -6607,7 +6721,7 @@ The minimum value for this variable is 4096.",
"Maximum number of temporary tables a client can keep open at a time.",
(uchar**) &global_system_variables.max_tmp_tables,
(uchar**) &max_system_variables.max_tmp_tables, 0, GET_ULONG,
- REQUIRED_ARG, 32, 1, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, 32, 1, (longlong) ULONG_MAX, 0, 1, 0},
{"max_user_connections", OPT_MAX_USER_CONNECTIONS,
"The maximum number of active connections for a single user (0 = no limit).",
(uchar**) &max_user_connections, (uchar**) &max_user_connections, 0, GET_UINT,
@@ -6615,17 +6729,17 @@ The minimum value for this variable is 4096.",
{"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT,
"After this many write locks, allow some read locks to run in between.",
(uchar**) &max_write_lock_count, (uchar**) &max_write_lock_count, 0, GET_ULONG,
- REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, (longlong) ULONG_MAX, 1, (longlong) ULONG_MAX, 0, 1, 0},
{"min_examined_row_limit", OPT_MIN_EXAMINED_ROW_LIMIT,
"Don't log queries which examine less than min_examined_row_limit rows to file.",
(uchar**) &global_system_variables.min_examined_row_limit,
(uchar**) &max_system_variables.min_examined_row_limit, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1L, 0},
+ REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1L, 0},
{"multi_range_count", OPT_MULTI_RANGE_COUNT,
"Number of key ranges to request at once.",
(uchar**) &global_system_variables.multi_range_count,
(uchar**) &max_system_variables.multi_range_count, 0,
- GET_ULONG, REQUIRED_ARG, 256, 1, ULONG_MAX, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, 256, 1, (longlong) ULONG_MAX, 0, 1, 0},
{"myisam_block_size", OPT_MYISAM_BLOCK_SIZE,
"Block size to be used for MyISAM index pages.",
(uchar**) &opt_myisam_block_size,
@@ -6637,12 +6751,6 @@ The minimum value for this variable is 4096.",
(uchar**) &myisam_data_pointer_size,
(uchar**) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG,
6, 2, 7, 0, 1, 0},
- {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
- "Deprecated option",
- (uchar**) &global_system_variables.myisam_max_extra_sort_file_size,
- (uchar**) &max_system_variables.myisam_max_extra_sort_file_size,
- 0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH,
- 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0},
{"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE,
"Don't use the fast sort index method to created index if the temporary file would get bigger than this.",
(uchar**) &global_system_variables.myisam_max_sort_file_size,
@@ -6653,16 +6761,16 @@ The minimum value for this variable is 4096.",
"Number of threads to use when repairing MyISAM tables. The value of 1 disables parallel repair.",
(uchar**) &global_system_variables.myisam_repair_threads,
(uchar**) &max_system_variables.myisam_repair_threads, 0,
- GET_ULONG, REQUIRED_ARG, 1, 1, ULONG_MAX, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, 1, 1, (longlong) ULONG_MAX, 0, 1, 0},
{"myisam_sort_buffer_size", OPT_MYISAM_SORT_BUFFER_SIZE,
"The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.",
(uchar**) &global_system_variables.myisam_sort_buff_size,
(uchar**) &max_system_variables.myisam_sort_buff_size, 0,
- GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, 8192*1024, 4, (longlong) ULONG_MAX, 0, 1, 0},
{"myisam_use_mmap", OPT_MYISAM_USE_MMAP,
"Use memory mapping for reading and writing MyISAM tables",
(uchar**) &opt_myisam_use_mmap,
- (uchar**) &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, 0,
+ (uchar**) &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, 0,
0, 0, 0, 0, 0},
{"myisam_stats_method", OPT_MYISAM_STATS_METHOD,
"Specifies how MyISAM index statistics collection code should threat NULLs. "
@@ -6684,15 +6792,16 @@ The minimum value for this variable is 4096.",
"If a read on a communication port is interrupted, retry this many times before giving up.",
(uchar**) &global_system_variables.net_retry_count,
(uchar**) &max_system_variables.net_retry_count,0,
- GET_ULONG, REQUIRED_ARG, MYSQLD_NET_RETRY_COUNT, 1, ULONG_MAX, 0, 1, 0},
+ GET_ULONG, REQUIRED_ARG, MYSQLD_NET_RETRY_COUNT, 1, (longlong) ULONG_MAX,
+ 0, 1, 0},
{"net_write_timeout", OPT_NET_WRITE_TIMEOUT,
"Number of seconds to wait for a block to be written to a connection before aborting the write.",
(uchar**) &global_system_variables.net_write_timeout,
(uchar**) &max_system_variables.net_write_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
- { "old", OPT_OLD_MODE, "Use compatible behavior.",
+ {"old", OPT_OLD_MODE, "Use compatible behavior.",
(uchar**) &global_system_variables.old_mode,
- (uchar**) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG,
+ (uchar**) &max_system_variables.old_mode, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"open_files_limit", OPT_OPEN_FILES_LIMIT,
"If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.",
@@ -6727,17 +6836,18 @@ The minimum value for this variable is 4096.",
"Allocation block size for query parsing and execution",
(uchar**) &global_system_variables.query_alloc_block_size,
(uchar**) &max_system_variables.query_alloc_block_size, 0, GET_ULONG,
- REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ULONG_MAX, 0, 1024, 0},
+ REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, (longlong) ULONG_MAX, 0, 1024,
+ 0},
#ifdef HAVE_QUERY_CACHE
{"query_cache_limit", OPT_QUERY_CACHE_LIMIT,
"Don't cache results that are bigger than this.",
(uchar**) &query_cache_limit, (uchar**) &query_cache_limit, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L, 0, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, 1024*1024L, 0, (longlong) ULONG_MAX, 0, 1, 0},
{"query_cache_min_res_unit", OPT_QUERY_CACHE_MIN_RES_UNIT,
"minimal size of unit in wich space for results is allocated (last unit will be trimed after writing all result data.",
(uchar**) &query_cache_min_res_unit, (uchar**) &query_cache_min_res_unit,
0, GET_ULONG, REQUIRED_ARG, QUERY_CACHE_MIN_RESULT_DATA_SIZE,
- 0, ULONG_MAX, 0, 1, 0},
+ 0, (longlong) ULONG_MAX, 0, 1, 0},
#endif /*HAVE_QUERY_CACHE*/
{"query_cache_size", OPT_QUERY_CACHE_SIZE,
"The memory allocated to store results from old queries.",
@@ -6760,13 +6870,13 @@ The minimum value for this variable is 4096.",
(uchar**) &global_system_variables.query_prealloc_size,
(uchar**) &max_system_variables.query_prealloc_size, 0, GET_ULONG,
REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, QUERY_ALLOC_PREALLOC_SIZE,
- ULONG_MAX, 0, 1024, 0},
+ (longlong) ULONG_MAX, 0, 1024, 0},
{"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE,
"Allocation block size for storing ranges during optimization",
(uchar**) &global_system_variables.range_alloc_block_size,
(uchar**) &max_system_variables.range_alloc_block_size, 0, GET_ULONG,
- REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, RANGE_ALLOC_BLOCK_SIZE, ULONG_MAX,
- 0, 1024, 0},
+ REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, RANGE_ALLOC_BLOCK_SIZE,
+ (longlong) ULONG_MAX, 0, 1024, 0},
{"read_buffer_size", OPT_RECORD_BUFFER,
"Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.",
(uchar**) &global_system_variables.read_buff_size,
@@ -6824,13 +6934,13 @@ The minimum value for this variable is 4096.",
"Each thread that needs to do a sort allocates a buffer of this size.",
(uchar**) &global_system_variables.sortbuff_size,
(uchar**) &max_system_variables.sortbuff_size, 0, GET_ULONG, REQUIRED_ARG,
- MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD,
- 1, 0},
+ MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, (longlong) ULONG_MAX,
+ MALLOC_OVERHEAD, 1, 0},
{"sync-binlog", OPT_SYNC_BINLOG,
"Synchronously flush binary log to disk after every #th event. "
"Use 0 (default) to disable synchronous flushing.",
(uchar**) &sync_binlog_period, (uchar**) &sync_binlog_period, 0, GET_ULONG,
- REQUIRED_ARG, 0, 0, ULONG_MAX, 0, 1, 0},
+ REQUIRED_ARG, 0, 0, (longlong) ULONG_MAX, 0, 1, 0},
{"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.",
(uchar**) &opt_sync_frm, (uchar**) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0,
0, 0, 0, 0},
@@ -6869,7 +6979,7 @@ The minimum value for this variable is 4096.",
{"thread_stack", OPT_THREAD_STACK,
"The stack size for each thread.", (uchar**) &my_thread_stack_size,
(uchar**) &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
- 1024L*128L, ULONG_MAX, 0, 1024, 0},
+ 1024L*128L, (longlong) ULONG_MAX, 0, 1024, 0},
{ "time_format", OPT_TIME_FORMAT,
"The TIME format (for future).",
(uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_TIME],
@@ -6885,12 +6995,14 @@ The minimum value for this variable is 4096.",
"Allocation block size for transactions to be stored in binary log",
(uchar**) &global_system_variables.trans_alloc_block_size,
(uchar**) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG,
- REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ULONG_MAX, 0, 1024, 0},
+ REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, (longlong) ULONG_MAX, 0, 1024,
+ 0},
{"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE,
"Persistent buffer for transactions to be stored in binary log",
(uchar**) &global_system_variables.trans_prealloc_size,
(uchar**) &max_system_variables.trans_prealloc_size, 0, GET_ULONG,
- REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ULONG_MAX, 0, 1024, 0},
+ REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, (longlong) ULONG_MAX, 0,
+ 1024, 0},
{"thread_handling", OPT_THREAD_HANDLING,
"Define threads usage for handling queries: "
"one-thread-per-connection or no-threads", 0, 0,
@@ -7174,7 +7286,7 @@ static int show_ssl_ctx_get_session_cache_mode(THD *thd, SHOW_VAR *var, char *bu
}
/*
- Functions relying on SSL
+ Functions relying on SSL
Note: In the show_ssl_* functions, we need to check if we have a
valid vio-object since this isn't always true, specifically
when session_status or global_status is requested from
@@ -7419,7 +7531,7 @@ static void usage(void)
default_collation_name= (char*) default_charset_info->name;
print_version();
puts("\
-Copyright (C) 2000 MySQL AB, by Monty and others\n\
+Copyright (C) 2000-2008 MySQL AB, Monty and others, 2008-2009 Sun Microsystems, Inc.\n\
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
and you are welcome to modify and redistribute it under the GPL license\n\n\
Starts the MySQL database server\n");
@@ -7478,7 +7590,10 @@ static int mysql_init_variables(void)
/* Things reset to zero */
opt_skip_slave_start= opt_reckless_slave = 0;
mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
+#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
+ /* We can only test for sub paths if my_symlink.c is using realpath */
myisam_test_invalid_symlink= test_if_data_home_dir;
+#endif
opt_log= opt_slow_log= 0;
opt_update_log= 0;
log_output_options= find_bit_type(log_output_str, &log_output_typelib);
@@ -7558,6 +7673,7 @@ static int mysql_init_variables(void)
sql_print_error("Cannot allocate the keycache");
return 1;
}
+
/* set key_cache_hash.default_value = dflt_key_cache */
multi_keycache_init();
@@ -7710,12 +7826,22 @@ mysqld_get_one_option(int optid,
char *argument)
{
switch(optid) {
- case '#':
#ifndef DBUG_OFF
- DBUG_SET_INITIAL(argument ? argument : default_dbug_option);
-#endif
+ case '#':
+ if (!argument)
+ argument= (char*) default_dbug_option;
+ if (argument[0] == '0' && !argument[1])
+ {
+ DEBUGGER_OFF;
+ break;
+ }
+ DEBUGGER_ON;
+ if (argument[0] == '1' && !argument[1])
+ break;
+ DBUG_SET_INITIAL(argument);
opt_endinfo=1; /* unireg: memory allocation */
break;
+#endif
case 'a':
global_system_variables.sql_mode= fix_sql_mode(MODE_ANSI);
global_system_variables.tx_isolation= ISO_SERIALIZABLE;
@@ -8023,16 +8149,16 @@ mysqld_get_one_option(int optid,
case OPT_MASTER_PASSWORD:
case OPT_MASTER_PORT:
case OPT_MASTER_CONNECT_RETRY:
- case OPT_MASTER_SSL:
+ case OPT_MASTER_SSL:
case OPT_MASTER_SSL_KEY:
- case OPT_MASTER_SSL_CERT:
+ case OPT_MASTER_SSL_CERT:
case OPT_MASTER_SSL_CAPATH:
case OPT_MASTER_SSL_CIPHER:
case OPT_MASTER_SSL_CA:
if (!slave_warning_issued) //only show the warning once
{
- slave_warning_issued = true;
- WARN_DEPRECATED(NULL, "5.2", "for replication startup options",
+ slave_warning_issued = true;
+ WARN_DEPRECATED(NULL, "5.2", "for replication startup options",
"'CHANGE MASTER'");
}
break;
@@ -8338,6 +8464,7 @@ static void get_options(int *argc,char **argv)
/* Set global variables based on startup options */
myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
+ my_crc_dbug_check= opt_my_crc_dbug_check;
/* long_query_time is in microseconds */
global_system_variables.long_query_time= max_system_variables.long_query_time=
@@ -8502,7 +8629,7 @@ static ulong find_bit_type_or_exit(const char *x, TYPELIB *bit_lib,
ulong res;
const char **ptr;
-
+
if ((res= find_bit_type(x, bit_lib)) == ~(ulong) 0)
{
ptr= bit_lib->type_names;
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 3ccc1e5cf41..f0f856c3c6a 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -966,15 +966,11 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond)
SELECT MAX(b) FROM t1 WHERE a=const AND b<const
*/
if (max_fl != less_fl)
- return cond->val_int() == 0; // Return 1 if WHERE is false
+ return cond->val_int() == 0; // Return 1 if WHERE is false
return 0;
}
- case Item_func::EQ_FUNC:
- case Item_func::EQUAL_FUNC:
- break;
- default: // Keep compiler happy
- DBUG_ASSERT(1); // Impossible
- break;
+ default:
+ break; // Ignore
}
return 0;
}
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index e2027d3571e..8fc9e584789 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -1208,13 +1208,11 @@ bool partition_info::set_up_charset_field_preps()
i= 0;
while ((field= *(ptr++)))
{
- CHARSET_INFO *cs;
uchar *field_buf;
LINT_INIT(field_buf);
if (!field_is_partition_charset(field))
continue;
- cs= ((Field_str*)field)->charset();
size= field->pack_length();
if (!(field_buf= (uchar*) sql_calloc(size)))
goto error;
diff --git a/sql/password.c b/sql/password.c
index 1ff67888ea4..43430f37f96 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -69,41 +69,12 @@
/*
New (MySQL 3.21+) random generation structure initialization
SYNOPSIS
- randominit()
+ my_rnd_init()
rand_st OUT Structure to initialize
seed1 IN First initialization parameter
seed2 IN Second initialization parameter
*/
-void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2)
-{ /* For mysql 3.21.# */
-#ifdef HAVE_purify
- bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
-#endif
- rand_st->max_value= 0x3FFFFFFFL;
- rand_st->max_value_dbl=(double) rand_st->max_value;
- rand_st->seed1=seed1%rand_st->max_value ;
- rand_st->seed2=seed2%rand_st->max_value;
-}
-
-
-/*
- Generate random number.
- SYNOPSIS
- my_rnd()
- rand_st INOUT Structure used for number generation
- RETURN VALUE
- generated pseudo random number
-*/
-
-double my_rnd(struct rand_struct *rand_st)
-{
- rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
- rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
- return (((double) rand_st->seed1)/rand_st->max_value_dbl);
-}
-
-
/*
Generate binary hash from raw text string
Used for Pre-4.1 password handling
@@ -164,7 +135,7 @@ void make_scrambled_password_323(char *to, const char *password)
void scramble_323(char *to, const char *message, const char *password)
{
- struct rand_struct rand_st;
+ struct my_rnd_struct rand_st;
ulong hash_pass[2], hash_message[2];
if (password && password[0])
@@ -173,7 +144,7 @@ void scramble_323(char *to, const char *message, const char *password)
const char *message_end= message + SCRAMBLE_LENGTH_323;
hash_password(hash_pass,password, (uint) strlen(password));
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ my_rnd_init(&rand_st,hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
for (; message < message_end; message++)
*to++= (char) (floor(my_rnd(&rand_st)*31)+64);
@@ -206,13 +177,13 @@ my_bool
check_scramble_323(const char *scrambled, const char *message,
ulong *hash_pass)
{
- struct rand_struct rand_st;
+ struct my_rnd_struct rand_st;
ulong hash_message[2];
char buff[16],*to,extra; /* Big enough for check */
const char *pos;
hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ my_rnd_init(&rand_st,hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
to=buff;
DBUG_ASSERT(sizeof(buff) > SCRAMBLE_LENGTH_323);
@@ -293,7 +264,8 @@ void make_password_from_salt_323(char *to, const ulong *salt)
rand_st INOUT structure used for number generation
*/
-void create_random_string(char *to, uint length, struct rand_struct *rand_st)
+void create_random_string(char *to, uint length,
+ struct my_rnd_struct *rand_st)
{
char *end= to + length;
/* Use pointer arithmetics as it is faster way to do so. */
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 4177cd0054d..e608420f21a 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -383,6 +383,7 @@ static uchar *net_store_length_fast(uchar *packet, uint length)
void net_end_statement(THD *thd)
{
+ DBUG_ENTER("net_end_statement");
DBUG_ASSERT(! thd->main_da.is_sent);
/* Can not be true, but do not take chances in production. */
@@ -419,6 +420,7 @@ void net_end_statement(THD *thd)
break;
}
thd->main_da.is_sent= TRUE;
+ DBUG_VOID_RETURN;
}
@@ -475,9 +477,10 @@ void Protocol::init(THD *thd_arg)
for the error.
*/
-void Protocol::end_partial_result_set(THD *thd)
+void Protocol::end_partial_result_set(THD *thd_arg)
{
- net_send_eof(thd, thd->server_status, 0 /* no warnings, we're inside SP */);
+ net_send_eof(thd_arg, thd_arg->server_status,
+ 0 /* no warnings, we're inside SP */);
}
@@ -788,8 +791,8 @@ bool Protocol_text::store(const char *from, size_t length,
{
CHARSET_INFO *tocs= this->thd->variables.character_set_results;
#ifndef DBUG_OFF
- DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %s", field_pos,
- field_count, from));
+ DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %*s", field_pos,
+ field_count, (int) length, from));
DBUG_ASSERT(field_pos < field_count);
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc
index fb609e12dcb..2d7234f78d7 100644
--- a/sql/rpl_filter.cc
+++ b/sql/rpl_filter.cc
@@ -351,6 +351,7 @@ Rpl_filter::add_do_db(const char* table_spec)
DBUG_ENTER("Rpl_filter::add_do_db");
i_string *db = new i_string(table_spec);
do_db.push_back(db);
+ DBUG_VOID_RETURN;
}
@@ -360,6 +361,7 @@ Rpl_filter::add_ignore_db(const char* table_spec)
DBUG_ENTER("Rpl_filter::add_ignore_db");
i_string *db = new i_string(table_spec);
ignore_db.push_back(db);
+ DBUG_VOID_RETURN;
}
extern "C" uchar *get_table_key(const uchar *, size_t *, my_bool);
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index 684655d1c3b..5132f51bef6 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -35,6 +35,7 @@ injector::transaction::transaction(MYSQL_BIN_LOG *log, THD *thd)
m_start_pos.m_file_name= my_strdup(log_info.log_file_name, MYF(0));
m_start_pos.m_file_pos= log_info.pos;
+ m_thd->lex->start_transaction_opt= 0; /* for begin_trans() */
begin_trans(m_thd);
thd->set_current_stmt_binlog_row_based();
diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h
index 4ece092c5b8..a31ff31a44f 100644
--- a/sql/rpl_injector.h
+++ b/sql/rpl_injector.h
@@ -290,7 +290,7 @@ public:
"START_STATE", "TABLE_STATE", "ROW_STATE", "STATE_COUNT"
};
- DBUG_ASSERT(0 <= target_state && target_state <= STATE_COUNT);
+ DBUG_ASSERT(target_state <= STATE_COUNT);
DBUG_PRINT("info", ("In state %s", state_name[m_state]));
#endif
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 5e46837e948..cb8b0e02ef9 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -38,11 +38,26 @@ Master_info::Master_info()
ssl_cipher[0]= 0; ssl_key[0]= 0;
bzero((char*) &file, sizeof(file));
- pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
+ /*
+ We have to use MYF_NO_DEADLOCK_DETECTION because mysqld doesn't
+ lock run_lock and data_lock consistently.
+ Should be fixed as this can easily lead to deadlocks
+ */
+ my_pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST,
+ "Master_info::run_lock", MYF_NO_DEADLOCK_DETECTION);
+ my_pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST,
+ "Master_info::data_lock", MYF_NO_DEADLOCK_DETECTION);
pthread_cond_init(&data_cond, NULL);
pthread_cond_init(&start_cond, NULL);
pthread_cond_init(&stop_cond, NULL);
+
+#ifdef SAFE_MUTEX
+ /* Define mutex order for locks to find wrong lock usage */
+ pthread_mutex_lock(&data_lock);
+ pthread_mutex_lock(&run_lock);
+ pthread_mutex_unlock(&run_lock);
+ pthread_mutex_unlock(&data_lock);
+#endif
}
Master_info::~Master_info()
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 3a0f784d195..fe8e17dc1c7 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -33,10 +33,10 @@ Relay_log_info::Relay_log_info()
:Slave_reporting_capability("SQL"),
no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id),
info_fd(-1), cur_log_fd(-1), save_temporary_tables(0),
+ cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0),
#if HAVE_purify
is_fake(FALSE),
#endif
- cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0),
group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0),
last_master_timestamp(0), slave_skip_counter(0),
abort_pos_wait(0), slave_run_id(0), sql_thd(0),
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 07e1528d483..da2c8b9cfd8 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -59,7 +59,7 @@
#include <thr_alarm.h>
#include <myisam.h>
#include <my_dir.h>
-
+#include <waiting_threads.h>
#include "events.h"
/* WITH_NDBCLUSTER_STORAGE_ENGINE */
@@ -234,6 +234,19 @@ static sys_var_long_ptr sys_concurrent_insert(&vars, "concurrent_insert",
static sys_var_long_ptr sys_connect_timeout(&vars, "connect_timeout",
&connect_timeout);
static sys_var_const_os_str sys_datadir(&vars, "datadir", mysql_real_data_home);
+
+static sys_var_thd_ulong sys_deadlock_search_depth_short(&vars,
+ "deadlock_search_depth_short",
+ &SV::wt_deadlock_search_depth_short);
+static sys_var_thd_ulong sys_deadlock_search_depth_long(&vars,
+ "deadlock_search_depth_long",
+ &SV::wt_deadlock_search_depth_long);
+static sys_var_thd_ulong sys_deadlock_timeout_short(&vars,
+ "deadlock_timeout_short",
+ &SV::wt_timeout_short);
+static sys_var_thd_ulong sys_deadlock_timeout_long(&vars,
+ "deadlock_timeout_long",
+ &SV::wt_timeout_long);
#ifndef DBUG_OFF
static sys_var_thd_dbug sys_dbug(&vars, "debug");
#endif
@@ -323,7 +336,7 @@ static sys_var_const sys_log_bin(&vars, "log_bin",
static sys_var_trust_routine_creators
sys_trust_routine_creators(&vars, "log_bin_trust_routine_creators",
&trust_function_creators);
-static sys_var_bool_ptr
+static sys_var_bool_ptr
sys_trust_function_creators(&vars, "log_bin_trust_function_creators",
&trust_function_creators);
static sys_var_const sys_log_error(&vars, "log_error",
@@ -545,10 +558,10 @@ static sys_var_thd_ulong sys_trans_alloc_block_size(&vars, "transaction_alloc_bl
static sys_var_thd_ulong sys_trans_prealloc_size(&vars, "transaction_prealloc_size",
&SV::trans_prealloc_size,
0, fix_trans_mem_root);
-sys_var_enum_const sys_thread_handling(&vars, "thread_handling",
- &SV::thread_handling,
- &thread_handling_typelib,
- NULL);
+sys_var_enum_const sys_thread_handling(&vars, "thread_handling",
+ &SV::thread_handling,
+ &thread_handling_typelib,
+ NULL);
#ifdef HAVE_QUERY_CACHE
static sys_var_long_ptr sys_query_cache_limit(&vars, "query_cache_limit",
@@ -1232,6 +1245,7 @@ void fix_slave_exec_mode(enum_var_type type)
}
if (bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT) == 0)
bit_do_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT);
+ DBUG_VOID_RETURN;
}
@@ -1278,7 +1292,7 @@ bool sys_var_thd_binlog_format::is_readonly() const
if (thd->in_sub_stmt)
{
my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
- return 1;
+ return 1;
}
return sys_var_thd_enum::is_readonly();
}
@@ -1509,7 +1523,6 @@ uchar *sys_var_enum::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
return (uchar*) enum_names->type_names[*value];
}
-
uchar *sys_var_enum_const::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
@@ -1590,7 +1603,7 @@ bool sys_var_thd_ha_rows::update(THD *thd, set_var *var)
if (var->type == OPT_GLOBAL)
{
/* Lock is needed to make things safe on 32 bit systems */
- pthread_mutex_lock(&LOCK_global_system_variables);
+ pthread_mutex_lock(&LOCK_global_system_variables);
global_system_variables.*offset= (ha_rows) tmp;
pthread_mutex_unlock(&LOCK_global_system_variables);
}
@@ -2199,10 +2212,9 @@ KEY_CACHE *get_key_cache(LEX_STRING *cache_name)
if (!cache_name || ! cache_name->length)
cache_name= &default_key_cache_base;
return ((KEY_CACHE*) find_named(&key_caches,
- cache_name->str, cache_name->length, 0));
+ cache_name->str, cache_name->length, 0));
}
-
uchar *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
@@ -2358,13 +2370,11 @@ end:
bool sys_var_log_state::update(THD *thd, set_var *var)
{
bool res;
-
if (this == &sys_var_log)
WARN_DEPRECATED(thd, "7.0", "@@log", "'@@general_log'");
else if (this == &sys_var_log_slow)
WARN_DEPRECATED(thd, "7.0", "@@log_slow_queries", "'@@slow_query_log'");
- pthread_mutex_lock(&LOCK_global_system_variables);
if (!var->save_result.ulong_value)
{
logger.deactivate_log_handler(thd, log_type);
@@ -2372,7 +2382,6 @@ bool sys_var_log_state::update(THD *thd, set_var *var)
}
else
res= logger.activate_log_handler(thd, log_type);
- pthread_mutex_unlock(&LOCK_global_system_variables);
return res;
}
@@ -2383,9 +2392,7 @@ void sys_var_log_state::set_default(THD *thd, enum_var_type type)
else if (this == &sys_var_log_slow)
WARN_DEPRECATED(thd, "7.0", "@@log_slow_queries", "'@@slow_query_log'");
- pthread_mutex_lock(&LOCK_global_system_variables);
logger.deactivate_log_handler(thd, log_type);
- pthread_mutex_unlock(&LOCK_global_system_variables);
}
@@ -2481,23 +2488,18 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
goto err;
}
- pthread_mutex_lock(&LOCK_global_system_variables);
logger.lock_exclusive();
if (file_log && log_state)
file_log->close(0);
- old_value= var_str->value;
- var_str->value= res;
- var_str->value_length= str_length;
- my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
if (file_log && log_state)
{
switch (log_type) {
case QUERY_LOG_SLOW:
- file_log->open_slow_log(sys_var_slow_log_path.value);
+ file_log->open_slow_log(res);
break;
case QUERY_LOG_GENERAL:
- file_log->open_query_log(sys_var_general_log_path.value);
+ file_log->open_query_log(res);
break;
default:
DBUG_ASSERT(0);
@@ -2505,6 +2507,13 @@ bool update_sys_var_str_path(THD *thd, sys_var_str *var_str,
}
logger.unlock();
+
+ /* update global variable */
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ old_value= var_str->value;
+ var_str->value= res;
+ var_str->value_length= str_length;
+ my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
pthread_mutex_unlock(&LOCK_global_system_variables);
err:
@@ -2544,26 +2553,22 @@ static void sys_default_slow_log_path(THD *thd, enum_var_type type)
bool sys_var_log_output::update(THD *thd, set_var *var)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
logger.lock_exclusive();
logger.init_slow_log(var->save_result.ulong_value);
logger.init_general_log(var->save_result.ulong_value);
*value= var->save_result.ulong_value;
logger.unlock();
- pthread_mutex_unlock(&LOCK_global_system_variables);
return 0;
}
void sys_var_log_output::set_default(THD *thd, enum_var_type type)
{
- pthread_mutex_lock(&LOCK_global_system_variables);
logger.lock_exclusive();
logger.init_slow_log(LOG_FILE);
logger.init_general_log(LOG_FILE);
*value= LOG_FILE;
logger.unlock();
- pthread_mutex_unlock(&LOCK_global_system_variables);
}
@@ -3633,7 +3638,7 @@ uchar *sys_var_thd_storage_engine::value_ptr(THD *thd, enum_var_type type,
if (type == OPT_GLOBAL)
plugin= my_plugin_lock(thd, &(global_system_variables.*offset));
hton= plugin_data(plugin, handlerton*);
- engine_name= &hton2plugin[hton->slot]->name;
+ engine_name= hton_name(hton);
result= (uchar *) thd->strmake(engine_name->str, engine_name->length);
if (type == OPT_GLOBAL)
plugin_unlock(thd, plugin);
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index 64898915b7e..13b3e771a91 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -106,6 +106,12 @@ void sp_cache_clear(sp_cache **cp)
}
+void sp_cache_end()
+{
+ pthread_mutex_destroy(&Cversion_lock);
+}
+
+
/*
Insert a routine into the cache.
diff --git a/sql/sp_cache.h b/sql/sp_cache.h
index f4d44a1f29f..efb61d76719 100644
--- a/sql/sp_cache.h
+++ b/sql/sp_cache.h
@@ -53,6 +53,7 @@ class sp_cache;
*/
void sp_cache_init();
+void sp_cache_end();
void sp_cache_clear(sp_cache **cp);
void sp_cache_insert(sp_cache **cp, sp_head *sp);
sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name);
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 97e5fcfa27a..9e59a5ee0de 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -150,11 +150,9 @@ Geometry *Geometry::construct(Geometry_buffer *buffer,
{
uint32 geom_type;
Geometry *result;
- char byte_order;
if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4)
return NULL;
- byte_order= data[SRID_SIZE];
geom_type= uint4korr(data + SRID_SIZE + 1);
if (!(result= create_by_typeid(buffer, (int) geom_type)))
return NULL;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index bd940608a07..efdcb5cec69 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -5611,7 +5611,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
{
int result;
String wrong_users;
- ulong sql_mode;
LEX_USER *user_name, *tmp_user_name;
List_iterator <LEX_USER> user_list(list);
TABLE_LIST tables[GRANT_TABLES];
@@ -5652,7 +5651,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
}
some_users_created= TRUE;
- sql_mode= thd->variables.sql_mode;
if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0))
{
append_user(&wrong_users, user_name);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 6db9f1df0f2..13d3af1b8d1 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2131,6 +2131,7 @@ void unlink_open_table(THD *thd, TABLE *find, bool unlock)
void drop_open_table(THD *thd, TABLE *table, const char *db_name,
const char *table_name)
{
+ DBUG_ENTER("drop_open_table");
if (table->s->tmp_table)
close_temporary_table(thd, table, 1, 1);
else
@@ -2141,10 +2142,12 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name,
unlink_open_table() also tells threads waiting for refresh or close
that something has happened.
*/
+ table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
unlink_open_table(thd, table, FALSE);
quick_rm_table(table_type, db_name, table_name, 0);
VOID(pthread_mutex_unlock(&LOCK_open));
}
+ DBUG_VOID_RETURN;
}
@@ -2997,6 +3000,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->pos_in_table_list= table_list;
table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
table->clear_column_bitmaps();
+#if !defined(DBUG_OFF) && !defined(HAVE_purify)
+ /*
+ Fill record with random values to find bugs where we access fields
+ without first reading them.
+ */
+ bfill(table->record[0], table->s->reclength, 254);
+#endif
DBUG_ASSERT(table->key_read == 0);
DBUG_RETURN(table);
}
@@ -3456,6 +3466,11 @@ static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks,
if (ulcktbl->lock_count)
{
/*
+ Inform handler that we will do a close even if the table may be
+ locked or part of a transaction
+ */
+ table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE);
+ /*
Wake up threads waiting for table-level lock on this table
so they won't sneak in when we will temporarily remove our
lock on it. This will also give them a chance to close their
@@ -3630,6 +3645,9 @@ TABLE *drop_locked_tables(THD *thd,const char *db, const char *table_name)
if (!strcmp(table->s->table_name.str, table_name) &&
!strcmp(table->s->db.str, db))
{
+ /* Inform handler that table will be dropped after close */
+ table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
+
/* If MERGE child, forward lock handling to parent. */
mysql_lock_remove(thd, thd->locked_tables,
table->parent ? table->parent : table, TRUE);
@@ -4467,8 +4485,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
/* Also used for indicating that prelocking is need */
TABLE_LIST **query_tables_last_own;
bool safe_to_ignore_table;
-
DBUG_ENTER("open_tables");
+
/*
temporary mem_root for new .frm parsing.
TODO: variables for size
@@ -5548,7 +5566,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
DBUG_ENTER("update_field_dependencies");
if (thd->mark_used_columns != MARK_COLUMNS_NONE)
{
- MY_BITMAP *current_bitmap, *other_bitmap;
+ MY_BITMAP *current_bitmap;
/*
We always want to register the used keys, as the column bitmap may have
@@ -5559,15 +5577,9 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
table->merge_keys.merge(field->part_of_key);
if (thd->mark_used_columns == MARK_COLUMNS_READ)
- {
current_bitmap= table->read_set;
- other_bitmap= table->write_set;
- }
else
- {
current_bitmap= table->write_set;
- other_bitmap= table->read_set;
- }
if (bitmap_fast_test_and_set(current_bitmap, field->field_index))
{
@@ -7351,7 +7363,10 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
/* make * substituting permanent */
SELECT_LEX *select_lex= thd->lex->current_select;
select_lex->with_wild= 0;
- select_lex->item_list= fields;
+#ifdef HAVE_purify
+ if (&select_lex->item_list != &fields) // Avoid warning
+#endif
+ select_lex->item_list= fields;
thd->restore_active_arena(arena, &backup);
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 7c97ee4cf32..63a5af5e666 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1185,7 +1185,10 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
{
ulonglong engine_data;
Query_cache_query *query;
- Query_cache_block *first_result_block, *result_block;
+#ifndef EMBEDDED_LIBRARY
+ Query_cache_block *first_result_block;
+#endif
+ Query_cache_block *result_block;
Query_cache_block_table *block_table, *block_table_end;
ulong tot_length;
Query_cache_query_flags flags;
@@ -1334,7 +1337,10 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
BLOCK_LOCK_RD(query_block);
query = query_block->query();
- result_block= first_result_block= query->result();
+ result_block= query->result();
+#ifndef EMBEDDED_LIBRARY
+ first_result_block= result_block;
+#endif
if (result_block == 0 || result_block->type != Query_cache_block::RESULT)
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 06f1c644be0..af62961c65f 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -261,13 +261,16 @@ int thd_tablespace_op(const THD *thd)
extern "C"
-const char *set_thd_proc_info(THD *thd, const char *info,
- const char *calling_function,
- const char *calling_file,
+const char *set_thd_proc_info(THD *thd, const char *info,
+ const char *calling_function,
+ const char *calling_file,
const unsigned int calling_line)
{
+ if (!thd)
+ thd= current_thd;
+
const char *old_info= thd->proc_info;
- DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
+ DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
(info != NULL) ? info : "(null)"));
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
thd->profiling.status_change(info, calling_function, calling_file, calling_line);
@@ -407,6 +410,7 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
void
Diagnostics_area::reset_diagnostics_area()
{
+ DBUG_ENTER("reset_diagnostics_area");
#ifdef DBUG_OFF
can_overwrite_status= FALSE;
/** Don't take chances in production */
@@ -420,6 +424,7 @@ Diagnostics_area::reset_diagnostics_area()
is_sent= FALSE;
/** Tiny reset in debug mode to see garbage right away */
m_status= DA_EMPTY;
+ DBUG_VOID_RETURN;
}
@@ -433,16 +438,14 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
ulonglong last_insert_id_arg,
const char *message_arg)
{
+ DBUG_ENTER("set_ok_status");
DBUG_ASSERT(! is_set());
-#ifdef DBUG_OFF
/*
In production, refuse to overwrite an error or a custom response
with an OK packet.
*/
if (is_error() || is_disabled())
return;
-#endif
- /** Only allowed to report success if has not yet reported an error */
m_server_status= thd->server_status;
m_total_warn_count= thd->total_warn_count;
@@ -453,6 +456,7 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
else
m_message[0]= '\0';
m_status= DA_OK;
+ DBUG_VOID_RETURN;
}
@@ -463,17 +467,15 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
void
Diagnostics_area::set_eof_status(THD *thd)
{
- /** Only allowed to report eof if has not yet reported an error */
-
+ DBUG_ENTER("set_eof_status");
+ /* Only allowed to report eof if has not yet reported an error */
DBUG_ASSERT(! is_set());
-#ifdef DBUG_OFF
/*
In production, refuse to overwrite an error or a custom response
with an EOF packet.
*/
if (is_error() || is_disabled())
return;
-#endif
m_server_status= thd->server_status;
/*
@@ -484,6 +486,7 @@ Diagnostics_area::set_eof_status(THD *thd)
m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;
m_status= DA_EOF;
+ DBUG_VOID_RETURN;
}
/**
@@ -494,6 +497,7 @@ void
Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
const char *message_arg)
{
+ DBUG_ENTER("set_error_status");
/*
Only allowed to report error if has not yet reported a success
The only exception is when we flush the message to the client,
@@ -510,9 +514,10 @@ Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
#endif
m_sql_errno= sql_errno_arg;
- strmake(m_message, message_arg, sizeof(m_message) - 1);
+ strmake(m_message, message_arg, sizeof(m_message)-1);
m_status= DA_ERROR;
+ DBUG_VOID_RETURN;
}
@@ -620,6 +625,10 @@ THD::THD()
peer_port= 0; // For SHOW PROCESSLIST
transaction.m_pending_rows_event= 0;
transaction.on= 1;
+ wt_thd_lazy_init(&transaction.wt, &variables.wt_deadlock_search_depth_short,
+ &variables.wt_timeout_short,
+ &variables.wt_deadlock_search_depth_long,
+ &variables.wt_timeout_long);
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
@@ -661,7 +670,7 @@ THD::THD()
tablespace_op=FALSE;
tmp= sql_rnd_with_mutex();
- randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
+ my_rnd_init(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id);
substitute_null_with_insert_id = FALSE;
thr_lock_info_init(&lock_info); /* safety: will be reset after start */
thr_lock_owner_init(&main_lock_id, &lock_info);
@@ -866,6 +875,7 @@ void THD::cleanup(void)
lock=locked_tables; locked_tables=0;
close_thread_tables(this);
}
+ wt_thd_destroy(&transaction.wt);
mysql_ha_cleanup(this);
delete_dynamic(&user_var_events);
hash_free(&user_vars);
@@ -873,7 +883,7 @@ void THD::cleanup(void)
my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR));
-
+
sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache);
@@ -911,6 +921,7 @@ THD::~THD()
#endif
stmt_map.reset(); /* close all prepared statements */
DBUG_ASSERT(lock_info.n_cursors == 0);
+
if (!cleanup_done)
cleanup();
@@ -992,6 +1003,14 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
*(to++)+= *(from++) - *(dec++);
}
+#define SECONDS_TO_WAIT_FOR_KILL 2
+#if !defined(__WIN__) && defined(HAVE_SELECT)
+/* my_sleep() can wait for sub second times */
+#define WAIT_FOR_KILL_TRY_TIMES 20
+#else
+#define WAIT_FOR_KILL_TRY_TIMES 2
+#endif
+
void THD::awake(THD::killed_state state_to_set)
{
@@ -1046,12 +1065,35 @@ void THD::awake(THD::killed_state state_to_set)
we issue a second KILL or the status it's waiting for happens).
It's true that we have set its thd->killed but it may not
see it immediately and so may have time to reach the cond_wait().
+
+ We have to do the loop with trylock, because if we would use
+ pthread_mutex_lock(), we can cause a deadlock as we are here locking
+ the mysys_var->mutex and mysys_var->current_mutex in a different order
+ than in the thread we are trying to kill.
+ We only sleep for 2 seconds as we don't want to have LOCK_delete
+ locked too long time.
+
+ There is a small change we may not succeed in aborting a thread that
+ is not yet waiting for a mutex, but as this happens only for a
+ thread that was doing something else when the kill was issued and
+ which should detect the kill flag before it starts to wait, this
+ should be good enough.
*/
if (mysys_var->current_cond && mysys_var->current_mutex)
{
- pthread_mutex_lock(mysys_var->current_mutex);
- pthread_cond_broadcast(mysys_var->current_cond);
- pthread_mutex_unlock(mysys_var->current_mutex);
+ uint i;
+ for (i= 0; i < WAIT_FOR_KILL_TRY_TIMES * SECONDS_TO_WAIT_FOR_KILL; i++)
+ {
+ int ret= pthread_mutex_trylock(mysys_var->current_mutex);
+ pthread_cond_broadcast(mysys_var->current_cond);
+ if (!ret)
+ {
+ /* Signal is sure to get through */
+ pthread_mutex_unlock(mysys_var->current_mutex);
+ break;
+ }
+ }
+ my_sleep(1000000L / WAIT_FOR_KILL_TRY_TIMES);
}
pthread_mutex_unlock(&mysys_var->mutex);
}
@@ -1081,12 +1123,23 @@ bool THD::store_globals()
*/
mysys_var->id= thread_id;
real_id= pthread_self(); // For debugging
+ mysys_var->stack_ends_here= thread_stack + // for consistency, see libevent_thread_proc
+ STACK_DIRECTION * (long)my_thread_stack_size;
/*
We have to call thr_lock_info_init() again here as THD may have been
created in another thread
*/
thr_lock_info_init(&lock_info);
+
+#ifdef SAFE_MUTEX
+ /* Register order of mutex for wrong mutex deadlock detector */
+ pthread_mutex_lock(&LOCK_delete);
+ pthread_mutex_lock(&mysys_var->mutex);
+
+ pthread_mutex_unlock(&mysys_var->mutex);
+ pthread_mutex_unlock(&LOCK_delete);
+#endif
return 0;
}
@@ -1471,7 +1524,7 @@ void THD::rollback_item_tree_changes()
select_result::select_result()
{
thd=current_thd;
- nest_level= -1;
+ nest_level= (uint) -1;
}
void select_result::send_error(uint errcode,const char *err)
@@ -2132,8 +2185,7 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
if (!cache)
{
cache= Item_cache::get_cache(val_item);
- switch (val_item->result_type())
- {
+ switch (val_item->result_type()) {
case REAL_RESULT:
op= &select_max_min_finder_subselect::cmp_real;
break;
@@ -2147,6 +2199,7 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
op= &select_max_min_finder_subselect::cmp_decimal;
break;
case ROW_RESULT:
+ case IMPOSSIBLE_RESULT:
// This case should never be choosen
DBUG_ASSERT(0);
op= 0;
@@ -3247,70 +3300,6 @@ THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
Update_rows_log_event *);
#endif
-#ifdef NOT_USED
-static char const*
-field_type_name(enum_field_types type)
-{
- switch (type) {
- case MYSQL_TYPE_DECIMAL:
- return "MYSQL_TYPE_DECIMAL";
- case MYSQL_TYPE_TINY:
- return "MYSQL_TYPE_TINY";
- case MYSQL_TYPE_SHORT:
- return "MYSQL_TYPE_SHORT";
- case MYSQL_TYPE_LONG:
- return "MYSQL_TYPE_LONG";
- case MYSQL_TYPE_FLOAT:
- return "MYSQL_TYPE_FLOAT";
- case MYSQL_TYPE_DOUBLE:
- return "MYSQL_TYPE_DOUBLE";
- case MYSQL_TYPE_NULL:
- return "MYSQL_TYPE_NULL";
- case MYSQL_TYPE_TIMESTAMP:
- return "MYSQL_TYPE_TIMESTAMP";
- case MYSQL_TYPE_LONGLONG:
- return "MYSQL_TYPE_LONGLONG";
- case MYSQL_TYPE_INT24:
- return "MYSQL_TYPE_INT24";
- case MYSQL_TYPE_DATE:
- return "MYSQL_TYPE_DATE";
- case MYSQL_TYPE_TIME:
- return "MYSQL_TYPE_TIME";
- case MYSQL_TYPE_DATETIME:
- return "MYSQL_TYPE_DATETIME";
- case MYSQL_TYPE_YEAR:
- return "MYSQL_TYPE_YEAR";
- case MYSQL_TYPE_NEWDATE:
- return "MYSQL_TYPE_NEWDATE";
- case MYSQL_TYPE_VARCHAR:
- return "MYSQL_TYPE_VARCHAR";
- case MYSQL_TYPE_BIT:
- return "MYSQL_TYPE_BIT";
- case MYSQL_TYPE_NEWDECIMAL:
- return "MYSQL_TYPE_NEWDECIMAL";
- case MYSQL_TYPE_ENUM:
- return "MYSQL_TYPE_ENUM";
- case MYSQL_TYPE_SET:
- return "MYSQL_TYPE_SET";
- case MYSQL_TYPE_TINY_BLOB:
- return "MYSQL_TYPE_TINY_BLOB";
- case MYSQL_TYPE_MEDIUM_BLOB:
- return "MYSQL_TYPE_MEDIUM_BLOB";
- case MYSQL_TYPE_LONG_BLOB:
- return "MYSQL_TYPE_LONG_BLOB";
- case MYSQL_TYPE_BLOB:
- return "MYSQL_TYPE_BLOB";
- case MYSQL_TYPE_VAR_STRING:
- return "MYSQL_TYPE_VAR_STRING";
- case MYSQL_TYPE_STRING:
- return "MYSQL_TYPE_STRING";
- case MYSQL_TYPE_GEOMETRY:
- return "MYSQL_TYPE_GEOMETRY";
- }
- return "Unknown";
-}
-#endif
-
namespace {
/**
@@ -3710,11 +3699,10 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
binlog_table_maps= 0;
DBUG_RETURN(error);
}
- break;
case THD::QUERY_TYPE_COUNT:
default:
- DBUG_ASSERT(0 <= qtype && qtype < QUERY_TYPE_COUNT);
+ DBUG_ASSERT(qtype < QUERY_TYPE_COUNT);
}
DBUG_RETURN(0);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 3439e5b4f74..c491f2d3348 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,4 +1,4 @@
-/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -67,6 +67,7 @@ private:
bool m_invalidated;
};
+#include <waiting_threads.h>
class Relay_log_info;
@@ -75,6 +76,7 @@ class Load_log_event;
class Slave_log_event;
class sp_rcontext;
class sp_cache;
+class Lex_input_stream;
class Parser_state;
class Rows_log_event;
@@ -280,18 +282,18 @@ struct system_variables
{
/*
How dynamically allocated system variables are handled:
-
+
The global_system_variables and max_system_variables are "authoritative"
They both should have the same 'version' and 'size'.
When attempting to access a dynamic variable, if the session version
is out of date, then the session version is updated and realloced if
neccessary and bytes copied from global to make up for missing data.
- */
+ */
ulong dynamic_variables_version;
char* dynamic_variables_ptr;
uint dynamic_variables_head; /* largest valid variable offset */
uint dynamic_variables_size; /* how many bytes are in use */
-
+
ulonglong myisam_max_extra_sort_file_size;
ulonglong myisam_max_sort_file_size;
ulonglong max_heap_table_size;
@@ -357,9 +359,9 @@ struct system_variables
my_bool low_priority_updates;
my_bool new_mode;
- /*
+ /*
compatibility option:
- - index usage hints (USE INDEX without a FOR clause) behave as in 5.0
+ - index usage hints (USE INDEX without a FOR clause) behave as in 5.0
*/
my_bool old_mode;
my_bool query_cache_wlock_invalidate;
@@ -396,6 +398,10 @@ struct system_variables
DATE_TIME_FORMAT *datetime_format;
DATE_TIME_FORMAT *time_format;
my_bool sysdate_is_now;
+
+ /* deadlock detection */
+ ulong wt_timeout_short, wt_deadlock_search_depth_short;
+ ulong wt_timeout_long, wt_deadlock_search_depth_long;
};
@@ -591,7 +597,7 @@ class Server_side_cursor;
- prepared, that is, contain placeholders,
- opened as cursors. We maintain 1 to 1 relationship between
statement and cursor - if user wants to create another cursor for his
- query, we create another statement for it.
+ query, we create another statement for it.
To perform some action with statement we reset THD part to the state of
that statement, do the action, and then save back modified state from THD
to the statement. It will be changed in near future, and Statement will
@@ -642,7 +648,7 @@ public:
it. We will see the query_length field as either 0, or the right value
for it.
Assuming that the write and read of an n-bit memory field in an n-bit
- computer is atomic, we can avoid races in the above way.
+ computer is atomic, we can avoid races in the above way.
This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB
STATUS.
*/
@@ -797,7 +803,7 @@ public:
{
return (*priv_host ? priv_host : (char *)"%");
}
-
+
bool set_user(char *user_arg);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1262,7 +1268,7 @@ public:
String packet; // dynamic buffer for network I/O
String convert_buffer; // buffer for charset conversions
struct sockaddr_in remote; // client socket address
- struct rand_struct rand; // used for authentication
+ struct my_rnd_struct rand; // used for authentication
struct system_variables variables; // Changeable local variables
struct system_status_var status_var; // Per thread statistic vars
struct system_status_var *initial_status_var; /* used by show status */
@@ -1325,7 +1331,7 @@ public:
/*
One thread can hold up to one named user-level lock. This variable
points to a lock object if the lock is present. See item_func.cc and
- chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK.
+ chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK.
*/
User_level_lock *ull;
#ifndef DBUG_OFF
@@ -1344,7 +1350,7 @@ public:
time_t start_time, user_time;
ulonglong connect_utime, thr_create_utime; // track down slow pthread_create
ulonglong start_utime, utime_after_lock;
-
+
thr_lock_type update_lock_default;
Delayed_insert *di;
@@ -1421,6 +1427,7 @@ public:
THD_TRANS stmt; // Trans for current statement
bool on; // see ha_enable_transaction()
XID_STATE xid_state;
+ WT_THD wt; ///< for deadlock detection
Rows_log_event *m_pending_rows_event;
/*
@@ -1753,7 +1760,7 @@ public:
*/
bool is_slave_error;
bool bootstrap, cleanup_done;
-
+
/** is set if some thread specific value(s) used in a statement. */
bool thread_specific_used;
bool charset_is_system_charset, charset_is_collation_connection;
@@ -1785,10 +1792,10 @@ public:
ulong ulong_value;
ulonglong ulonglong_value;
} sys_var_tmp;
-
+
struct {
- /*
- If true, mysql_bin_log::write(Log_event) call will not write events to
+ /*
+ If true, mysql_bin_log::write(Log_event) call will not write events to
binlog, and maintain 2 below variables instead (use
mysql_bin_log.start_union_events to turn this on)
*/
@@ -1799,13 +1806,13 @@ public:
*/
bool unioned_events;
/*
- If TRUE, at least one mysql_bin_log::write(Log_event e), where
- e.cache_stmt == TRUE call has been made after last
+ If TRUE, at least one mysql_bin_log::write(Log_event e), where
+ e.cache_stmt == TRUE call has been made after last
mysql_bin_log.start_union_events() call.
*/
bool unioned_events_trans;
-
- /*
+
+ /*
'queries' (actually SP statements) that run under inside this binlog
union have thd->query_id >= first_query_id.
*/
@@ -1834,7 +1841,7 @@ public:
killing mysqld) where it's vital to not allocate excessive and not used
memory. Note, that we still don't return error from init_for_queries():
if preallocation fails, we should notice that at the first call to
- alloc_root.
+ alloc_root.
*/
void init_for_queries();
void change_user(void);
@@ -1864,12 +1871,12 @@ public:
The query can be logged row-based or statement-based
*/
ROW_QUERY_TYPE,
-
+
/*
The query has to be logged statement-based
*/
STMT_QUERY_TYPE,
-
+
/*
The query represents a change to a table in the "mysql"
database and is currently mapped to ROW_QUERY_TYPE.
@@ -1877,7 +1884,7 @@ public:
MYSQL_QUERY_TYPE,
QUERY_TYPE_COUNT
};
-
+
int binlog_query(enum_binlog_query_type qtype,
char const *query, ulong query_len,
bool is_trans, bool suppress_use,
@@ -2127,7 +2134,7 @@ public:
if ((temporary_tables == NULL) && (in_sub_stmt == 0) &&
(system_thread != SYSTEM_THREAD_NDBCLUSTER_BINLOG))
{
- current_stmt_binlog_row_based=
+ current_stmt_binlog_row_based=
test(variables.binlog_format == BINLOG_FORMAT_ROW);
}
}
@@ -2342,7 +2349,7 @@ public:
@return
-1 if nest level is undefined, otherwise a positive integer.
*/
- int get_nest_level() { return nest_level; }
+ int get_nest_level() { return (int) nest_level; }
#ifdef EMBEDDED_LIBRARY
virtual void begin_dataset() {}
#else
@@ -2532,10 +2539,17 @@ public:
int prepare2(void) { return 0; }
};
+
+#if defined(WITH_MARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES)
+#include <maria.h>
+#define ENGINE_COLUMNDEF MARIA_COLUMNDEF
+#else
#include <myisam.h>
+#define ENGINE_COLUMNDEF MI_COLUMNDEF
+#endif
-/*
- Param to create temporary tables when doing SELECT:s
+/*
+ Param to create temporary tables when doing SELECT:s
NOTE
This structure is copied using memcpy as a part of JOIN.
*/
@@ -2554,7 +2568,7 @@ public:
Copy_field *save_copy_field, *save_copy_field_end;
uchar *group_buff;
Item **items_to_copy; /* Fields in tmp table */
- MI_COLUMNDEF *recinfo,*start_recinfo;
+ ENGINE_COLUMNDEF *recinfo, *start_recinfo;
KEY *keyinfo;
ha_rows end_write_records;
uint field_count,sum_func_count,func_count;
@@ -2563,8 +2577,8 @@ public:
uint quick_group;
bool using_indirect_summary_function;
/* If >0 convert all blob fields to varchar(convert_blob_length) */
- uint convert_blob_length;
- CHARSET_INFO *table_charset;
+ uint convert_blob_length;
+ CHARSET_INFO *table_charset;
bool schema_table;
/*
True if GROUP BY and its aggregate functions are already computed
@@ -2698,7 +2712,7 @@ public:
else
db= db_arg;
}
- inline Table_ident(LEX_STRING table_arg)
+ inline Table_ident(LEX_STRING table_arg)
:table(table_arg), sel((SELECT_LEX_UNIT *)0)
{
db.str=0;
@@ -2744,7 +2758,7 @@ class user_var_entry
};
/*
- Unique -- class for unique (removing of duplicates).
+ Unique -- class for unique (removing of duplicates).
Puts all values to the TREE. If the tree becomes too big,
it's dumped to the file. User can request sorted values, or
just iterate through them. In the last case tree merging is performed in
@@ -2778,9 +2792,9 @@ public:
}
bool get(TABLE *table);
- static double get_use_cost(uint *buffer, uint nkeys, uint key_size,
+ static double get_use_cost(uint *buffer, uint nkeys, uint key_size,
ulonglong max_in_memory_size);
- inline static int get_cost_calc_buff_size(ulong nkeys, uint key_size,
+ inline static int get_cost_calc_buff_size(ulong nkeys, uint key_size,
ulonglong max_in_memory_size)
{
register ulonglong max_elems_in_tree=
@@ -2841,7 +2855,7 @@ class multi_update :public select_result_interceptor
uint table_count;
/*
List of tables referenced in the CHECK OPTION condition of
- the updated view excluding the updated table.
+ the updated view excluding the updated table.
*/
List <TABLE> unupdated_check_opt_tables;
Copy_field *copy_field;
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index ebd424f00f0..53babf517c1 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -38,7 +38,7 @@ SQL_CRYPT::SQL_CRYPT(const char *password)
void SQL_CRYPT::crypt_init(ulong *rand_nr)
{
uint i;
- randominit(&rand,rand_nr[0],rand_nr[1]);
+ my_rnd_init(&rand,rand_nr[0],rand_nr[1]);
for (i=0 ; i<=255; i++)
decode_buff[i]= (char) i;
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
index f3db9adde25..7d803245b0b 100644
--- a/sql/sql_crypt.h
+++ b/sql/sql_crypt.h
@@ -20,7 +20,7 @@
class SQL_CRYPT :public Sql_alloc
{
- struct rand_struct rand,org_rand;
+ struct my_rnd_struct rand,org_rand;
char decode_buff[256],encode_buff[256];
uint shift;
void crypt_init(ulong *seed);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 1a23077f6a0..74867398a35 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -992,6 +992,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
DBUG_ENTER("mysql_truncate");
bzero((char*) &create_info,sizeof(create_info));
+
/* If it is a temporary table, close and regenerate it */
if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
{
@@ -1001,7 +1002,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
goto trunc_by_del;
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
-
+
+ create_info.options|= HA_LEX_CREATE_TMP_TABLE;
close_temporary_table(thd, table, 0, 0); // Don't free share
ha_create_table(thd, share->normalized_path.str,
share->db.str, share->table_name.str, &create_info, 1);
@@ -1035,7 +1037,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
table_list->db, table_list->table_name);
DBUG_RETURN(TRUE);
}
- if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd, table_type),
+ if (!ha_check_storage_engine_flag(ha_resolve_by_legacy_type(thd,
+ table_type),
HTON_CAN_RECREATE))
goto trunc_by_del;
@@ -1043,9 +1046,11 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
DBUG_RETURN(TRUE);
}
- // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
- // crashes, replacement works. *(path + path_length - reg_ext_length)=
- // '\0';
+ /*
+ Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
+ crashes, replacement works. *(path + path_length - reg_ext_length)=
+ '\0';
+ */
path[path_length - reg_ext_length] = 0;
VOID(pthread_mutex_lock(&LOCK_open));
error= ha_create_table(thd, path, table_list->db, table_list->table_name,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index fb437bed3fa..2344724818f 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -88,6 +88,7 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
SYNOPSIS
check_view_single_update()
fields The insert/update fields to be checked.
+ values Values to use for update
view The view for insert.
map [in/out] The insert table map.
@@ -107,8 +108,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
1 Error
*/
-bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
- table_map *map)
+bool check_view_single_update(List<Item> &fields, List<Item> *values,
+ TABLE_LIST *view, table_map *map)
{
/* it is join view => we need to find the table for update */
List_iterator_fast<Item> it(fields);
@@ -119,6 +120,15 @@ bool check_view_single_update(List<Item> &fields, TABLE_LIST *view,
while ((item= it++))
tables|= item->used_tables();
+ if (values)
+ {
+ it.init(*values);
+ while ((item= it++))
+ tables|= item->used_tables();
+ }
+
+ /* Convert to real table bits */
+ tables&= ~PSEUDO_TABLE_BITS;
/* Check found map against provided map */
if (*map)
{
@@ -152,6 +162,10 @@ error:
fields The insert fields.
values The insert values.
check_unique If duplicate values should be rejected.
+ fields_and_values_from_different_maps
+ Set to 1 if fields and values are using
+ different table maps, like on select ... insert
+ map Store here table map for used fields
NOTE
Clears TIMESTAMP_AUTO_SET_ON_INSERT from table->timestamp_field_type
@@ -165,7 +179,9 @@ error:
static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
- bool check_unique, table_map *map)
+ bool check_unique,
+ bool fields_and_values_from_different_maps,
+ table_map *map)
{
TABLE *table= table_list->table;
@@ -238,7 +254,10 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE)
{
- if (check_view_single_update(fields, table_list, map))
+ if (check_view_single_update(fields,
+ fields_and_values_from_different_maps ?
+ (List<Item>*) 0 : &values,
+ table_list, map))
return -1;
table= table_list->table;
}
@@ -298,7 +317,8 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
*/
static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
- List<Item> &update_fields, table_map *map)
+ List<Item> &update_fields,
+ List<Item> &update_values, table_map *map)
{
TABLE *table= insert_table_list->table;
my_bool timestamp_mark;
@@ -320,7 +340,8 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
return -1;
if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE &&
- check_view_single_update(update_fields, insert_table_list, map))
+ check_view_single_update(update_fields, &update_values,
+ insert_table_list, map))
return -1;
if (table->timestamp_field)
@@ -387,10 +408,9 @@ void prepare_triggers_for_insert_stmt(TABLE *table)
downgrade the lock in handler::store_lock() method.
*/
-static
-void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
- enum_duplicates duplic,
- bool is_multi_insert)
+void upgrade_lock_type_for_insert(THD *thd, thr_lock_type *lock_type,
+ enum_duplicates duplic,
+ bool is_multi_insert)
{
if (duplic == DUP_UPDATE ||
duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT)
@@ -559,6 +579,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
bool transactional_table, joins_freed= FALSE;
bool changed;
bool was_insert_delayed= (table_list->lock_type == TL_WRITE_DELAYED);
+ bool using_bulk_insert= 0;
uint value_count;
ulong counter = 1;
ulonglong id;
@@ -586,8 +607,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
Upgrade lock type if the requested lock is incompatible with
the current connection mode or table operation.
*/
- upgrade_lock_type(thd, &table_list->lock_type, duplic,
- values_list.elements > 1);
+ upgrade_lock_type_for_insert(thd, &table_list->lock_type, duplic,
+ values_list.elements > 1);
/*
We can't write-delayed into a table locked with LOCK TABLES:
@@ -724,8 +745,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
{
if (duplic != DUP_ERROR || ignore)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- if (!thd->prelocked_mode)
+ if (!thd->prelocked_mode && values_list.elements > 1)
+ {
+ using_bulk_insert= 1;
table->file->ha_start_bulk_insert(values_list.elements);
+ }
}
thd->abort_on_warning= (!ignore && (thd->variables.sql_mode &
@@ -839,7 +863,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
auto_inc values from the delayed_insert thread as they share TABLE.
*/
table->file->ha_release_auto_increment();
- if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+ if (using_bulk_insert && table->file->ha_end_bulk_insert(0) && !error)
{
table->file->print_error(my_errno,MYF(0));
error=1;
@@ -1172,7 +1196,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
bool res= 0;
table_map map= 0;
DBUG_ENTER("mysql_prepare_insert");
- DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d",
+ DBUG_PRINT("enter", ("table_list 0x%lx table 0x%lx view %d",
(ulong)table_list, (ulong)table,
(int)insert_into_view));
/* INSERT should have a SELECT or VALUES clause */
@@ -1225,9 +1249,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
table_list->next_local= 0;
context->resolve_in_table_list_only(table_list);
- res= check_insert_fields(thd, context->table_list, fields, *values,
- !insert_into_view, &map) ||
- setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
+ res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) ||
+ check_insert_fields(thd, context->table_list, fields, *values,
+ !insert_into_view, 0, &map));
if (!res && check_fields)
{
@@ -1240,18 +1264,19 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
thd->abort_on_warning= saved_abort_on_warning;
}
+ if (!res)
+ res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
+
if (!res && duplic == DUP_UPDATE)
{
select_lex->no_wrap_view_item= TRUE;
- res= check_update_fields(thd, context->table_list, update_fields, &map);
+ res= check_update_fields(thd, context->table_list, update_fields,
+ update_values, &map);
select_lex->no_wrap_view_item= FALSE;
}
/* Restore the current context. */
ctx_state.restore_state(context, table_list);
-
- if (!res)
- res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
}
if (res)
@@ -1726,7 +1751,8 @@ public:
thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT;
thd.security_ctx->host_or_ip= "";
bzero((char*) &info,sizeof(info));
- pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
+ my_pthread_mutex_init(&mutex, MY_MUTEX_INIT_FAST, "Delayed_insert::mutex",
+ 0);
pthread_cond_init(&cond,NULL);
pthread_cond_init(&cond_client,NULL);
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -2231,7 +2257,8 @@ void kill_delayed_threads(void)
in handle_delayed_insert()
*/
if (&di->mutex != di->thd.mysys_var->current_mutex)
- pthread_mutex_lock(di->thd.mysys_var->current_mutex);
+ my_pthread_mutex_lock(di->thd.mysys_var->current_mutex,
+ MYF_NO_DEADLOCK_DETECTION);
pthread_cond_broadcast(di->thd.mysys_var->current_cond);
if (&di->mutex != di->thd.mysys_var->current_mutex)
pthread_mutex_unlock(di->thd.mysys_var->current_mutex);
@@ -2477,13 +2504,14 @@ end:
clients
*/
- close_thread_tables(thd); // Free the table
di->table=0;
di->dead= 1; // If error
thd->killed= THD::KILL_CONNECTION; // If error
- pthread_cond_broadcast(&di->cond_client); // Safety
pthread_mutex_unlock(&di->mutex);
+ close_thread_tables(thd); // Free the table
+ pthread_cond_broadcast(&di->cond_client); // Safety
+
pthread_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table
pthread_mutex_lock(&LOCK_delayed_insert);
delete di;
@@ -2877,10 +2905,9 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
we are fixing fields from insert list.
*/
lex->current_select= &lex->select_lex;
- res= check_insert_fields(thd, table_list, *fields, values,
- !insert_into_view, &map) ||
- setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0);
-
+ res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
+ check_insert_fields(thd, table_list, *fields, values,
+ !insert_into_view, 1, &map));
if (!res && fields->elements)
{
bool saved_abort_on_warning= thd->abort_on_warning;
@@ -2906,7 +2933,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
lex->select_lex.no_wrap_view_item= TRUE;
res= res || check_update_fields(thd, context->table_list,
- *info.update_fields, &map);
+ *info.update_fields, *info.update_values,
+ &map);
lex->select_lex.no_wrap_view_item= FALSE;
/*
When we are not using GROUP BY and there are no ungrouped aggregate functions
@@ -3155,7 +3183,7 @@ bool select_insert::send_eof()
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
- error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0;
+ error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert(0) : 0;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
@@ -3230,7 +3258,7 @@ void select_insert::abort() {
before.
*/
if (!thd->prelocked_mode)
- table->file->ha_end_bulk_insert();
+ table->file->ha_end_bulk_insert(0);
/*
If at least one row has been inserted/modified and will stay in
@@ -3465,6 +3493,12 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
MYSQL_LOCK_IGNORE_FLUSH, &not_used)) ||
hooks->postlock(&table, 1))
{
+ /* purecov: begin tested */
+ /*
+ This can happen in innodb when you get a deadlock when using same table
+ in insert and select
+ */
+ my_error(ER_CANT_LOCK, MYF(0), my_errno);
if (*lock)
{
mysql_unlock_tables(thd, *lock);
@@ -3474,6 +3508,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
if (!create_info->table_existed)
drop_open_table(thd, table, create_table->db, create_table->table_name);
DBUG_RETURN(0);
+ /* purecov: end */
}
DBUG_RETURN(table);
}
@@ -3574,7 +3609,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_RETURN(-1);
}
- /* First field to copy */
+ /* First field to copy */
field= table->field+table->s->fields - values.elements;
/* Mark all fields that are given values */
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 239fb1d49f3..cae8f682a09 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -395,7 +395,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
error= read_sep_field(thd, info, table_list, fields_vars,
set_fields, set_values, read_info,
*enclosed, skip_lines, ignore);
- if (!thd->prelocked_mode && table->file->ha_end_bulk_insert() && !error)
+ if (!thd->prelocked_mode && table->file->ha_end_bulk_insert(0) && !error)
{
table->file->print_error(my_errno, MYF(0));
error= 1;
@@ -558,12 +558,9 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
List_iterator_fast<Item> it(fields_vars);
Item_field *sql_field;
TABLE *table= table_list->table;
- ulonglong id;
bool err;
DBUG_ENTER("read_fixed_length");
- id= 0;
-
while (!read_info.read_fixed_length())
{
if (thd->killed)
@@ -689,12 +686,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
Item *item;
TABLE *table= table_list->table;
uint enclosed_length;
- ulonglong id;
bool err;
DBUG_ENTER("read_sep_field");
enclosed_length=enclosed.length();
- id= 0;
for (;;it.rewind())
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 99b131c3aef..ae9ac38d39f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -28,6 +28,10 @@
#include "events.h"
#include "sql_trigger.h"
+#ifdef WITH_MARIA_STORAGE_ENGINE
+#include "../storage/maria/ha_maria.h"
+#endif
+
/**
@defgroup Runtime_Environment Runtime Environment
@{
@@ -170,6 +174,9 @@ bool end_active_trans(THD *thd)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_commit(thd))
error=1;
+#ifdef WITH_MARIA_STORAGE_ENGINE
+ ha_maria::implicit_commit(thd, TRUE);
+#endif
}
thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
@@ -356,7 +363,7 @@ void init_update_queries(void)
bool is_update_query(enum enum_sql_command command)
{
- DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
+ DBUG_ASSERT(command <= SQLCOM_END);
return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
}
@@ -367,7 +374,7 @@ bool is_update_query(enum enum_sql_command command)
*/
bool is_log_table_write_query(enum enum_sql_command command)
{
- DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
+ DBUG_ASSERT(command <= SQLCOM_END);
return (sql_command_flags[command] & CF_WRITE_LOGS_COMMAND) != 0;
}
@@ -703,6 +710,7 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
xa_state_names[thd->transaction.xid_state.xa_state]);
DBUG_RETURN(1);
}
+ thd->lex->start_transaction_opt= 0; /* for begin_trans() */
switch (completion) {
case COMMIT:
/*
@@ -1219,6 +1227,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *beginning_of_next_stmt= (char*) end_of_stmt;
+#ifdef WITH_MARIA_STORAGE_ENGINE
+ ha_maria::implicit_commit(thd, FALSE);
+#endif
+
net_end_statement(thd);
query_cache_end_of_result(thd);
/*
@@ -1458,7 +1470,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
STATUS_VAR current_global_status_var;
ulong uptime;
+#if defined(SAFEMALLOC) || !defined(EMBEDDED_LIBRARY)
uint length;
+#endif
ulonglong queries_per_second1000;
char buff[250];
uint buff_len= sizeof(buff);
@@ -1471,22 +1485,21 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
else
queries_per_second1000= thd->query_id * LL(1000) / uptime;
- length= my_snprintf((char*) buff, buff_len - 1,
- "Uptime: %lu Threads: %d Questions: %lu "
- "Slow queries: %lu Opens: %lu Flush tables: %lu "
- "Open tables: %u Queries per second avg: %u.%u",
- uptime,
- (int) thread_count, (ulong) thd->query_id,
- current_global_status_var.long_query_count,
- current_global_status_var.opened_tables,
- refresh_version,
- cached_open_tables(),
- (uint) (queries_per_second1000 / 1000),
- (uint) (queries_per_second1000 % 1000));
-#ifdef EMBEDDED_LIBRARY
- /* Store the buffer in permanent memory */
- my_ok(thd, 0, 0, buff);
+#if defined(SAFEMALLOC) || !defined(EMBEDDED_LIBRARY)
+ length=
#endif
+ my_snprintf((char*) buff, buff_len - 1,
+ "Uptime: %lu Threads: %d Questions: %lu "
+ "Slow queries: %lu Opens: %lu Flush tables: %lu "
+ "Open tables: %u Queries per second avg: %u.%u",
+ uptime,
+ (int) thread_count, (ulong) thd->query_id,
+ current_global_status_var.long_query_count,
+ current_global_status_var.opened_tables,
+ refresh_version,
+ cached_open_tables(),
+ (uint) (queries_per_second1000 / 1000),
+ (uint) (queries_per_second1000 % 1000));
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
{
@@ -1497,7 +1510,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(sf_malloc_max_memory+1023L)/1024L);
}
#endif
-#ifndef EMBEDDED_LIBRARY
+#ifdef EMBEDDED_LIBRARY
+ /* Store the buffer in permanent memory */
+ my_ok(thd, 0, 0, buff);
+#else
VOID(my_net_write(net, (uchar*) buff, length));
VOID(net_flush(net));
thd->main_da.disable_status();
@@ -1583,6 +1599,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->mysys_var->abort= 0;
}
+#ifdef WITH_MARIA_STORAGE_ENGINE
+ ha_maria::implicit_commit(thd, FALSE);
+#endif
+
net_end_statement(thd);
query_cache_end_of_result(thd);
@@ -2293,8 +2313,8 @@ mysql_execute_command(THD *thd)
my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES", "enable-profiling");
goto error;
#endif
- break;
}
+ break;
case SQLCOM_SHOW_NEW_MASTER:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
@@ -2741,10 +2761,12 @@ end_with_restore_list:
#endif /* HAVE_REPLICATION */
case SQLCOM_ALTER_TABLE:
- DBUG_ASSERT(first_table == all_tables && first_table != 0);
{
ulong priv=0;
ulong priv_needed= ALTER_ACL;
+
+ DBUG_ASSERT(first_table == all_tables && first_table != 0);
+
/*
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
so we have to use a copy of this structure to make execution
@@ -2754,7 +2776,7 @@ end_with_restore_list:
HA_CREATE_INFO create_info(lex->create_info);
Alter_info alter_info(lex->alter_info, thd->mem_root);
- if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ if (thd->is_fatal_error) /* OOM creating a copy of alter_info */
goto error;
/*
We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
@@ -4842,11 +4864,6 @@ create_sp_error:
if (!(sql_command_flags[lex->sql_command] & CF_HAS_ROW_COUNT))
thd->row_count_func= -1;
- goto finish;
-
-error:
- res= TRUE;
-
finish:
if (need_start_waiting)
{
@@ -4857,6 +4874,11 @@ finish:
start_waiting_global_read_lock(thd);
}
DBUG_RETURN(res || thd->is_error());
+
+error:
+ thd_proc_info(thd, "query end");
+ res= TRUE;
+ goto finish;
}
@@ -5045,8 +5067,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
(see SQLCOM_GRANT case, mysql_execute_command() function) and
set db_is_pattern according to 'dont_check_global_grants' value.
*/
- bool db_is_pattern= (test(want_access & GRANT_ACL) &&
- dont_check_global_grants);
+ bool db_is_pattern= ((want_access & GRANT_ACL) && dont_check_global_grants);
ulong dummy;
DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
@@ -5524,6 +5545,7 @@ void mysql_reset_thd_for_next_command(THD *thd)
DBUG_ENTER("mysql_reset_thd_for_next_command");
DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */
DBUG_ASSERT(! thd->in_sub_stmt);
+ DBUG_ASSERT(thd->transaction.on);
thd->free_list= 0;
thd->select_number= 1;
/*
@@ -7541,15 +7563,14 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg,
/*
Check if path does not contain mysql data home directory
+
SYNOPSIS
test_if_data_home_dir()
dir directory
- conv_home_dir converted data home directory
- home_dir_len converted data home directory length
RETURN VALUES
0 ok
- 1 error
+ 1 error ; Given path contains data directory
*/
C_MODE_START
@@ -7577,11 +7598,17 @@ int test_if_data_home_dir(const char *dir)
mysql_unpacked_real_data_home_len,
(const uchar*) mysql_unpacked_real_data_home,
mysql_unpacked_real_data_home_len))
+ {
+ DBUG_PRINT("error", ("Path is part of mysql_real_data_home"));
DBUG_RETURN(1);
+ }
}
else if (!memcmp(path, mysql_unpacked_real_data_home,
mysql_unpacked_real_data_home_len))
+ {
+ DBUG_PRINT("error", ("Path is part of mysql_real_data_home"));
DBUG_RETURN(1);
+ }
}
DBUG_RETURN(0);
}
@@ -7642,6 +7669,7 @@ bool parse_sql(THD *thd,
Parser_state *parser_state,
Object_creation_ctx *creation_ctx)
{
+ bool mysql_parse_status;
DBUG_ASSERT(thd->m_parser_state == NULL);
/* Backup creation context. */
@@ -7657,7 +7685,7 @@ bool parse_sql(THD *thd,
/* Parse the query. */
- bool mysql_parse_status= MYSQLparse(thd) != 0;
+ mysql_parse_status= MYSQLparse(thd) != 0;
/* Check that if MYSQLparse() failed, thd->is_error() is set. */
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 0df1631294b..e73e65dc38f 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -635,7 +635,7 @@ static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc CALLER_INFO_PROTO)
*plugin= pi;
#endif
pi->ref_count++;
- DBUG_PRINT("info",("thd: 0x%lx, plugin: \"%s\", ref_count: %d",
+ DBUG_PRINT("info",("thd: 0x%lx plugin: \"%s\" ref_count: %d",
(long) current_thd, pi->name.str, pi->ref_count));
if (lex)
@@ -2607,7 +2607,7 @@ TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
default:
return NULL;
}
- return NULL;
+ return NULL; /* Keep compiler happy */
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 7fcc374e3f3..1a93d8d5099 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1122,6 +1122,8 @@ static bool mysql_test_insert(Prepared_statement *stmt,
if (insert_precheck(thd, table_list))
goto error;
+ upgrade_lock_type_for_insert(thd, &table_list->lock_type, duplic,
+ values_list.elements > 1);
/*
open temporary memory pool for temporary data allocated by derived
tables & preparation procedure
@@ -2462,7 +2464,6 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
DBUG_VOID_RETURN;
-
}
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index cb5b3722559..320360b2587 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -38,9 +38,6 @@
#define MAX_QUERY_LENGTH 300
-/* Reserved for systems that can't record the function name in source. */
-const char * const _unknown_func_ = "<unknown>";
-
/**
Connects Information_Schema and Profiling.
*/
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
index b5537487d26..3ddec4e3811 100644
--- a/sql/sql_profile.h
+++ b/sql/sql_profile.h
@@ -16,27 +16,6 @@
#ifndef _SQL_PROFILE_H
#define _SQL_PROFILE_H
-#if __STDC_VERSION__ < 199901L
-# if __GNUC__ >= 2
-# define __func__ __FUNCTION__
-# else
-# define __func__ _unknown_func_
-extern const char * const _unknown_func_;
-# endif
-#elif defined(_MSC_VER)
-# if _MSC_VER < 1300
-# define __func__ _unknown_func_
-extern const char * const _unknown_func_;
-# else
-# define __func__ __FUNCTION__
-# endif
-#elif defined(__BORLANDC__)
-# define __func__ __FUNC__
-#else
-# define __func__ _unknown_func_
-extern const char * const _unknown_func_;
-#endif
-
extern ST_FIELD_INFO query_profile_statistics_info[];
int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 81db5469891..14088961ea2 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1605,7 +1605,7 @@ bool show_binlogs(THD* thd)
if (!mysql_bin_log.is_open())
{
my_message(ER_NO_BINARY_LOGGING, ER(ER_NO_BINARY_LOGGING), MYF(0));
- return 1;
+ DBUG_RETURN(TRUE);
}
field_list.push_back(new Item_empty_string("Log_name", 255));
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 90a5c5c4c8b..0e3856240ca 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -31,11 +31,16 @@
#include "mysql_priv.h"
#include "sql_select.h"
#include "sql_cursor.h"
-
#include <m_ctype.h>
#include <my_bit.h>
#include <hash.h>
#include <ft_global.h>
+#if defined(WITH_MARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES)
+#include "../storage/maria/ha_maria.h"
+#define TMP_ENGINE_HTON maria_hton
+#else
+#define TMP_ENGINE_HTON myisam_hton
+#endif
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext",
@@ -120,8 +125,13 @@ static COND *optimize_cond(JOIN *join, COND *conds,
Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table);
-static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
- ulonglong options);
+static bool create_internal_tmp_table(TABLE *,TMP_TABLE_PARAM *, ulonglong);
+static bool create_internal_tmp_table_from_heap2(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ int error,
+ bool ignore_last_dupp,
+ handlerton *hton,
+ const char *proc_info);
static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table,
Procedure *proc);
@@ -1808,7 +1818,10 @@ JOIN::exec()
curr_join->having= curr_join->tmp_having= 0; // Allready done
/* Change sum_fields reference to calculated fields in tmp_table */
- curr_join->all_fields= *curr_all_fields;
+#ifdef HAVE_purify
+ if (curr_join != this)
+#endif
+ curr_join->all_fields= *curr_all_fields;
if (!items1)
{
items1= items0 + all_fields.elements;
@@ -1827,8 +1840,13 @@ JOIN::exec()
fields_list.elements, all_fields))
DBUG_VOID_RETURN;
}
- curr_join->tmp_all_fields1= tmp_all_fields1;
- curr_join->tmp_fields_list1= tmp_fields_list1;
+#ifdef HAVE_purify
+ if (curr_join != this)
+#endif
+ {
+ curr_join->tmp_all_fields1= tmp_all_fields1;
+ curr_join->tmp_fields_list1= tmp_fields_list1;
+ }
curr_join->items1= items1;
}
curr_all_fields= &tmp_all_fields1;
@@ -2032,8 +2050,13 @@ JOIN::exec()
tmp_table_param.save_copy_field= curr_join->tmp_table_param.copy_field;
tmp_table_param.save_copy_field_end=
curr_join->tmp_table_param.copy_field_end;
- curr_join->tmp_all_fields3= tmp_all_fields3;
- curr_join->tmp_fields_list3= tmp_fields_list3;
+#ifdef HAVE_purify
+ if (curr_join != this)
+#endif
+ {
+ curr_join->tmp_all_fields3= tmp_all_fields3;
+ curr_join->tmp_fields_list3= tmp_fields_list3;
+ }
}
else
{
@@ -2502,11 +2525,10 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
table->pos_in_table_list= tables;
- error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
- if(error)
+ if ((error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK)))
{
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(1);
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(1);
}
table->quick_keys.clear_all();
table->reginfo.join_tab=s;
@@ -3542,16 +3564,16 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
Item_func *arg0=(Item_func *)(func->arguments()[0]),
*arg1=(Item_func *)(func->arguments()[1]);
if (arg1->const_item() &&
- ((functype == Item_func::GE_FUNC && arg1->val_real() > 0) ||
- (functype == Item_func::GT_FUNC && arg1->val_real() >=0)) &&
arg0->type() == Item::FUNC_ITEM &&
- arg0->functype() == Item_func::FT_FUNC)
+ arg0->functype() == Item_func::FT_FUNC &&
+ ((functype == Item_func::GE_FUNC && arg1->val_real() > 0) ||
+ (functype == Item_func::GT_FUNC && arg1->val_real() >=0)))
cond_func=(Item_func_match *) arg0;
else if (arg0->const_item() &&
- ((functype == Item_func::LE_FUNC && arg0->val_real() > 0) ||
- (functype == Item_func::LT_FUNC && arg0->val_real() >=0)) &&
arg1->type() == Item::FUNC_ITEM &&
- arg1->functype() == Item_func::FT_FUNC)
+ arg1->functype() == Item_func::FT_FUNC &&
+ ((functype == Item_func::LE_FUNC && arg0->val_real() > 0) ||
+ (functype == Item_func::LT_FUNC && arg0->val_real() >=0)))
cond_func=(Item_func_match *) arg1;
}
}
@@ -9665,7 +9687,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
KEY *keyinfo;
KEY_PART_INFO *key_part_info;
Item **copy_func;
- MI_COLUMNDEF *recinfo;
+ ENGINE_COLUMNDEF *recinfo;
uint total_uneven_bit_length= 0;
bool force_copy_fields= param->force_copy_fields;
/* Treat sum functions as normal ones when loose index scan is used. */
@@ -9693,11 +9715,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
/*
No need to change table name to lower case as we are only creating
- MyISAM or HEAP tables here
+ MyISAM, Maria or HEAP tables here
*/
fn_format(path, path, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME);
-
if (group)
{
if (!param->quick_group)
@@ -9789,7 +9810,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
init_tmp_table_share(thd, share, "", 0, tmpname, tmpname);
share->blob_field= blob_field;
share->blob_ptr_size= portable_sizeof_char_ptr;
- share->db_low_byte_first=1; // True for HEAP and MyISAM
+ share->db_low_byte_first=1; // True for HEAP, MyISAM and Maria
share->table_charset= param->table_charset;
share->primary_key= MAX_KEY; // Indicate no primary key
share->keys_for_keyread.init();
@@ -9921,6 +9942,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*blob_field++= fieldnr;
blob_count++;
}
+ if (new_field->real_type() == MYSQL_TYPE_STRING ||
+ new_field->real_type() == MYSQL_TYPE_VARCHAR)
+ {
+ string_count++;
+ string_total_length+= new_field->pack_length();
+ }
if (item->marker == 4 && item->maybe_null)
{
group_null_items++;
@@ -9957,7 +9984,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM))
{
- share->db_plugin= ha_lock_engine(0, myisam_hton);
+ share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON);
table->file= get_new_handler(share, &table->mem_root,
share->db_type());
if (group &&
@@ -9974,7 +10001,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!table->file)
goto err;
-
if (!using_unique_constraint)
reclength+= group_null_items; // null flag is stored separately
@@ -10110,13 +10136,16 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
/* Make entry for create table */
recinfo->length=length;
if (field->flags & BLOB_FLAG)
- recinfo->type= (int) FIELD_BLOB;
+ recinfo->type= FIELD_BLOB;
else if (use_packed_rows &&
field->real_type() == MYSQL_TYPE_STRING &&
length >= MIN_STRING_LENGTH_TO_PACK_ROWS)
- recinfo->type=FIELD_SKIP_ENDSPACE;
+ recinfo->type= FIELD_SKIP_ENDSPACE;
+ else if (field->real_type() == MYSQL_TYPE_VARCHAR)
+ recinfo->type= FIELD_VARCHAR;
else
- recinfo->type=FIELD_NORMAL;
+ recinfo->type= FIELD_NORMAL;
+
if (!--hidden_field_count)
null_count=(null_count+7) & ~7; // move to next byte
@@ -10279,9 +10308,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (thd->is_fatal_error) // If end of memory
goto err; /* purecov: inspected */
share->db_record_offset= 1;
- if (share->db_type() == myisam_hton)
+ if (share->db_type() == TMP_ENGINE_HTON)
{
- if (create_myisam_tmp_table(table,param,select_options))
+ if (create_internal_tmp_table(table,param,select_options))
goto err;
}
if (open_tmp_table(table))
@@ -10443,15 +10472,149 @@ static bool open_tmp_table(TABLE *table)
}
-static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
- ulonglong options)
+#if defined(WITH_MARIA_STORAGE_ENGINE) && defined(USE_MARIA_FOR_TMP_TABLES)
+
+/* Create internal Maria temporary table */
+
+static bool create_internal_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
+ ulonglong options)
+{
+ int error;
+ MARIA_KEYDEF keydef;
+ MARIA_UNIQUEDEF uniquedef;
+ KEY *keyinfo=param->keyinfo;
+ TABLE_SHARE *share= table->s;
+ MARIA_CREATE_INFO create_info;
+ DBUG_ENTER("create_internal_tmp_table");
+
+ if (share->keys)
+ { // Get keys for ni_create
+ bool using_unique_constraint=0;
+ HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root,
+ sizeof(*seg) * keyinfo->key_parts);
+ if (!seg)
+ goto err;
+
+ bzero(seg, sizeof(*seg) * keyinfo->key_parts);
+ if (keyinfo->key_length >= table->file->max_key_length() ||
+ keyinfo->key_parts > table->file->max_key_parts() ||
+ share->uniques)
+ {
+ /* Can't create a key; Make a unique constraint instead of a key */
+ share->keys= 0;
+ share->uniques= 1;
+ using_unique_constraint=1;
+ bzero((char*) &uniquedef,sizeof(uniquedef));
+ uniquedef.keysegs=keyinfo->key_parts;
+ uniquedef.seg=seg;
+ uniquedef.null_are_equal=1;
+
+ /* Create extra column for hash value */
+ bzero((uchar*) param->recinfo,sizeof(*param->recinfo));
+ param->recinfo->type= FIELD_CHECK;
+ param->recinfo->length= MARIA_UNIQUE_HASH_LENGTH;
+ param->recinfo++;
+ share->reclength+= MARIA_UNIQUE_HASH_LENGTH;
+ }
+ else
+ {
+ /* Create an unique key */
+ bzero((char*) &keydef,sizeof(keydef));
+ keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
+ keydef.keysegs= keyinfo->key_parts;
+ keydef.seg= seg;
+ }
+ for (uint i=0; i < keyinfo->key_parts ; i++,seg++)
+ {
+ Field *field=keyinfo->key_part[i].field;
+ seg->flag= 0;
+ seg->language= field->charset()->number;
+ seg->length= keyinfo->key_part[i].length;
+ seg->start= keyinfo->key_part[i].offset;
+ if (field->flags & BLOB_FLAG)
+ {
+ seg->type=
+ ((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ?
+ HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2);
+ seg->bit_start= (uint8)(field->pack_length() - share->blob_ptr_size);
+ seg->flag= HA_BLOB_PART;
+ seg->length=0; // Whole blob in unique constraint
+ }
+ else
+ {
+ seg->type= keyinfo->key_part[i].type;
+ /* Tell handler if it can do suffic space compression */
+ if (field->real_type() == MYSQL_TYPE_STRING &&
+ keyinfo->key_part[i].length > 4)
+ seg->flag|= HA_SPACE_PACK;
+ }
+ if (!(field->flags & NOT_NULL_FLAG))
+ {
+ seg->null_bit= field->null_bit;
+ seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
+ /*
+ We are using a GROUP BY on something that contains NULL
+ In this case we have to tell Maria that two NULL should
+ on INSERT be regarded at the same value
+ */
+ if (!using_unique_constraint)
+ keydef.flag|= HA_NULL_ARE_EQUAL;
+ }
+ }
+ }
+ bzero((char*) &create_info,sizeof(create_info));
+
+ if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
+ OPTION_BIG_TABLES)
+ create_info.data_file_length= ~(ulonglong) 0;
+
+ if ((error= maria_create(share->table_name.str,
+ share->reclength < 64 &&
+ !share->blob_fields ? STATIC_RECORD :
+ BLOCK_RECORD,
+ share->keys, &keydef,
+ (uint) (param->recinfo-param->start_recinfo),
+ param->start_recinfo,
+ share->uniques, &uniquedef,
+ &create_info,
+ HA_CREATE_TMP_TABLE)))
+ {
+ table->file->print_error(error,MYF(0)); /* purecov: inspected */
+ table->db_stat=0;
+ goto err;
+ }
+ status_var_increment(table->in_use->status_var.created_tmp_disk_tables);
+ share->db_record_offset= 1;
+ DBUG_RETURN(0);
+ err:
+ DBUG_RETURN(1);
+}
+
+
+bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ int error,
+ bool ignore_last_dupp_key_error)
+{
+ return create_internal_tmp_table_from_heap2(thd, table, param, error,
+ ignore_last_dupp_key_error,
+ maria_hton,
+ "converting HEAP to Maria");
+}
+
+#else
+
+/* Create internal MyISAM temporary table */
+
+static bool create_internal_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
+ ulonglong options)
{
int error;
MI_KEYDEF keydef;
MI_UNIQUEDEF uniquedef;
KEY *keyinfo=param->keyinfo;
TABLE_SHARE *share= table->s;
- DBUG_ENTER("create_myisam_tmp_table");
+ DBUG_ENTER("create_internal_tmp_table");
if (share->keys)
{ // Get keys for ni_create
@@ -10554,55 +10717,43 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
}
-void
-free_tmp_table(THD *thd, TABLE *entry)
-{
- MEM_ROOT own_root= entry->mem_root;
- const char *save_proc_info;
- DBUG_ENTER("free_tmp_table");
- DBUG_PRINT("enter",("table: %s",entry->alias));
-
- save_proc_info=thd->proc_info;
- thd_proc_info(thd, "removing tmp table");
-
- if (entry->file)
- {
- if (entry->db_stat)
- entry->file->ha_drop_table(entry->s->table_name.str);
- else
- entry->file->ha_delete_table(entry->s->table_name.str);
- delete entry->file;
- }
-
- /* free blobs */
- for (Field **ptr=entry->field ; *ptr ; ptr++)
- (*ptr)->free();
- free_io_cache(entry);
-
- if (entry->temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot);
+/**
+ If a HEAP table gets full, create a MyISAM table and copy all rows to this
+*/
- plugin_unlock(0, entry->s->db_plugin);
+bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ int error,
+ bool ignore_last_dupp_key_error)
+{
+ return create_internal_tmp_table_from_heap2(thd, table, param, error,
+ ignore_last_dupp_key_error,
+ myisam_hton,
+ "converting HEAP to MyISAM");
+}
- free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
- thd_proc_info(thd, save_proc_info);
+#endif /* WITH_MARIA_STORAGE_ENGINE */
- DBUG_VOID_RETURN;
-}
-/**
- If a HEAP table gets full, create a MyISAM table and copy all rows
- to this.
+/*
+ If a HEAP table gets full, create a internal table in MyISAM or Maria
+ and copy all rows to this
*/
-bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
- int error, bool ignore_last_dupp_key_error)
+
+static bool
+create_internal_tmp_table_from_heap2(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ int error,
+ bool ignore_last_dupp_key_error,
+ handlerton *hton,
+ const char *proc_info)
{
TABLE new_table;
TABLE_SHARE share;
const char *save_proc_info;
int write_err;
- DBUG_ENTER("create_myisam_from_heap");
+ DBUG_ENTER("create_internal_tmp_table_from_heap2");
if (table->s->db_type() != heap_hton ||
error != HA_ERR_RECORD_FILE_FULL)
@@ -10613,15 +10764,15 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
new_table= *table;
share= *table->s;
new_table.s= &share;
- new_table.s->db_plugin= ha_lock_engine(thd, myisam_hton);
+ new_table.s->db_plugin= ha_lock_engine(thd, hton);
if (!(new_table.file= get_new_handler(&share, &new_table.mem_root,
new_table.s->db_type())))
DBUG_RETURN(1); // End of memory
save_proc_info=thd->proc_info;
- thd_proc_info(thd, "converting HEAP to MyISAM");
+ thd_proc_info(thd, proc_info);
- if (create_myisam_tmp_table(&new_table, param,
+ if (create_internal_tmp_table(&new_table, param,
thd->lex->select_lex.options | thd->options))
goto err2;
if (open_tmp_table(&new_table))
@@ -10684,7 +10835,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
table->use_all_columns();
if (save_proc_info)
thd_proc_info(thd, (!strcmp(save_proc_info,"Copying to tmp table") ?
- "Copying to tmp table on disk" : save_proc_info));
+ "Copying to tmp table on disk" : save_proc_info));
DBUG_RETURN(0);
err:
@@ -10702,6 +10853,43 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
}
+void
+free_tmp_table(THD *thd, TABLE *entry)
+{
+ MEM_ROOT own_root= entry->mem_root;
+ const char *save_proc_info;
+ DBUG_ENTER("free_tmp_table");
+ DBUG_PRINT("enter",("table: %s",entry->alias));
+
+ save_proc_info=thd->proc_info;
+ thd_proc_info(thd, "removing tmp table");
+
+ if (entry->file)
+ {
+ if (entry->db_stat)
+ entry->file->ha_drop_table(entry->s->table_name.str);
+ else
+ entry->file->ha_delete_table(entry->s->table_name.str);
+ delete entry->file;
+ }
+
+ /* free blobs */
+ for (Field **ptr=entry->field ; *ptr ; ptr++)
+ (*ptr)->free();
+ free_io_cache(entry);
+
+ if (entry->temp_pool_slot != MY_BIT_NONE)
+ bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot);
+
+ plugin_unlock(0, entry->s->db_plugin);
+
+ free_root(&own_root, MYF(0)); /* the table is allocated in its own root */
+ thd_proc_info(thd, save_proc_info);
+
+ DBUG_VOID_RETURN;
+}
+
+
/**
@details
Rows produced by a join sweep may end up in a temporary table or be sent
@@ -11437,6 +11625,11 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}
+ /*
+ The optimizer trust the engine that when stats.records is 0, there
+ was no found rows
+ */
+ DBUG_ASSERT(table->file->stats.records > 0 || error);
}
else
{
@@ -11466,6 +11659,17 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
}
if (*tab->on_expr_ref && !table->null_row)
{
+#if !defined(DBUG_OFF) && defined(NOT_USING_ITEM_EQUAL)
+ /*
+ This test could be very usefull to find bugs in the optimizer
+ where we would call this function with an expression that can't be
+ evaluated yet. We can't have this enabled by default as long as
+ have items like Item_equal, that doesn't report they are const but
+ they can still be called even if they contain not const items.
+ */
+ (*tab->on_expr_ref)->update_used_tables();
+ DBUG_ASSERT((*tab->on_expr_ref)->const_item());
+#endif
if ((table->null_row= test((*tab->on_expr_ref)->val_int() == 0)))
mark_as_null_row(table);
}
@@ -12160,7 +12364,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if (!table->file->is_fatal_error(error, HA_CHECK_DUP))
goto end;
- if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
+ if (create_internal_tmp_table_from_heap(join->thd, table, &join->tmp_table_param,
error,1))
DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error
table->s->uniques=0; // To ensure rows are the same
@@ -12244,7 +12448,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
copy_funcs(join->tmp_table_param.items_to_copy);
if ((error=table->file->ha_write_row(table->record[0])))
{
- if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
+ if (create_internal_tmp_table_from_heap(join->thd, table, &join->tmp_table_param,
error, 0))
DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error
/* Change method to update rows */
@@ -12339,7 +12543,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!join->having || join->having->val_int())
{
int error= table->file->ha_write_row(table->record[0]);
- if (error && create_myisam_from_heap(join->thd, table,
+ if (error && create_internal_tmp_table_from_heap(join->thd, table,
&join->tmp_table_param,
error, 0))
DBUG_RETURN(NESTED_LOOP_ERROR);
@@ -13655,13 +13859,14 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
else if (!found)
{
found=1;
- file->position(record); // Remember position
+ if ((error= file->remember_rnd_pos()))
+ goto err;
}
}
if (!found)
break; // End of file
- /* Restart search on next row */
- error=file->restart_rnd_next(record,file->ref);
+ /* Restart search on saved row */
+ error=file->restart_rnd_next(record);
}
file->extra(HA_EXTRA_NO_CACHE);
@@ -15804,7 +16009,7 @@ int JOIN::rollup_write_data(uint idx, TABLE *table_arg)
copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]);
if ((write_error= table_arg->file->ha_write_row(table_arg->record[0])))
{
- if (create_myisam_from_heap(thd, table_arg, &tmp_table_param,
+ if (create_internal_tmp_table_from_heap(thd, table_arg, &tmp_table_param,
write_error, 0))
return 1;
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index c5961f097c2..eacd3d39905 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -463,7 +463,8 @@ public:
group_optimized_away= 0;
all_fields= fields_arg;
- fields_list= fields_arg;
+ if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
+ fields_list= fields_arg;
bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.init();
tmp_table_param.end_write_records= HA_POS_ERROR;
@@ -551,7 +552,7 @@ bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
uint elements, List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item **func_ptr);
-bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
+bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
int error, bool ignore_last_dupp_error);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
Field* create_tmp_field_from_field(THD *thd, Field* org_field,
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 3c4dc103ddd..8ae2787dc1a 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -173,15 +173,15 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin,
switch (plug->license) {
case PLUGIN_LICENSE_GPL:
- table->field[9]->store(PLUGIN_LICENSE_GPL_STRING,
+ table->field[9]->store(PLUGIN_LICENSE_GPL_STRING,
strlen(PLUGIN_LICENSE_GPL_STRING), cs);
break;
case PLUGIN_LICENSE_BSD:
- table->field[9]->store(PLUGIN_LICENSE_BSD_STRING,
+ table->field[9]->store(PLUGIN_LICENSE_BSD_STRING,
strlen(PLUGIN_LICENSE_BSD_STRING), cs);
break;
default:
- table->field[9]->store(PLUGIN_LICENSE_PROPRIETARY_STRING,
+ table->field[9]->store(PLUGIN_LICENSE_PROPRIETARY_STRING,
strlen(PLUGIN_LICENSE_PROPRIETARY_STRING), cs);
break;
}
@@ -492,7 +492,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
file=dirp->dir_entry+i;
if (dir)
{ /* Return databases */
- if ((file->name[0] == '.' &&
+ if ((file->name[0] == '.' &&
((file->name[1] == '.' && file->name[2] == '\0') ||
file->name[1] == '\0')))
continue; /* . or .. */
@@ -518,7 +518,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
if (wild && wild_compare(uname, wild, 0))
continue;
- if (!(file_name=
+ if (!(file_name=
thd->make_lex_string(file_name, uname, file_name_len, TRUE)))
{
my_dirend(dirp);
@@ -557,7 +557,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db,
continue;
}
#endif
- if (!(file_name=
+ if (!(file_name=
thd->make_lex_string(file_name, uname, file_name_len, TRUE)) ||
files->push_back(file_name))
{
@@ -596,7 +596,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
/*
Clear all messages with 'error' level status and
- issue a warning with 'warning' level status in
+ issue a warning with 'warning' level status in
case of invalid view and last error is ER_VIEW_INVALID
*/
mysql_reset_errors(thd, true);
@@ -787,7 +787,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
Field **ptr,*field;
for (ptr=table->field ; (field= *ptr); ptr++)
{
- if (!wild || !wild[0] ||
+ if (!wild || !wild[0] ||
!wild_case_compare(system_charset_info, field->field_name,wild))
{
if (table_list->view)
@@ -1002,7 +1002,7 @@ static bool get_field_default_value(THD *thd, TABLE *table,
We are using CURRENT_TIMESTAMP instead of NOW because it is
more standard
*/
- has_now_default= table->timestamp_field == field &&
+ has_now_default= table->timestamp_field == field &&
field->unireg_check != Field::TIMESTAMP_UN_FIELD;
has_default= (field_type != FIELD_TYPE_BLOB &&
@@ -1071,11 +1071,11 @@ static bool get_field_default_value(THD *thd, TABLE *table,
to tailor the format of the statement. Can be
NULL, in which case only SQL_MODE is considered
when building the statement.
-
+
NOTE
Currently always return 0, but might return error code in the
future.
-
+
RETURN
0 OK
*/
@@ -1176,7 +1176,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
field->sql_type(type);
packet->append(type.ptr(), type.length(), system_charset_info);
- if (field->has_charset() &&
+ if (field->has_charset() &&
!(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)))
{
if (field->charset() != share->table_charset)
@@ -1184,8 +1184,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN(" CHARACTER SET "));
packet->append(field->charset()->csname);
}
- /*
- For string types dump collation name only if
+ /*
+ For string types dump collation name only if
collation is not primary for the given charset
*/
if (!(field->charset()->state & MY_CS_PRIMARY))
@@ -1212,11 +1212,11 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(def_value.ptr(), def_value.length(), system_charset_info);
}
- if (!limited_mysql_mode && table->timestamp_field == field &&
+ if (!limited_mysql_mode && table->timestamp_field == field &&
field->unireg_check != Field::TIMESTAMP_DN_FIELD)
packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP"));
- if (field->unireg_check == Field::NEXT_NUMBER &&
+ if (field->unireg_check == Field::NEXT_NUMBER &&
!(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS))
packet->append(STRING_WITH_LEN(" AUTO_INCREMENT"));
@@ -1229,8 +1229,10 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
key_info= table->key_info;
bzero((char*) &create_info, sizeof(create_info));
- /* Allow update_create_info to update row type */
+ /* Allow update_create_info to update row type, page checksums and options */
create_info.row_type= share->row_type;
+ create_info.page_checksum= share->page_checksum;
+ create_info.options= share->db_create_options;
file->update_create_info(&create_info);
primary_key= share->primary_key;
@@ -1365,7 +1367,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(buff, (uint) (end - buff));
}
-
+
if (share->table_charset &&
!(thd->variables.sql_mode & MODE_MYSQL323) &&
!(thd->variables.sql_mode & MODE_MYSQL40))
@@ -1411,19 +1413,19 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(buff, (uint) (end - buff));
}
- if (share->db_create_options & HA_OPTION_PACK_KEYS)
+ if (create_info.options & HA_OPTION_PACK_KEYS)
packet->append(STRING_WITH_LEN(" PACK_KEYS=1"));
- if (share->db_create_options & HA_OPTION_NO_PACK_KEYS)
+ if (create_info.options & HA_OPTION_NO_PACK_KEYS)
packet->append(STRING_WITH_LEN(" PACK_KEYS=0"));
/* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */
- if (share->db_create_options & HA_OPTION_CHECKSUM)
+ if (create_info.options & HA_OPTION_CHECKSUM)
packet->append(STRING_WITH_LEN(" CHECKSUM=1"));
- if (share->page_checksum != HA_CHOICE_UNDEF)
+ if (create_info.page_checksum != HA_CHOICE_UNDEF)
{
packet->append(STRING_WITH_LEN(" PAGE_CHECKSUM="));
- packet->append(ha_choice_values[(uint) share->page_checksum], 1);
+ packet->append(ha_choice_values[create_info.page_checksum], 1);
}
- if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
+ if (create_info.options & HA_OPTION_DELAY_KEY_WRITE)
packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1"));
if (create_info.row_type != ROW_TYPE_DEFAULT)
{
@@ -1536,7 +1538,7 @@ view_store_options(THD *thd, TABLE_LIST *table, String *buff)
/*
Append DEFINER clause to the given buffer.
-
+
SYNOPSIS
append_definer()
thd [in] thread handle
@@ -1565,7 +1567,7 @@ static void append_algorithm(TABLE_LIST *table, String *buff)
/*
Append DEFINER clause to the given buffer.
-
+
SYNOPSIS
append_definer()
thd [in] thread handle
@@ -1725,8 +1727,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
"%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
}
else
- thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ?
- tmp_sctx->host_or_ip :
+ thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ?
+ tmp_sctx->host_or_ip :
tmp_sctx->host ? tmp_sctx->host : "");
if ((thd_info->db=tmp->db)) // Safe test
thd_info->db=thd->strdup(thd_info->db);
@@ -1755,7 +1757,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thd_info->query=0;
if (tmp->query)
{
- /*
+ /*
query_length is always set to 0 when we set query = NULL; see
the comment in sql_class.h why this prevents crashes in possible
races with query_length
@@ -2002,7 +2004,7 @@ void reset_status_vars()
/* Note that SHOW_LONG_NOFLUSH variables are not reset */
if (ptr->type == SHOW_LONG)
*(ulong*) ptr->value= 0;
- }
+ }
}
/*
@@ -2149,7 +2151,6 @@ static bool show_status_array(THD *thd, const char *wild,
const char *pos, *end; // We assign a lot of const's
pthread_mutex_lock(&LOCK_global_system_variables);
-
if (show_type == SHOW_SYS)
{
sys_var *var= ((sys_var *) value);
@@ -2165,20 +2166,20 @@ static bool show_status_array(THD *thd, const char *wild,
*/
switch (show_type) {
case SHOW_DOUBLE_STATUS:
- value= ((char *) status_var + (ulong) value);
+ value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_DOUBLE:
end= buff + my_sprintf(buff, (buff, "%f", *(double*) value));
break;
case SHOW_LONG_STATUS:
- value= ((char *) status_var + (ulong) value);
+ value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_LONG:
case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
end= int10_to_str(*(long*) value, buff, 10);
break;
case SHOW_LONGLONG_STATUS:
- value= ((char *) status_var + (ulonglong) value);
+ value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_LONGLONG:
end= longlong10_to_str(*(longlong*) value, buff, 10);
@@ -2231,12 +2232,11 @@ static bool show_status_array(THD *thd, const char *wild,
DBUG_ASSERT(0);
break;
}
+ pthread_mutex_unlock(&LOCK_global_system_variables);
table->field[1]->store(pos, (uint32) (end - pos), charset);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
table->field[1]->set_notnull();
- pthread_mutex_unlock(&LOCK_global_system_variables);
-
if (schema_table_store_record(thd, table))
{
res= TRUE;
@@ -2262,14 +2262,14 @@ void calc_sum_of_all_status(STATUS_VAR *to)
I_List_iterator<THD> it(threads);
THD *tmp;
-
+
/* Get global values as base */
*to= global_status_var;
-
+
/* Add to this status from existing threads */
while ((tmp= it++))
add_to_status(to, &tmp->status_var);
-
+
VOID(pthread_mutex_unlock(&LOCK_thread_count));
DBUG_VOID_RETURN;
}
@@ -2304,7 +2304,7 @@ bool schema_table_store_record(THD *thd, TABLE *table)
int error;
if ((error= table->file->ha_write_row(table->record[0])))
{
- if (create_myisam_from_heap(thd, table,
+ if (create_internal_tmp_table_from_heap(thd, table,
table->pos_in_table_list->schema_table_param,
error, 0))
return 1;
@@ -2326,17 +2326,17 @@ int make_table_list(THD *thd, SELECT_LEX *sel,
/**
- @brief Get lookup value from the part of 'WHERE' condition
+ @brief Get lookup value from the part of 'WHERE' condition
- @details This function gets lookup value from
- the part of 'WHERE' condition if it's possible and
+ @details This function gets lookup value from
+ the part of 'WHERE' condition if it's possible and
fill appropriate lookup_field_vals struct field
with this value.
@param[in] thd thread handler
@param[in] item_func part of WHERE condition
@param[in] table I_S table
- @param[in, out] lookup_field_vals Struct which holds lookup values
+ @param[in, out] lookup_field_vals Struct which holds lookup values
@return
0 success
@@ -2344,7 +2344,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel,
*/
bool get_lookup_value(THD *thd, Item_func *item_func,
- TABLE_LIST *table,
+ TABLE_LIST *table,
LOOKUP_FIELD_VALUES *lookup_field_vals)
{
ST_SCHEMA_TABLE *schema_table= table->schema_table;
@@ -2410,16 +2410,16 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
/**
- @brief Calculates lookup values from 'WHERE' condition
+ @brief Calculates lookup values from 'WHERE' condition
@details This function calculates lookup value(database name, table name)
- from 'WHERE' condition if it's possible and
+ from 'WHERE' condition if it's possible and
fill lookup_field_vals struct fields with these values.
@param[in] thd thread handler
@param[in] cond WHERE condition
@param[in] table I_S table
- @param[in, out] lookup_field_vals Struct which holds lookup values
+ @param[in, out] lookup_field_vals Struct which holds lookup values
@return
0 success
@@ -2568,7 +2568,7 @@ static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table)
@param[in] thd thread handler
@param[in] cond WHERE condition
@param[in] tables I_S table
- @param[in, out] lookup_field_values Struct which holds lookup values
+ @param[in, out] lookup_field_values Struct which holds lookup values
@return
0 success
@@ -2630,7 +2630,7 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table)
idx_field_vals idx_field_vals->db_name contains db name or
wild string
with_i_schema returns 1 if we added 'IS' name to list
- otherwise returns 0
+ otherwise returns 0
RETURN
zero success
@@ -2654,7 +2654,7 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
LIKE clause (see also get_index_field_values() function)
*/
if (!lookup_field_vals->db_value.str ||
- !wild_case_compare(system_charset_info,
+ !wild_case_compare(system_charset_info,
INFORMATION_SCHEMA_NAME.str,
lookup_field_vals->db_value.str))
{
@@ -2698,7 +2698,7 @@ int make_db_list(THD *thd, List<LEX_STRING> *files,
}
-struct st_add_schema_table
+struct st_add_schema_table
{
List<LEX_STRING> *files;
const char *wild;
@@ -2762,7 +2762,7 @@ int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild)
else if (wild_compare(tmp_schema_table->table_name, wild, 0))
continue;
}
- if ((file_name=
+ if ((file_name=
thd->make_lex_string(file_name, tmp_schema_table->table_name,
strlen(tmp_schema_table->table_name), TRUE)) &&
!files->push_back(file_name))
@@ -2818,7 +2818,7 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
}
}
else
- {
+ {
if (table_names->push_back(&lookup_field_vals->table_value))
return 1;
/*
@@ -2879,7 +2879,7 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
@retval 1 error
*/
-static int
+static int
fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
ST_SCHEMA_TABLE *schema_table,
Open_tables_state *open_tables_state_backup)
@@ -2906,7 +2906,7 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
Let us set fake sql_command so views won't try to merge
themselves into main statement. If we don't do this,
SELECT * from information_schema.xxxx will cause problems.
- SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
+ SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()'
*/
lex->sql_command= SQLCOM_SHOW_FIELDS;
res= open_normal_and_derived_tables(thd, show_table_list,
@@ -2916,11 +2916,11 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
get_all_tables() returns 1 on failure and 0 on success thus
return only these and not the result code of ::process_table()
- We should use show_table_list->alias instead of
+ We should use show_table_list->alias instead of
show_table_list->table_name because table_name
could be changed during opening of I_S tables. It's safe
- to use alias because alias contains original table name
- in this case(this part of code is used only for
+ to use alias because alias contains original table name
+ in this case(this part of code is used only for
'show columns' & 'show statistics' commands).
*/
table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias,
@@ -2930,7 +2930,7 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables,
show_table_list->db_length, FALSE);
else
db_name= &show_table_list->view_db;
-
+
error= test(schema_table->process_table(thd, show_table_list,
table, res, db_name,
@@ -2968,7 +2968,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table,
{
enum legacy_db_type not_used;
char path[FN_REFLEN];
- (void) build_table_filename(path, sizeof(path), db_name->str,
+ (void) build_table_filename(path, sizeof(path), db_name->str,
table_name->str, reg_ext, 0);
switch (mysql_frm_type(thd, path, &not_used)) {
case FRMTYPE_ERROR:
@@ -3066,7 +3066,7 @@ uint get_table_open_method(TABLE_LIST *tables,
*/
static int fill_schema_table_from_frm(THD *thd,TABLE *table,
- ST_SCHEMA_TABLE *schema_table,
+ ST_SCHEMA_TABLE *schema_table,
LEX_STRING *db_name,
LEX_STRING *table_name,
enum enum_schema_tables schema_table_idx)
@@ -3093,7 +3093,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table,
res= 0;
goto err;
}
-
+
if (share->is_view)
{
if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY)
@@ -3105,7 +3105,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table,
else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL)
{
/*
- tell get_all_tables() to fall back to
+ tell get_all_tables() to fall back to
open_normal_and_derived_tables()
*/
res= 1;
@@ -3174,7 +3174,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
List<LEX_STRING> db_names;
List_iterator_fast<LEX_STRING> it(db_names);
COND *partial_cond= 0;
- uint derived_tables= lex->derived_tables;
+ uint derived_tables= lex->derived_tables;
int error= 1;
Open_tables_state open_tables_state_backup;
bool save_view_prepare_mode= lex->view_prepare_mode;
@@ -3195,7 +3195,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
- /*
+ /*
this branch processes SHOW FIELDS, SHOW INDEXES commands.
see sql_parse.cc, prepare_schema_table() function where
this values are initialized
@@ -3219,7 +3219,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value)
{
- /*
+ /*
if lookup value is empty string then
it's impossible table name or db name
*/
@@ -3237,7 +3237,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
!lookup_field_vals.wild_db_value)
tables->has_db_lookup_value= TRUE;
if (lookup_field_vals.table_value.length &&
- !lookup_field_vals.wild_table_value)
+ !lookup_field_vals.wild_table_value)
tables->has_table_lookup_value= TRUE;
if (tables->has_db_lookup_value && tables->has_table_lookup_value)
@@ -3261,7 +3261,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
while ((db_name= it++))
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!check_access(thd,SELECT_ACL, db_name->str,
+ if (!check_access(thd,SELECT_ACL, db_name->str,
&thd->col_access, 0, 1, with_i_schema) ||
sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
@@ -3291,7 +3291,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
/*
If table is I_S.tables and open_table_method is 0 (eg SKIP_OPEN)
- we can skip table opening and we don't have lookup value for
+ we can skip table opening and we don't have lookup value for
table name or lookup value is wild string(table name list is
already created by make_table_name_list() function).
*/
@@ -3313,7 +3313,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
- if (!(table_open_method & ~OPEN_FRM_ONLY) &&
+ if (!(table_open_method & ~OPEN_FRM_ONLY) &&
!with_i_schema)
{
if (!fill_schema_table_from_frm(thd, table, schema_table, db_name,
@@ -3367,10 +3367,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
else
{
/*
- We should use show_table_list->alias instead of
+ We should use show_table_list->alias instead of
show_table_list->table_name because table_name
could be changed during opening of I_S tables. It's safe
- to use alias because alias contains original table name
+ to use alias because alias contains original table name
in this case.
*/
thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
@@ -3584,15 +3584,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
ptr=strmov(ptr," delay_key_write=1");
if (share->row_type != ROW_TYPE_DEFAULT)
- ptr=strxmov(ptr, " row_format=",
+ ptr=strxmov(ptr, " row_format=",
ha_row_type[(uint) share->row_type],
NullS);
- if (share->transactional != HA_CHOICE_UNDEF)
- {
- ptr= strxmov(ptr, " TRANSACTIONAL=",
- (share->transactional == HA_CHOICE_YES ? "1" : "0"),
- NullS);
- }
if (share->key_block_size)
{
ptr= strmov(ptr, " KEY_BLOCK_SIZE=");
@@ -3606,7 +3600,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
ptr= strxmov(ptr, " transactional=",
ha_choice_values[(uint) share->transactional], NullS);
table->field[19]->store(option_buff+1,
- (ptr == option_buff ? 0 :
+ (ptr == option_buff ? 0 :
(uint) (ptr-option_buff)-1), cs);
tmp_buff= (share->table_charset ?
@@ -3644,7 +3638,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
tmp_buff= "Compact";
break;
case ROW_TYPE_PAGE:
- tmp_buff= "Paged";
+ tmp_buff= "Page";
break;
}
table->field[6]->store(tmp_buff, strlen(tmp_buff), cs);
@@ -3689,7 +3683,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables,
table->field[16]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[16]->set_notnull();
}
- if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
+ if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
{
table->field[18]->store((longlong) file->checksum(), TRUE);
table->field[18]->set_notnull();
@@ -3720,7 +3714,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
/*
I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
rather than in SHOW COLUMNS
- */
+ */
if (thd->is_error())
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
thd->main_da.sql_errno(), thd->main_da.message());
@@ -3759,7 +3753,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
uint col_access;
check_access(thd,SELECT_ACL | EXTRA_ACL, db_name->str,
&tables->grant.privilege, 0, 0, test(tables->schema_table));
- col_access= get_column_grant(thd, &tables->grant,
+ col_access= get_column_grant(thd, &tables->grant,
db_name->str, table_name->str,
field->field_name) & COL_ACLS;
if (!tables->schema_table && !col_access)
@@ -3782,7 +3776,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
cs);
table->field[4]->store((longlong) count, TRUE);
field->sql_type(type);
- table->field[14]->store(type.ptr(), type.length(), cs);
+ table->field[14]->store(type.ptr(), type.length(), cs);
tmp_buff= strchr(type.ptr(), '(');
table->field[7]->store(type.ptr(),
(tmp_buff ? tmp_buff - type.ptr() :
@@ -3804,7 +3798,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
uint32 octet_max_length= field->max_display_length();
if (is_blob && octet_max_length != (uint32) 4294967295U)
octet_max_length /= field->charset()->mbmaxlen;
- longlong char_max_len= is_blob ?
+ longlong char_max_len= is_blob ?
(longlong) octet_max_length / field->charset()->mbminlen :
(longlong) octet_max_length / field->charset()->mbmaxlen;
table->field[8]->store(char_max_len, TRUE);
@@ -3837,7 +3831,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
field_length= field->max_display_length();
decimals= -1; // return NULL
break;
- case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
field_length= field->field_length;
if (decimals == NOT_FIXED_DEC)
@@ -3903,7 +3897,7 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond)
for (cs= all_charsets ; cs < all_charsets+255 ; cs++)
{
CHARSET_INFO *tmp_cs= cs[0];
- if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
+ if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) &&
(tmp_cs->state & MY_CS_AVAILABLE) &&
!(tmp_cs->state & MY_CS_HIDDEN) &&
!(wild && wild[0] &&
@@ -4016,7 +4010,7 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond)
for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
{
CHARSET_INFO *tmp_cl= cl[0];
- if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
+ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
!my_charset_same(tmp_cs, tmp_cl))
continue;
if (!(wild && wild[0] &&
@@ -4050,13 +4044,13 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
{
CHARSET_INFO **cl;
CHARSET_INFO *tmp_cs= cs[0];
- if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
+ if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) ||
!(tmp_cs->state & MY_CS_PRIMARY))
continue;
for (cl= all_charsets; cl < all_charsets+255 ;cl ++)
{
CHARSET_INFO *tmp_cl= cl[0];
- if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
+ if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) ||
!my_charset_same(tmp_cs,tmp_cl))
continue;
restore_record(table, s->default_values);
@@ -4122,7 +4116,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
table->field[10]->store(STRING_WITH_LEN("SQL"), cs);
get_field(thd->mem_root, proc_table->field[6], &tmp_string);
table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs);
- table->field[12]->store(sp_data_access_name[enum_idx].str,
+ table->field[12]->store(sp_data_access_name[enum_idx].str,
sp_data_access_name[enum_idx].length , cs);
get_field(thd->mem_root, proc_table->field[7], &tmp_string);
table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs);
@@ -4436,10 +4430,10 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
if (res && thd->is_error())
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
thd->main_da.sql_errno(), thd->main_da.message());
}
- if (res)
+ if (res)
thd->clear_error();
DBUG_RETURN(0);
}
@@ -4480,7 +4474,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
TABLE *show_table= tables->table;
KEY *key_info=show_table->key_info;
uint primary_key= show_table->s->primary_key;
- show_table->file->info(HA_STATUS_VARIABLE |
+ show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
@@ -4509,7 +4503,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list);
while ((f_key_info=it++))
{
- if (store_constraints(thd, table, db_name, table_name,
+ if (store_constraints(thd, table, db_name, table_name,
f_key_info->forein_id->str,
strlen(f_key_info->forein_id->str),
"FOREIGN KEY", 11))
@@ -4664,7 +4658,7 @@ static int get_schema_key_column_usage_record(THD *thd,
TABLE *show_table= tables->table;
KEY *key_info=show_table->key_info;
uint primary_key= show_table->s->primary_key;
- show_table->file->info(HA_STATUS_VARIABLE |
+ show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
@@ -4681,8 +4675,8 @@ static int get_schema_key_column_usage_record(THD *thd,
restore_record(table, s->default_values);
store_key_column_usage(table, db_name, table_name,
key_info->name,
- strlen(key_info->name),
- key_part->field->field_name,
+ strlen(key_info->name),
+ key_part->field->field_name,
strlen(key_part->field->field_name),
(longlong) f_idx);
if (schema_table_store_record(thd, table))
@@ -4718,7 +4712,7 @@ static int get_schema_key_column_usage_record(THD *thd,
system_charset_info);
table->field[9]->set_notnull();
table->field[10]->store(f_key_info->referenced_table->str,
- f_key_info->referenced_table->length,
+ f_key_info->referenced_table->length,
system_charset_info);
table->field[10]->set_notnull();
table->field[11]->store(r_info->str, r_info->length,
@@ -4792,7 +4786,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table,
table->field[20]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
table->field[20]->set_notnull();
}
- if (file->ha_table_flags() & (ulong) HA_HAS_CHECKSUM)
+ if (file->ha_table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM))
{
table->field[21]->store((longlong) stat_info.check_sum, TRUE);
table->field[21]->set_notnull();
@@ -4886,7 +4880,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
tmp_res.append(partition_keywords[PKW_KEY].str,
partition_keywords[PKW_KEY].length);
else
- tmp_res.append(partition_keywords[PKW_HASH].str,
+ tmp_res.append(partition_keywords[PKW_HASH].str,
partition_keywords[PKW_HASH].length);
table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs);
break;
@@ -4922,7 +4916,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
tmp_res.append(partition_keywords[PKW_KEY].str,
partition_keywords[PKW_KEY].length);
else
- tmp_res.append(partition_keywords[PKW_HASH].str,
+ tmp_res.append(partition_keywords[PKW_HASH].str,
partition_keywords[PKW_HASH].length);
table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs);
table->field[8]->set_notnull();
@@ -5001,7 +4995,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables,
/* SUBPARTITION_ORDINAL_POSITION */
table->field[6]->store((longlong) ++subpart_pos, TRUE);
table->field[6]->set_notnull();
-
+
store_schema_partitions_record(thd, table, show_table, subpart_elem,
file, part_id);
part_id++;
@@ -5219,7 +5213,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
else
sch_table->field[ISE_ON_COMPLETION]->
store(STRING_WITH_LEN("PRESERVE"), scs);
-
+
number_to_datetime(et.created, &time, 0, &not_used);
DBUG_ASSERT(not_used==0);
sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
@@ -5340,7 +5334,7 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond)
tmp1= &tmp;
}
else
- {
+ {
option_type= OPT_SESSION;
tmp1= &thd->status_var;
}
@@ -5395,7 +5389,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
{
List<FOREIGN_KEY_INFO> f_key_list;
TABLE *show_table= tables->table;
- show_table->file->info(HA_STATUS_VARIABLE |
+ show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
@@ -5409,9 +5403,9 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
table->field[9]->store(table_name->str, table_name->length, cs);
table->field[2]->store(f_key_info->forein_id->str,
f_key_info->forein_id->length, cs);
- table->field[4]->store(f_key_info->referenced_db->str,
+ table->field[4]->store(f_key_info->referenced_db->str,
f_key_info->referenced_db->length, cs);
- table->field[10]->store(f_key_info->referenced_table->str,
+ table->field[10]->store(f_key_info->referenced_table->str,
f_key_info->referenced_table->length, cs);
if (f_key_info->referenced_key_name)
{
@@ -5422,9 +5416,9 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
else
table->field[5]->set_null();
table->field[6]->store(STRING_WITH_LEN("NONE"), cs);
- table->field[7]->store(f_key_info->update_method->str,
+ table->field[7]->store(f_key_info->update_method->str,
f_key_info->update_method->length, cs);
- table->field[8]->store(f_key_info->delete_method->str,
+ table->field[8]->store(f_key_info->delete_method->str,
f_key_info->delete_method->length, cs);
if (schema_table_store_record(thd, table))
DBUG_RETURN(1);
@@ -5433,7 +5427,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
DBUG_RETURN(0);
}
-struct schema_table_ref
+struct schema_table_ref
{
const char *table_name;
ST_SCHEMA_TABLE *schema_table;
@@ -5500,7 +5494,7 @@ ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
}
schema_table_a.table_name= table_name;
- if (plugin_foreach(thd, find_schema_table_in_plugin,
+ if (plugin_foreach(thd, find_schema_table_in_plugin,
MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
DBUG_RETURN(schema_table_a.schema_table);
@@ -5575,7 +5569,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
break;
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
- if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC,
+ if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC,
fields_info->field_length)) == NULL)
DBUG_RETURN(NULL);
break;
@@ -5629,7 +5623,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
tmp_table_param->schema_table= 1;
SELECT_LEX *select_lex= thd->lex->current_select;
if (!(table= create_tmp_table(thd, tmp_table_param,
- field_list, (ORDER*) 0, 0, 0,
+ field_list, (ORDER*) 0, 0, 0,
(select_lex->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR, table_list->alias)))
@@ -5974,7 +5968,7 @@ bool get_schema_tables_result(JOIN *join,
thd->no_warnings_for_error= 1;
for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
- {
+ {
if (!tab->table || !tab->table->pos_in_table_list)
break;
@@ -6099,17 +6093,17 @@ ST_FIELD_INFO tables_fields_info[]=
{"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", OPEN_FULL_TABLE},
{"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
- {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
- {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
{"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
- {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
+ {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
{"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
- {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0,
+ {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Auto_increment", OPEN_FULL_TABLE},
{"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", OPEN_FULL_TABLE},
{"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", OPEN_FULL_TABLE},
@@ -6580,9 +6574,9 @@ ST_FIELD_INFO files_fields_info[]=
{"EXTENT_SIZE", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
{"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
+ {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
+ {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
{"CREATION_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
{"LAST_UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
@@ -6594,20 +6588,20 @@ ST_FIELD_INFO files_fields_info[]=
{"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", SKIP_OPEN_TABLE},
{"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
+ {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0,
+ {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", SKIP_OPEN_TABLE},
{"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", SKIP_OPEN_TABLE},
{"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", SKIP_OPEN_TABLE},
{"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", SKIP_OPEN_TABLE},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
+ {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
(MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", SKIP_OPEN_TABLE},
{"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
{"EXTRA", 255, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
@@ -6656,13 +6650,13 @@ ST_FIELD_INFO referential_constraints_fields_info[]=
ST_SCHEMA_TABLE schema_tables[]=
{
- {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
+ {"CHARACTER_SETS", charsets_fields_info, create_schema_table,
fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
- {"COLLATIONS", collation_fields_info, create_schema_table,
+ {"COLLATIONS", collation_fields_info, create_schema_table,
fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
{"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0},
- {"COLUMNS", columns_fields_info, create_schema_table,
+ {"COLUMNS", columns_fields_info, create_schema_table,
get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
{"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table,
@@ -6699,7 +6693,7 @@ ST_SCHEMA_TABLE schema_tables[]=
{"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
create_schema_table, get_all_tables, 0, get_referential_constraints_record,
1, 9, 0, OPEN_TABLE_ONLY},
- {"ROUTINES", proc_fields_info, create_schema_table,
+ {"ROUTINES", proc_fields_info, create_schema_table,
fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
{"SCHEMATA", schema_fields_info, create_schema_table,
fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
@@ -6726,7 +6720,7 @@ ST_SCHEMA_TABLE schema_tables[]=
{"TRIGGERS", triggers_fields_info, create_schema_table,
get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
OPEN_TABLE_ONLY},
- {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
+ {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table,
fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
{"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
make_old_format, 0, 0, -1, 1, 0},
@@ -6756,8 +6750,8 @@ int initialize_schema_table(st_plugin_int *plugin)
{
schema_table->create_table= create_schema_table;
schema_table->old_format= make_old_format;
- schema_table->idx_field1= -1,
- schema_table->idx_field2= -1;
+ schema_table->idx_field1= -1,
+ schema_table->idx_field2= -1;
/* Make the name available to the init() function. */
schema_table->table_name= plugin->name.str;
@@ -6770,7 +6764,7 @@ int initialize_schema_table(st_plugin_int *plugin)
my_free(schema_table, MYF(0));
DBUG_RETURN(1);
}
-
+
/* Make sure the plugin name is not set inside the init() function. */
schema_table->table_name= plugin->name.str;
}
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 1e9322f7f5b..f54b085eeda 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -34,7 +34,9 @@
the callback function 'unpack_addon_fields'.
*/
-typedef struct st_sort_addon_field { /* Sort addon packed field */
+typedef struct st_sort_addon_field
+{
+ /* Sort addon packed field */
Field *field; /* Original field */
uint offset; /* Offset from the last sorted field */
uint null_offset; /* Offset to to null bit from the last sorted field */
@@ -42,14 +44,6 @@ typedef struct st_sort_addon_field { /* Sort addon packed field */
uint8 null_bit; /* Null bit mask for the field */
} SORT_ADDON_FIELD;
-typedef struct st_buffpek { /* Struktur om sorteringsbuffrarna */
- my_off_t file_pos; /* Where we are in the sort file */
- uchar *base,*key; /* key pointers */
- ha_rows count; /* Number of rows in table */
- ulong mem_count; /* numbers of keys in memory */
- ulong max_keys; /* Max keys in buffert */
-} BUFFPEK;
-
struct BUFFPEK_COMPARE_CONTEXT
{
qsort_cmp2 key_compare;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 4827810334f..a7443e1bd9b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2925,10 +2925,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS))
length=column->length;
}
- else if (length == 0)
+ else if (length == 0 && (sql_field->flags & NOT_NULL_FLAG))
{
my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name);
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(TRUE);
}
if (length > file->max_key_part_length() && key->type != Key::FULLTEXT)
{
@@ -3262,8 +3262,9 @@ bool mysql_create_table_no_lock(THD *thd,
if (check_engine(thd, table_name, create_info))
DBUG_RETURN(TRUE);
db_options= create_info->table_options;
- if (create_info->row_type == ROW_TYPE_DYNAMIC)
- db_options|=HA_OPTION_PACK_RECORD;
+ if (create_info->row_type != ROW_TYPE_FIXED &&
+ create_info->row_type != ROW_TYPE_DEFAULT)
+ db_options|= HA_OPTION_PACK_RECORD;
alias= table_case_name(create_info, table_name);
if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root,
create_info->db_type)))
@@ -3469,6 +3470,14 @@ bool mysql_create_table_no_lock(THD *thd,
goto err;
}
+ /* Give warnings for not supported table options */
+ if (create_info->transactional && !file->ht->commit)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ ER(ER_ILLEGAL_HA_CREATE_OPTION),
+ file->engine_name()->str,
+ "TRANSACTIONAL=1");
+
VOID(pthread_mutex_lock(&LOCK_open));
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
@@ -3521,7 +3530,6 @@ bool mysql_create_table_no_lock(THD *thd,
goto warn;
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
goto unlock_and_end;
- break;
default:
DBUG_PRINT("info", ("error: %u from storage engine", retcode));
my_error(retcode, MYF(0),table_name);
@@ -3838,7 +3846,7 @@ mysql_rename_table(handlerton *base, const char *old_db,
Win32 clients must also have a WRITE LOCK on the table !
*/
-void wait_while_table_is_used(THD *thd, TABLE *table,
+void wait_while_table_is_used(THD *thd,TABLE *table,
enum ha_extra_function function)
{
DBUG_ENTER("wait_while_table_is_used");
@@ -3847,8 +3855,7 @@ void wait_while_table_is_used(THD *thd, TABLE *table,
table->db_stat, table->s->version));
safe_mutex_assert_owner(&LOCK_open);
-
- VOID(table->file->extra(function));
+
/* Mark all tables that are in use as 'old' */
mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */
@@ -3856,6 +3863,8 @@ void wait_while_table_is_used(THD *thd, TABLE *table,
remove_table_from_cache(thd, table->s->db.str,
table->s->table_name.str,
RTFC_WAIT_OTHER_THREAD_FLAG);
+ /* extra() call must come only after all instances above are closed */
+ VOID(table->file->extra(function));
DBUG_VOID_RETURN;
}
@@ -5307,6 +5316,8 @@ compare_tables(TABLE *table,
create_info->used_fields & HA_CREATE_USED_CHARSET ||
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
+ create_info->used_fields & HA_CREATE_USED_PAGE_CHECKSUM ||
+ create_info->used_fields & HA_CREATE_USED_TRANSACTIONAL ||
create_info->used_fields & HA_CREATE_USED_PACK_KEYS ||
create_info->used_fields & HA_CREATE_USED_MAX_ROWS ||
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
@@ -5325,8 +5336,7 @@ compare_tables(TABLE *table,
new_field_it.init(alter_info->create_list);
tmp_new_field_it.init(tmp_alter_info.create_list);
- /*
- Go through fields and check if the original ones are compatible
+ /* Go through fields and check if the original ones are compatible
with new table.
*/
for (f_ptr= table->field, new_field= new_field_it++,
@@ -5348,11 +5358,11 @@ compare_tables(TABLE *table,
}
/* Don't pack rows in old tables if the user has requested this. */
- if (create_info->row_type == ROW_TYPE_DYNAMIC ||
+ if (create_info->row_type == ROW_TYPE_DYNAMIC ||
(tmp_new_field->flags & BLOB_FLAG) ||
tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
- create_info->row_type != ROW_TYPE_FIXED)
- create_info->table_options|= HA_OPTION_PACK_RECORD;
+ create_info->row_type != ROW_TYPE_FIXED)
+ create_info->table_options|= HA_OPTION_PACK_RECORD;
/* Check if field was renamed */
field->flags&= ~FIELD_IS_RENAMED;
@@ -5597,6 +5607,7 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled,
Sets create_info->varchar if the table has a VARCHAR column.
Prepares alter_info->create_list and alter_info->key_list with
columns and keys of the new table.
+
@retval TRUE error, out of memory or a semantical error in ALTER
TABLE instructions
@retval FALSE success
@@ -5623,7 +5634,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
uint used_fields= create_info->used_fields;
KEY *key_info=table->key_info;
bool rc= TRUE;
-
+ Create_field *def;
+ Field **f_ptr,*field;
DBUG_ENTER("mysql_prepare_alter_table");
create_info->varchar= FALSE;
@@ -5659,18 +5671,16 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
create_info->tablespace= tablespace;
}
restore_record(table, s->default_values); // Empty record for DEFAULT
- Create_field *def;
/*
First collect all fields from table which isn't in drop_list
*/
- Field **f_ptr,*field;
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{
+ Alter_drop *drop;
if (field->type() == MYSQL_TYPE_STRING)
create_info->varchar= TRUE;
/* Check if field should be dropped */
- Alter_drop *drop;
drop_it.rewind();
while ((drop=drop_it++))
{
@@ -5744,7 +5754,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
{
if (def->change && ! def->field)
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change,
+ table->s->table_name.str);
goto err;
}
/*
@@ -5779,7 +5790,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (!find)
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after,
+ table->s->table_name.str);
goto err;
}
find_it.after(def); // Put element after this
@@ -5829,6 +5841,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
continue; // Wrong field (from UNIREG)
const char *key_part_name=key_part->field->field_name;
Create_field *cfield;
+ uint key_part_length;
+
field_it.rewind();
while ((cfield=field_it++))
{
@@ -5844,7 +5858,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
}
if (!cfield)
continue; // Field is removed
- uint key_part_length=key_part->length;
+ key_part_length= key_part->length;
if (cfield->field) // Not new field
{
/*
@@ -6037,7 +6051,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
uint index_add_count;
uint *index_add_buffer;
uint candidate_key_count;
- bool committed= 0;
bool no_pk;
DBUG_ENTER("mysql_alter_table");
@@ -6865,7 +6878,6 @@ view_err:
DBUG_PRINT("info", ("Committing before unlocking table"));
if (ha_autocommit_or_rollback(thd, 0) || end_active_trans(thd))
goto err1;
- committed= 1;
}
/*end of if (! new_table) for add/drop index*/
@@ -7175,9 +7187,9 @@ copy_data_between_tables(TABLE *from,TABLE *to,
enum enum_enable_or_disable keys_onoff,
bool error_if_not_empty)
{
- int error;
- Copy_field *copy,*copy_end;
- ulong found_count,delete_count;
+ int error= 1, errpos= 0;
+ Copy_field *copy= NULL, *copy_end;
+ ulong found_count= 0, delete_count= 0;
THD *thd= current_thd;
uint length= 0;
SORT_FIELD *sortorder;
@@ -7187,8 +7199,10 @@ copy_data_between_tables(TABLE *from,TABLE *to,
List<Item> all_fields;
ha_rows examined_rows;
bool auto_increment_field_copied= 0;
- ulong save_sql_mode;
+ ulong save_sql_mode= thd->variables.sql_mode;
ulonglong prev_insert_id;
+ List_iterator<Create_field> it(create);
+ Create_field *def;
DBUG_ENTER("copy_data_between_tables");
/*
@@ -7197,15 +7211,16 @@ copy_data_between_tables(TABLE *from,TABLE *to,
This needs to be done before external_lock
*/
- error= ha_enable_transaction(thd, FALSE);
- if (error)
- DBUG_RETURN(-1);
-
+ if (ha_enable_transaction(thd, FALSE))
+ goto err;
+ errpos=1;
+
if (!(copy= new Copy_field[to->s->fields]))
- DBUG_RETURN(-1); /* purecov: inspected */
+ goto err; /* purecov: inspected */
if (to->file->ha_external_lock(thd, F_WRLCK))
- DBUG_RETURN(-1);
+ goto err;
+ errpos= 2;
/* We need external lock before we can disable/enable keys */
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
@@ -7217,11 +7232,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
from->file->info(HA_STATUS_VARIABLE);
to->file->ha_start_bulk_insert(from->file->stats.records);
+ errpos= 3;
- save_sql_mode= thd->variables.sql_mode;
-
- List_iterator<Create_field> it(create);
- Create_field *def;
copy_end=copy;
for (Field **ptr=to->field ; *ptr ; ptr++)
{
@@ -7245,8 +7257,6 @@ copy_data_between_tables(TABLE *from,TABLE *to,
}
- found_count=delete_count=0;
-
if (order)
{
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
@@ -7266,7 +7276,6 @@ copy_data_between_tables(TABLE *from,TABLE *to,
tables.table= from;
tables.alias= tables.table_name= from->s->table_name.str;
tables.db= from->s->db.str;
- error= 1;
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
@@ -7283,6 +7292,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
/* Tell handler that we have values for all columns in the to table */
to->use_all_columns();
init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE);
+ errpos= 4;
if (ignore)
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
thd->row_count= 0;
@@ -7346,22 +7356,24 @@ copy_data_between_tables(TABLE *from,TABLE *to,
else
found_count++;
}
- end_read_record(&info);
+
+err:
+ if (errpos >= 4)
+ end_read_record(&info);
free_io_cache(from);
- delete [] copy; // This is never 0
+ delete [] copy;
- if (to->file->ha_end_bulk_insert() && error <= 0)
+ if (error > 0)
+ to->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
+ if (errpos >= 3 && to->file->ha_end_bulk_insert(error > 1) && error <= 0)
{
to->file->print_error(my_errno,MYF(0));
- error=1;
+ error= 1;
}
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
- if (ha_enable_transaction(thd, TRUE))
- {
+ if (errpos >= 1 && ha_enable_transaction(thd, TRUE))
error= 1;
- goto err;
- }
/*
Ensure that the new table is saved properly to disk so that we
@@ -7372,15 +7384,15 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (end_active_trans(thd))
error=1;
- err:
thd->variables.sql_mode= save_sql_mode;
thd->abort_on_warning= 0;
- free_io_cache(from);
*copied= found_count;
*deleted=delete_count;
to->file->ha_release_auto_increment();
- if (to->file->ha_external_lock(thd,F_UNLCK))
+ if (errpos >= 2 && to->file->ha_external_lock(thd,F_UNLCK))
error=1;
+ if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME))
+ error= 1;
DBUG_RETURN(error > 0 ? -1 : 0);
}
@@ -7460,11 +7472,14 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
}
else
{
- if (t->file->ha_table_flags() & HA_HAS_CHECKSUM &&
- !(check_opt->flags & T_EXTEND))
+ /* Call ->checksum() if the table checksum matches 'old_mode' settings */
+ if (!(check_opt->flags & T_EXTEND) &&
+ (((t->file->ha_table_flags() & HA_HAS_OLD_CHECKSUM) &&
+ thd->variables.old_mode) ||
+ ((t->file->ha_table_flags() & HA_HAS_NEW_CHECKSUM) &&
+ !thd->variables.old_mode)))
protocol->store((ulonglong)t->file->checksum());
- else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) &&
- (check_opt->flags & T_QUICK))
+ else if (check_opt->flags & T_QUICK)
protocol->store_null();
else
{
@@ -7501,8 +7516,17 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
for (uint i= 0; i < t->s->fields; i++ )
{
Field *f= t->field[i];
- if ((f->type() == MYSQL_TYPE_BLOB) ||
- (f->type() == MYSQL_TYPE_VARCHAR))
+ if (! thd->variables.old_mode &&
+ f->is_real_null(0))
+ continue;
+ enum_field_types field_type= f->type();
+ /*
+ BLOB and VARCHAR have pointers in their field, we must convert
+ to string; GEOMETRY is implemented on top of BLOB.
+ */
+ if ((field_type == MYSQL_TYPE_BLOB) ||
+ (field_type == MYSQL_TYPE_VARCHAR) ||
+ (field_type == MYSQL_TYPE_GEOMETRY))
{
String tmp;
f->val_str(&tmp);
@@ -7562,7 +7586,7 @@ static bool check_engine(THD *thd, const char *table_name,
if (create_info->used_fields & HA_CREATE_USED_ENGINE)
{
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
- ha_resolve_storage_engine_name(*new_engine), "TEMPORARY");
+ hton_name(*new_engine)->str, "TEMPORARY");
*new_engine= 0;
return TRUE;
}
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
index 9fec0e3bc63..14b29452750 100644
--- a/sql/sql_tablespace.cc
+++ b/sql/sql_tablespace.cc
@@ -34,7 +34,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
- ha_resolve_storage_engine_name(hton),
+ hton_name(hton)->str,
ts_info->tablespace_name ? ts_info->tablespace_name
: ts_info->logfile_group_name);
}
@@ -43,13 +43,14 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
{
if ((error= hton->alter_tablespace(hton, thd, ts_info)))
{
- if (error == HA_ADMIN_NOT_IMPLEMENTED)
+ if (error == 1)
{
- my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "");
+ DBUG_RETURN(1);
}
- else if (error == 1)
+
+ if (error == HA_ADMIN_NOT_IMPLEMENTED)
{
- DBUG_RETURN(1);
+ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "");
}
else
{
@@ -63,7 +64,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_ILLEGAL_HA_CREATE_OPTION,
ER(ER_ILLEGAL_HA_CREATE_OPTION),
- ha_resolve_storage_engine_name(hton),
+ hton_name(hton)->str,
"TABLESPACE or LOGFILE GROUP");
}
write_bin_log(thd, FALSE, thd->query, thd->query_length);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index fd3036e3d80..68a614c710e 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -63,9 +63,9 @@ bool select_union::send_data(List<Item> &values)
if ((error= table->file->ha_write_row(table->record[0])))
{
- /* create_myisam_from_heap will generate error if needed */
+ /* create_internal_tmp_table_from_heap will generate error if needed */
if (table->file->is_fatal_error(error, HA_CHECK_DUP) &&
- create_myisam_from_heap(thd, table, &tmp_table_param, error, 1))
+ create_internal_tmp_table_from_heap(thd, table, &tmp_table_param, error, 1))
return 1;
}
return 0;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f448fb7ab50..181ff82f0fe 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1748,7 +1748,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)
{
if (error &&
- create_myisam_from_heap(thd, tmp_table,
+ create_internal_tmp_table_from_heap(thd, tmp_table,
tmp_table_param + offset, error, 1))
{
do_update= 0;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index be66f7c2d80..816040aa323 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1021,7 +1021,6 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
bool parse_status;
bool result, view_is_mergeable;
TABLE_LIST *view_main_select_tables;
-
DBUG_ENTER("mysql_make_view");
DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name));
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 7df035bbfc3..920fe7af9fb 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1686,7 +1686,7 @@ create:
push_warning_printf(YYTHD, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
- ha_resolve_storage_engine_name(lex->create_info.db_type),
+ hton_name(lex->create_info.db_type)->str,
$5->table.str);
}
}
@@ -12182,6 +12182,16 @@ table_lock:
lock_option:
READ_SYM { $$= TL_READ_NO_INSERT; }
| WRITE_SYM { $$= TL_WRITE_DEFAULT; }
+ | WRITE_SYM CONCURRENT
+ {
+#ifdef HAVE_QUERY_CACHE
+ if (Lex->sphead != 0)
+ $$= TL_WRITE_DEFAULT;
+ else
+#endif
+ $$= TL_WRITE_CONCURRENT_INSERT;
+ }
+
| LOW_PRIORITY WRITE_SYM { $$= TL_WRITE_LOW_PRIORITY; }
| READ_SYM LOCAL_SYM { $$= TL_READ; }
;
diff --git a/sql/table.cc b/sql/table.cc
index 17454ffb012..7437f601c7b 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -526,7 +526,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
int error, table_type;
bool error_given;
File file;
- uchar head[288], *disk_buff;
+ uchar head[288];
char path[FN_REFLEN];
MEM_ROOT **root_ptr, *old_root;
DBUG_ENTER("open_table_def");
@@ -535,7 +535,6 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
error= 1;
error_given= 0;
- disk_buff= NULL;
strxmov(path, share->normalized_path.str, reg_ext, NullS);
if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
@@ -2544,6 +2543,8 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
create_info->default_table_charset= share->table_charset;
create_info->table_charset= 0;
create_info->comment= share->comment;
+ create_info->transactional= share->transactional;
+ create_info->page_checksum= share->page_checksum;
DBUG_VOID_RETURN;
}
diff --git a/sql/time.cc b/sql/time.cc
index a6619cf4cee..687bb09e0f0 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -561,7 +561,7 @@ bool parse_date_time_format(timestamp_type format_type,
return 0;
break;
default:
- DBUG_ASSERT(1);
+ DBUG_ASSERT(0);
break;
}
return 1; // Error
diff --git a/sql/unireg.cc b/sql/unireg.cc
index da018ebec3d..eedac2fd582 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -159,8 +159,7 @@ bool mysql_create_frm(THD *thd, const char *file_name,
reclength=uint2korr(forminfo+266);
/* Calculate extra data segment length */
- str_db_type.str= (char *) ha_resolve_storage_engine_name(create_info->db_type);
- str_db_type.length= strlen(str_db_type.str);
+ str_db_type= *hton_name(create_info->db_type);
/* str_db_type */
create_info->extra_size= (2 + str_db_type.length +
2 + create_info->connect_string.length);
@@ -525,7 +524,7 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
int2store(pos+6, key->block_size);
pos+=8;
key_parts+=key->key_parts;
- DBUG_PRINT("loop", ("flags: %lu key_parts: %d at 0x%lx",
+ DBUG_PRINT("loop", ("flags: %lu key_parts: %d key_part: 0x%lx",
key->flags, key->key_parts,
(long) key->key_part));
for (key_part=key->key_part,key_part_end=key_part+key->key_parts ;
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index 7edfca53751..09401d20282 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -1511,7 +1511,7 @@ void ha_archive::start_bulk_insert(ha_rows rows)
Other side of start_bulk_insert, is end_bulk_insert. Here we turn off the bulk insert
flag, and set the share dirty so that the next select will call sync for us.
*/
-int ha_archive::end_bulk_insert()
+int ha_archive::end_bulk_insert(bool table_will_be_deleted)
{
DBUG_ENTER("ha_archive::end_bulk_insert");
bulk_insert= FALSE;
diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h
index ab630ed22fd..22f8302982d 100644
--- a/storage/archive/ha_archive.h
+++ b/storage/archive/ha_archive.h
@@ -134,7 +134,7 @@ public:
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
int repair(THD* thd, HA_CHECK_OPT* check_opt);
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool table_will_be_deleted);
enum row_type get_row_type() const
{
return ROW_TYPE_COMPRESSED;
diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc
index 368ce7e28f3..e29fe4162f4 100644
--- a/storage/csv/ha_tina.cc
+++ b/storage/csv/ha_tina.cc
@@ -441,7 +441,7 @@ ha_tina::ha_tina(handlerton *hton, TABLE_SHARE *table_arg)
*/
current_position(0), next_position(0), local_saved_data_file_length(0),
file_buff(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH),
- local_data_file_version(0), records_is_known(0)
+ local_data_file_version(0), records_is_known(0), curr_lock_type(F_UNLCK)
{
/* Set our original buffers from pre-allocated memory */
buffer.set((char*)byte_buffer, IO_SIZE, &my_charset_bin);
@@ -729,7 +729,7 @@ const char **ha_tina::bas_ext() const
for CSV engine. For more details see mysys/thr_lock.c
*/
-void tina_get_status(void* param, int concurrent_insert)
+void tina_get_status(void* param, my_bool concurrent_insert)
{
ha_tina *tina= (ha_tina*) param;
tina->get_status();
@@ -1495,6 +1495,14 @@ int ha_tina::delete_all_rows()
DBUG_RETURN(rc);
}
+int ha_tina::external_lock(THD *thd __attribute__((unused)), int lock_type)
+{
+ if (lock_type==F_UNLCK && curr_lock_type == F_WRLCK)
+ update_status();
+ curr_lock_type= lock_type;
+ return 0;
+}
+
/*
Called by the database to lock the table. Keep in mind that this
is an internal lock.
@@ -1509,7 +1517,7 @@ THR_LOCK_DATA **ha_tina::store_lock(THD *thd,
return to;
}
-/*
+/*
Create a table. You do not want to leave the table open after a call to
this (the database will call ::open() if it needs to).
*/
diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h
index 5b4381396fc..09bcac612d8 100644
--- a/storage/csv/ha_tina.h
+++ b/storage/csv/ha_tina.h
@@ -85,6 +85,8 @@ class ha_tina: public handler
MEM_ROOT blobroot;
private:
+ int curr_lock_type;
+
bool get_write_pos(off_t *end_pos, tina_set *closest_hole);
int open_update_temp_file_if_needed();
int init_tina_writer();
@@ -155,6 +157,8 @@ public:
bool check_if_incompatible_data(HA_CREATE_INFO *info,
uint table_changes);
+ int external_lock(THD *thd, int lock_type);
+
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc
index 6cfbd355c40..fa2bd9454e9 100644
--- a/storage/federated/ha_federated.cc
+++ b/storage/federated/ha_federated.cc
@@ -1988,12 +1988,12 @@ void ha_federated::start_bulk_insert(ha_rows rows)
@retval != 0 Error occured at remote server. Also sets my_errno.
*/
-int ha_federated::end_bulk_insert()
+int ha_federated::end_bulk_insert(bool abort)
{
int error= 0;
DBUG_ENTER("ha_federated::end_bulk_insert");
- if (bulk_insert.str && bulk_insert.length)
+ if (!abort && bulk_insert.str && bulk_insert.length)
{
if (real_query(bulk_insert.str, bulk_insert.length))
error= stash_remote_error();
diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h
index 1974f9936fc..d2a86794904 100644
--- a/storage/federated/ha_federated.h
+++ b/storage/federated/ha_federated.h
@@ -205,7 +205,7 @@ public:
int close(void); // required
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool abort);
int write_row(uchar *buf);
int update_row(const uchar *old_data, uchar *new_data);
int delete_row(const uchar *buf);
diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c
index 2abef2d9b43..c6f7e644ed6 100644
--- a/storage/heap/hp_write.c
+++ b/storage/heap/hp_write.c
@@ -109,7 +109,7 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *record,
custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
if (keyinfo->flag & HA_NOSAME)
{
- custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE;
+ custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT;
keyinfo->rb_tree.flag= TREE_NO_DUPS;
}
else
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 5d895833f42..502a1da7b4d 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1492,6 +1492,9 @@ innobase_init(
int err;
bool ret;
char *default_path;
+#ifdef SAFE_MUTEX
+ my_bool old_safe_mutex_deadlock_detector;
+#endif
DBUG_ENTER("innobase_init");
handlerton *innobase_hton= (handlerton *)p;
@@ -1744,8 +1747,15 @@ innobase_init(
srv_sizeof_trx_t_in_ha_innodb_cc = sizeof(trx_t);
+#ifdef SAFE_MUTEX
+ /* Disable deadlock detection as it's very slow for the buffer pool */
+ old_safe_mutex_deadlock_detector= safe_mutex_deadlock_detector;
+ safe_mutex_deadlock_detector= 0;
+#endif
err = innobase_start_or_create_for_mysql();
-
+#ifdef SAFE_MUTEX
+ safe_mutex_deadlock_detector= old_safe_mutex_deadlock_detector;
+#endif
if (err != DB_SUCCESS) {
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
diff --git a/storage/maria/CMakeLists.txt b/storage/maria/CMakeLists.txt
new file mode 100644
index 00000000000..cf01a6f1be1
--- /dev/null
+++ b/storage/maria/CMakeLists.txt
@@ -0,0 +1,91 @@
+# Copyright (C) 2007 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake")
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
+ ${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/extra/yassl/include)
+SET(MARIA_SOURCES ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c
+ ma_rnext.c ma_rnext_same.c
+ ma_search.c ma_page.c ma_key_recover.c ma_key.c
+ ma_locking.c ma_state.c
+ ma_rrnd.c ma_scan.c ma_cache.c
+ ma_statrec.c ma_packrec.c ma_dynrec.c
+ ma_blockrec.c ma_bitmap.c
+ ma_update.c ma_write.c ma_unique.c
+ ma_delete.c
+ ma_rprev.c ma_rfirst.c ma_rlast.c ma_rsame.c
+ ma_rsamepos.c ma_panic.c ma_close.c ma_create.c
+ ma_range.c ma_dbug.c ma_checksum.c
+ ma_changed.c ma_static.c ma_delete_all.c
+ ma_delete_table.c ma_rename.c ma_check.c
+ ma_keycache.c ma_preload.c ma_ft_parser.c
+ ma_ft_update.c ma_ft_boolean_search.c
+ ma_ft_nlq_search.c ft_maria.c ma_sort.c
+ ha_maria.cc trnman.c lockman.c tablockman.c
+ ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c
+ ma_sp_key.c ma_control_file.c ma_loghandler.c
+ ma_pagecache.c ma_pagecaches.c
+ ma_checkpoint.c ma_recovery.c ma_commit.c ma_pagecrc.c
+ ha_maria.h maria_def.h ma_recovery_util.c
+)
+
+IF(NOT SOURCE_SUBLIBS)
+
+ ADD_LIBRARY(maria ${MARIA_SOURCES})
+
+ADD_EXECUTABLE(maria_ftdump maria_ftdump.c)
+TARGET_LINK_LIBRARIES(maria_ftdump maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(maria_chk maria_chk.c)
+TARGET_LINK_LIBRARIES(maria_chk maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(maria_read_log maria_read_log.c)
+TARGET_LINK_LIBRARIES(maria_read_log maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(maria_pack maria_pack.c)
+TARGET_LINK_LIBRARIES(maria_pack maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(maria_dump_log ma_loghandler.c unittest/ma_loghandler_examples.c)
+TARGET_LINK_LIBRARIES(maria_dump_log maria myisam mysys dbug strings zlib wsock32)
+SET_TARGET_PROPERTIES(maria_dump_log PROPERTIES COMPILE_FLAGS "-DMARIA_DUMP_LOG")
+
+ADD_EXECUTABLE(ma_test1 ma_test1.c)
+TARGET_LINK_LIBRARIES(ma_test1 maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(ma_test2 ma_test2.c)
+TARGET_LINK_LIBRARIES(ma_test2 maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(ma_test3 ma_test3.c)
+TARGET_LINK_LIBRARIES(ma_test3 maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(ma_rt_test ma_rt_test.c)
+TARGET_LINK_LIBRARIES(ma_rt_test maria myisam mysys dbug strings zlib wsock32)
+
+ADD_EXECUTABLE(ma_sp_test ma_sp_test.c)
+TARGET_LINK_LIBRARIES(ma_sp_test maria myisam mysys dbug strings zlib wsock32)
+
+IF(EMBED_MANIFESTS)
+ MYSQL_EMBED_MANIFEST("maria_ftdump" "asInvoker")
+ MYSQL_EMBED_MANIFEST("maria_chk" "asInvoker")
+ MYSQL_EMBED_MANIFEST("maria_read_log" "asInvoker")
+ MYSQL_EMBED_MANIFEST("maria_pack" "asInvoker")
+ENDIF(EMBED_MANIFESTS)
+
+ENDIF(NOT SOURCE_SUBLIBS)
diff --git a/storage/maria/Makefile.am b/storage/maria/Makefile.am
new file mode 100644
index 00000000000..0f1e482c3a1
--- /dev/null
+++ b/storage/maria/Makefile.am
@@ -0,0 +1,197 @@
+# Copyright (C) 2000-2008 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+MYSQLLIBdir= $(pkglibdir)
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include \
+ -I$(top_srcdir)/regex \
+ -I$(top_srcdir)/sql \
+ -I$(srcdir)
+WRAPLIBS=
+
+LDADD =
+
+DEFS = @DEFS@
+
+# "." is needed first because tests in unittest need libmaria
+SUBDIRS = . unittest
+
+EXTRA_DIST = ma_test_all.sh ma_test_all.res ma_test_big.sh \
+ ma_ft_stem.c CMakeLists.txt plug.in ma_test_recovery
+pkgdata_DATA = ma_test_all ma_test_all.res ma_test_recovery
+pkglib_LIBRARIES = libmaria.a
+bin_PROGRAMS = maria_chk maria_pack maria_ftdump maria_read_log \
+ maria_dump_log
+maria_chk_DEPENDENCIES= $(LIBRARIES)
+# Only reason to link with libmyisam.a here is that it's where some fulltext
+# pieces are (but soon we'll remove fulltext dependencies from Maria).
+# For now, it imposes that storage/myisam be built before storage/maria.
+maria_chk_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+maria_pack_DEPENDENCIES=$(LIBRARIES)
+maria_pack_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+maria_read_log_DEPENDENCIES=$(LIBRARIES)
+maria_read_log_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+maria_dump_log_DEPENDENCIES=$(LIBRARIES) ma_loghandler.c
+maria_dump_log_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+maria_dump_log_SOURCES= ma_loghandler.c unittest/ma_loghandler_examples.c
+maria_dump_log_CPPFLAGS= -DMARIA_DUMP_LOG
+noinst_PROGRAMS = ma_test1 ma_test2 ma_test3 ma_rt_test ma_sp_test
+noinst_HEADERS = maria_def.h ma_rt_index.h ma_rt_key.h ma_rt_mbr.h \
+ ma_sp_defs.h ma_fulltext.h ma_ftdefs.h ma_ft_test1.h \
+ ma_ft_eval.h trnman.h lockman.h tablockman.h \
+ ma_control_file.h ha_maria.h ma_blockrec.h \
+ ma_loghandler.h ma_loghandler_lsn.h ma_pagecache.h \
+ ma_checkpoint.h ma_recovery.h ma_commit.h ma_state.h \
+ trnman_public.h ma_check_standalone.h \
+ ma_key_recover.h ma_recovery_util.h
+ma_test1_DEPENDENCIES= $(LIBRARIES)
+ma_test1_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+ma_test2_DEPENDENCIES= $(LIBRARIES)
+ma_test2_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+ma_test3_DEPENDENCIES= $(LIBRARIES)
+ma_test3_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+#ma_ft_test1_DEPENDENCIES= $(LIBRARIES)
+#ma_ft_eval_DEPENDENCIES= $(LIBRARIES)
+maria_ftdump_DEPENDENCIES= $(LIBRARIES)
+maria_ftdump_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+ma_rt_test_DEPENDENCIES= $(LIBRARIES)
+ma_rt_test_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+ma_sp_test_DEPENDENCIES= $(LIBRARIES)
+ma_sp_test_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+libmaria_a_SOURCES = ma_init.c ma_open.c ma_extra.c ma_info.c ma_rkey.c \
+ ma_rnext.c ma_rnext_same.c \
+ ma_search.c ma_page.c ma_key_recover.c ma_key.c \
+ ma_locking.c ma_state.c \
+ ma_rrnd.c ma_scan.c ma_cache.c \
+ ma_statrec.c ma_packrec.c ma_dynrec.c \
+ ma_blockrec.c ma_bitmap.c \
+ ma_update.c ma_write.c ma_unique.c \
+ ma_delete.c \
+ ma_rprev.c ma_rfirst.c ma_rlast.c ma_rsame.c \
+ ma_rsamepos.c ma_panic.c ma_close.c ma_create.c\
+ ma_range.c ma_dbug.c ma_checksum.c \
+ ma_changed.c ma_static.c ma_delete_all.c \
+ ma_delete_table.c ma_rename.c ma_check.c \
+ ma_keycache.c ma_preload.c ma_ft_parser.c \
+ ma_ft_update.c ma_ft_boolean_search.c \
+ ma_ft_nlq_search.c ft_maria.c ma_sort.c \
+ trnman.c lockman.c tablockman.c \
+ ma_rt_index.c ma_rt_key.c ma_rt_mbr.c ma_rt_split.c \
+ ma_sp_key.c ma_control_file.c ma_loghandler.c \
+ ma_pagecache.c ma_pagecaches.c \
+ ma_checkpoint.c ma_recovery.c ma_commit.c \
+ ma_pagecrc.c ma_recovery_util.c \
+ ha_maria.cc
+CLEANFILES = test?.MA? FT?.MA? isam.log ma_test_all ma_rt_test.MA? sp_test.MA? maria_log_control maria_log.0000*
+
+SUFFIXES = .sh
+
+.sh:
+ @RM@ -f $@ $@-t
+ @SED@ \
+ -e 's!@''bindir''@!$(bindir)!g' \
+ -e 's!@''scriptdir''@!$(bindir)!g' \
+ -e 's!@''prefix''@!$(prefix)!g' \
+ -e 's!@''datadir''@!$(datadir)!g' \
+ -e 's!@''localstatedir''@!$(localstatedir)!g' \
+ -e 's!@''libexecdir''@!$(libexecdir)!g' \
+ -e 's!@''CC''@!@CC@!'\
+ -e 's!@''CXX''@!@CXX@!'\
+ -e 's!@''GXX''@!@GXX@!'\
+ -e 's!@''PERL''@!@PERL@!' \
+ -e 's!@''CFLAGS''@!@SAVE_CFLAGS@!'\
+ -e 's!@''CXXFLAGS''@!@SAVE_CXXFLAGS@!'\
+ -e 's!@''LDFLAGS''@!@SAVE_LDFLAGS@!'\
+ -e 's!@''VERSION''@!@VERSION@!' \
+ -e 's!@''MYSQL_SERVER_SUFFIX''@!@MYSQL_SERVER_SUFFIX@!' \
+ -e 's!@''COMPILATION_COMMENT''@!@COMPILATION_COMMENT@!' \
+ -e 's!@''MACHINE_TYPE''@!@MACHINE_TYPE@!' \
+ -e 's!@''HOSTNAME''@!@HOSTNAME@!' \
+ -e 's!@''SYSTEM_TYPE''@!@SYSTEM_TYPE@!' \
+ -e 's!@''CHECK_PID''@!@CHECK_PID@!' \
+ -e 's!@''FIND_PROC''@!@FIND_PROC@!' \
+ -e 's!@''MYSQLD_DEFAULT_SWITCHES''@!@MYSQLD_DEFAULT_SWITCHES@!' \
+ -e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \
+ -e 's!@''TARGET_LINUX''@!@TARGET_LINUX@!' \
+ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \
+ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \
+ -e 's!@''sysconfdir''@!@sysconfdir@!' \
+ -e 's!@''SHORT_MYSQL_INTRO''@!@SHORT_MYSQL_INTRO@!' \
+ -e 's!@''SHARED_LIB_VERSION''@!@SHARED_LIB_VERSION@!' \
+ -e 's!@''MYSQL_BASE_VERSION''@!@MYSQL_BASE_VERSION@!' \
+ -e 's!@''MYSQL_NO_DASH_VERSION''@!@MYSQL_NO_DASH_VERSION@!' \
+ -e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \
+ -e 's!@''PERL_DBI_VERSION''@!@PERL_DBI_VERSION@!' \
+ -e 's!@''PERL_DBD_VERSION''@!@PERL_DBD_VERSION@!' \
+ -e 's!@''PERL_DATA_DUMPER''@!@PERL_DATA_DUMPER@!' \
+ $< > $@-t
+ @CHMOD@ +x $@-t
+ @MV@ $@-t $@
+
+tags:
+ etags *.h *.c *.cc
+
+unittests = unittest
+
+test:
+ perl $(top_srcdir)/unittest/unit.pl run $(unittests)
+
+test-verbose:
+ HARNESS_VERBOSE=1 perl $(top_srcdir)/unittest/unit.pl run $(unittests)
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/storage/maria/file_formats.txt b/storage/maria/file_formats.txt
new file mode 100644
index 00000000000..927e8ad985e
--- /dev/null
+++ b/storage/maria/file_formats.txt
@@ -0,0 +1,71 @@
+#
+# This should contain a description of the file format for most Maria files
+#
+
+# Description of the header in the index file
+
+Header, 24 bytes
+
+Pos Length
+
+0 4 file_version
+4 2 options
+6 2 header_length
+8 2 state_info_length
+10 2 base_info_length
+12 2 base_pos
+14 2 key_parts
+16 2 unique_key_parts
+18 1 keys
+19 1 uniques
+20 1 language
+21 1 fulltext_keys
+22 1 data_file_type
+23 1 org_data_file_type
+
+
+Status part
+
+24 2 open_count
+26 2 state_changed
+28 7 create_rename_lsn
+ 7 is_of_horizon
+ 7 skip_redo_lsn
+ 8 state.records
+ 8 state->state.del
+ 8 state->split
+ 8 state->dellink
+ 8 state->first_bitmap_with_space
+ 8 state->state.key_file_length
+ 8 state->state.data_file_length
+ 8 state->state.empty
+ 8 state->state.key_empty
+ 8 state->auto_increment
+ 8 state->state.checksum
+ 4 state->process
+ 4 state->unique
+ 4 state->status
+ 4 state->update_count
+
+ 1 state->sortkey
+ 1 reserved
+
+for each key
+ 8 state->key_root[i]
+
+ 8 state->key_del
+ 4 state->sec_index_changed
+ 4 state->sec_index_used
+ 4 state->version
+ 8 state->key_map
+ 8 state->create_time
+ 8 state->recover_time
+ 8 state->check_time
+ 8 state->records_at_analyze
+
+for each key
+ 4 reserved
+
+for each key part
+ 8 state->rec_per_key_part[i]
+ 4 state->nulls_per_key_part[i]
diff --git a/storage/maria/ft_maria.c b/storage/maria/ft_maria.c
new file mode 100644
index 00000000000..1b082f904d0
--- /dev/null
+++ b/storage/maria/ft_maria.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/*
+ This function is for interface functions between fulltext and maria
+*/
+
+#include "ma_ftdefs.h"
+
+FT_INFO *maria_ft_init_search(uint flags, void *info, uint keynr,
+ uchar *query, uint query_len, CHARSET_INFO *cs,
+ uchar *record)
+{
+ FT_INFO *res;
+ if (flags & FT_BOOL)
+ res= maria_ft_init_boolean_search((MARIA_HA *) info, keynr, query,
+ query_len, cs);
+ else
+ res= maria_ft_init_nlq_search((MARIA_HA *) info, keynr, query, query_len,
+ flags, record);
+ return res;
+}
+
+const struct _ft_vft _ma_ft_vft_nlq = {
+ maria_ft_nlq_read_next, maria_ft_nlq_find_relevance,
+ maria_ft_nlq_close_search, maria_ft_nlq_get_relevance,
+ maria_ft_nlq_reinit_search
+};
+const struct _ft_vft _ma_ft_vft_boolean = {
+ maria_ft_boolean_read_next, maria_ft_boolean_find_relevance,
+ maria_ft_boolean_close_search, maria_ft_boolean_get_relevance,
+ maria_ft_boolean_reinit_search
+};
+
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
new file mode 100644
index 00000000000..efcfca5bd62
--- /dev/null
+++ b/storage/maria/ha_maria.cc
@@ -0,0 +1,3323 @@
+/* Copyright (C) 2004-2008 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ Copyright (C) 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#define MYSQL_SERVER 1
+#include "mysql_priv.h"
+#include <mysql/plugin.h>
+#include <m_ctype.h>
+#include <my_dir.h>
+#include <myisampack.h>
+#include <my_bit.h>
+#include "ha_maria.h"
+#include "trnman_public.h"
+
+C_MODE_START
+#include "maria_def.h"
+#include "ma_rt_index.h"
+#include "ma_blockrec.h"
+#include "ma_checkpoint.h"
+#include "ma_recovery.h"
+C_MODE_END
+
+/*
+ Note that in future versions, only *transactional* Maria tables can
+ rollback, so this flag should be up or down conditionally.
+*/
+#ifdef MARIA_CANNOT_ROLLBACK
+#define CANNOT_ROLLBACK_FLAG HA_NO_TRANSACTIONS
+#define trans_register_ha(A, B, C) do { /* nothing */ } while(0)
+#else
+#define CANNOT_ROLLBACK_FLAG 0
+#endif
+#define THD_TRN (*(TRN **)thd_ha_data(thd, maria_hton))
+
+ulong pagecache_division_limit, pagecache_age_threshold;
+ulonglong pagecache_buffer_size;
+
+/**
+ As the auto-repair is initiated when opened from the SQL layer
+ (open_unireg_entry(), check_and_repair()), it does not happen when Maria's
+ Recovery internally opens the table to apply log records to it, which is
+ good. It would happen only after Recovery, if the table is still
+ corrupted.
+*/
+ulong maria_recover_options= HA_RECOVER_NONE;
+handlerton *maria_hton;
+
+/* bits in maria_recover_options */
+const char *maria_recover_names[]=
+{
+ /*
+ Compared to MyISAM, "default" was renamed to "normal" as it collided with
+ SET var=default which sets to the var's default i.e. what happens when the
+ var is not set i.e. HA_RECOVER_NONE.
+ Another change is that OFF is used to disable, not ""; this is to have OFF
+ display in SHOW VARIABLES which is better than "".
+ */
+ "OFF", "NORMAL", "BACKUP", "FORCE", "QUICK", NullS
+};
+TYPELIB maria_recover_typelib=
+{
+ array_elements(maria_recover_names) - 1, "",
+ maria_recover_names, NULL
+};
+
+const char *maria_stats_method_names[]=
+{
+ "nulls_unequal", "nulls_equal",
+ "nulls_ignored", NullS
+};
+TYPELIB maria_stats_method_typelib=
+{
+ array_elements(maria_stats_method_names) - 1, "",
+ maria_stats_method_names, NULL
+};
+
+/* transactions log purge mode */
+const char *maria_translog_purge_type_names[]=
+{
+ "immediate", "external", "at_flush", NullS
+};
+TYPELIB maria_translog_purge_type_typelib=
+{
+ array_elements(maria_translog_purge_type_names) - 1, "",
+ maria_translog_purge_type_names, NULL
+};
+const char *maria_sync_log_dir_names[]=
+{
+ "NEVER", "NEWFILE", "ALWAYS", NullS
+};
+
+TYPELIB maria_sync_log_dir_typelib=
+{
+ array_elements(maria_sync_log_dir_names) - 1, "",
+ maria_sync_log_dir_names, NULL
+};
+
+/** Interval between background checkpoints in seconds */
+static ulong checkpoint_interval;
+static void update_checkpoint_interval(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+/** After that many consecutive recovery failures, remove logs */
+static ulong force_start_after_recovery_failures;
+static void update_log_file_size(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+
+static MYSQL_SYSVAR_ULONG(block_size, maria_block_size,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Block size to be used for MARIA index pages.", 0, 0,
+ MARIA_KEY_BLOCK_LENGTH, MARIA_MIN_KEY_BLOCK_LENGTH,
+ MARIA_MAX_KEY_BLOCK_LENGTH, MARIA_MIN_KEY_BLOCK_LENGTH);
+
+static MYSQL_SYSVAR_ULONG(checkpoint_interval, checkpoint_interval,
+ PLUGIN_VAR_RQCMDARG,
+ "Interval between automatic checkpoints, in seconds; 0 means"
+ " 'no automatic checkpoints' which makes sense only for testing.",
+ NULL, update_checkpoint_interval, 30, 0, UINT_MAX, 1);
+
+static MYSQL_SYSVAR_ULONG(force_start_after_recovery_failures,
+ force_start_after_recovery_failures,
+ /*
+ Read-only because setting it on the fly has no useful effect,
+ should be set on command-line.
+ */
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Number of consecutive log recovery failures after which logs will be"
+ " automatically deleted to cure the problem; 0 (the default) disables"
+ " the feature.", NULL, NULL, 0, 0, UINT_MAX8, 1);
+
+static MYSQL_SYSVAR_BOOL(page_checksum, maria_page_checksums, 0,
+ "Maintain page checksums (can be overridden per table "
+ "with PAGE_CHECKSUM clause in CREATE TABLE)", 0, 0, 1);
+
+/* It is only command line argument */
+static MYSQL_SYSVAR_STR(log_dir_path, maria_data_root,
+ PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_RQCMDARG,
+ "Path to the directory where to store transactional log",
+ NULL, NULL, mysql_real_data_home);
+
+
+static MYSQL_SYSVAR_ULONG(log_file_size, log_file_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Limit for transaction log size",
+ NULL, update_log_file_size, TRANSLOG_FILE_SIZE,
+ TRANSLOG_MIN_FILE_SIZE, 0xffffffffL, TRANSLOG_PAGE_SIZE);
+
+static MYSQL_SYSVAR_ENUM(log_purge_type, log_purge_type,
+ PLUGIN_VAR_RQCMDARG,
+ "Specifies how maria transactional log will be purged. "
+ "Possible values of name are \"immediate\", \"external\" "
+ "and \"at_flush\"",
+ NULL, NULL, TRANSLOG_PURGE_IMMIDIATE,
+ &maria_translog_purge_type_typelib);
+
+static MYSQL_SYSVAR_ULONGLONG(max_sort_file_size,
+ maria_max_temp_length, PLUGIN_VAR_RQCMDARG,
+ "Don't use the fast sort index method to created index if the "
+ "temporary file would get bigger than this.",
+ 0, 0, MAX_FILE_SIZE, 0, MAX_FILE_SIZE, 1024*1024);
+
+static MYSQL_SYSVAR_ULONG(pagecache_age_threshold,
+ pagecache_age_threshold, PLUGIN_VAR_RQCMDARG,
+ "This characterizes the number of hits a hot block has to be untouched "
+ "until it is considered aged enough to be downgraded to a warm block. "
+ "This specifies the percentage ratio of that number of hits to the "
+ "total number of blocks in the page cache.", 0, 0,
+ 300, 100, ~0L, 100);
+
+static MYSQL_SYSVAR_ULONGLONG(pagecache_buffer_size, pagecache_buffer_size,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "The size of the buffer used for index blocks for Maria tables. "
+ "Increase this to get better index handling (for all reads and "
+ "multiple writes) to as much as you can afford.", 0, 0,
+ KEY_CACHE_SIZE, MALLOC_OVERHEAD, ~(ulong) 0, IO_SIZE);
+
+static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit,
+ PLUGIN_VAR_RQCMDARG,
+ "The minimum percentage of warm blocks in key cache", 0, 0,
+ 100, 1, 100, 1);
+
+static MYSQL_SYSVAR_ENUM(recover, maria_recover_options, PLUGIN_VAR_OPCMDARG,
+ "Specifies how corrupted tables should be automatically repaired."
+ " Possible values are \"NORMAL\" (the default), \"BACKUP\", \"FORCE\","
+ " \"QUICK\", or \"OFF\" which is like not using the option.",
+ NULL, NULL, HA_RECOVER_NONE, &maria_recover_typelib);
+
+static MYSQL_THDVAR_ULONG(repair_threads, PLUGIN_VAR_RQCMDARG,
+ "Number of threads to use when repairing maria tables. The value of 1 "
+ "disables parallel repair.",
+ 0, 0, 1, 1, ~0L, 1);
+
+static MYSQL_THDVAR_ULONG(sort_buffer_size, PLUGIN_VAR_RQCMDARG,
+ "The buffer that is allocated when sorting the index when doing a "
+ "REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.",
+ 0, 0, 8192*1024, 4, ~0L, 1);
+
+static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG,
+ "Specifies how maria index statistics collection code should treat "
+ "NULLs. Possible values are \"nulls_unequal\", \"nulls_equal\", "
+ "and \"nulls_ignored\".", 0, 0, 0, &maria_stats_method_typelib);
+
+static MYSQL_SYSVAR_ENUM(sync_log_dir, sync_log_dir, PLUGIN_VAR_RQCMDARG,
+ "Controls syncing directory after log file growth and new file "
+ "creation. Possible values are \"never\", \"newfile\" and "
+ "\"always\").", NULL, NULL, TRANSLOG_SYNC_DIR_NEWFILE,
+ &maria_sync_log_dir_typelib);
+
+/*****************************************************************************
+** MARIA tables
+*****************************************************************************/
+
+static handler *maria_create_handler(handlerton *hton,
+ TABLE_SHARE * table,
+ MEM_ROOT *mem_root)
+{
+ return new (mem_root) ha_maria(hton, table);
+}
+
+
+// collect errors printed by maria_check routines
+
+static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type,
+ const char *fmt, va_list args)
+{
+ THD *thd= (THD *) param->thd;
+ Protocol *protocol= thd->protocol;
+ uint length, msg_length;
+ char msgbuf[HA_MAX_MSG_BUF];
+ char name[NAME_LEN * 2 + 2];
+
+ msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+ msgbuf[sizeof(msgbuf) - 1]= 0; // healthy paranoia
+
+ DBUG_PRINT(msg_type, ("message: %s", msgbuf));
+
+ if (!thd->vio_ok())
+ {
+ sql_print_error(msgbuf);
+ return;
+ }
+
+ if (param->testflag &
+ (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | T_AUTO_REPAIR))
+ {
+ my_message(ER_NOT_KEYFILE, msgbuf, MYF(MY_WME));
+ return;
+ }
+ length= (uint) (strxmov(name, param->db_name, ".", param->table_name,
+ NullS) - name);
+ /*
+ TODO: switch from protocol to push_warning here. The main reason we didn't
+ it yet is parallel repair. Due to following trace:
+ ma_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
+
+ Also we likely need to lock mutex here (in both cases with protocol and
+ push_warning).
+ */
+ protocol->prepare_for_resend();
+ protocol->store(name, length, system_charset_info);
+ protocol->store(param->op_name, system_charset_info);
+ protocol->store(msg_type, system_charset_info);
+ protocol->store(msgbuf, msg_length, system_charset_info);
+ if (protocol->write())
+ sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
+ msgbuf);
+ return;
+}
+
+
+/*
+ Convert TABLE object to Maria key and column definition
+
+ SYNOPSIS
+ table2maria()
+ table_arg in TABLE object.
+ keydef_out out Maria key definition.
+ recinfo_out out Maria column definition.
+ records_out out Number of fields.
+
+ DESCRIPTION
+ This function will allocate and initialize Maria key and column
+ definition for further use in ma_create or for a check for underlying
+ table conformance in merge engine.
+
+ The caller needs to free *recinfo_out after use. Since *recinfo_out
+ and *keydef_out are allocated with a my_multi_malloc, *keydef_out
+ is freed automatically when *recinfo_out is freed.
+
+ RETURN VALUE
+ 0 OK
+ # error code
+*/
+
+static int table2maria(TABLE *table_arg, data_file_type row_type,
+ MARIA_KEYDEF **keydef_out,
+ MARIA_COLUMNDEF **recinfo_out, uint *records_out,
+ MARIA_CREATE_INFO *create_info)
+{
+ uint i, j, recpos, minpos, fieldpos, temp_length, length;
+ enum ha_base_keytype type= HA_KEYTYPE_BINARY;
+ uchar *record;
+ KEY *pos;
+ MARIA_KEYDEF *keydef;
+ MARIA_COLUMNDEF *recinfo, *recinfo_pos;
+ HA_KEYSEG *keyseg;
+ TABLE_SHARE *share= table_arg->s;
+ uint options= share->db_options_in_use;
+ DBUG_ENTER("table2maria");
+
+ if (row_type == BLOCK_RECORD)
+ options|= HA_OPTION_PACK_RECORD;
+
+ if (!(my_multi_malloc(MYF(MY_WME),
+ recinfo_out, (share->fields * 2 + 2) * sizeof(MARIA_COLUMNDEF),
+ keydef_out, share->keys * sizeof(MARIA_KEYDEF),
+ &keyseg,
+ (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
+ NullS)))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
+ keydef= *keydef_out;
+ recinfo= *recinfo_out;
+ pos= table_arg->key_info;
+ for (i= 0; i < share->keys; i++, pos++)
+ {
+ keydef[i].flag= (uint16) (pos->flags & (HA_NOSAME | HA_FULLTEXT |
+ HA_SPATIAL));
+ keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?
+ (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) :
+ pos->algorithm;
+ keydef[i].block_length= pos->block_size;
+ keydef[i].seg= keyseg;
+ keydef[i].keysegs= pos->key_parts;
+ for (j= 0; j < pos->key_parts; j++)
+ {
+ Field *field= pos->key_part[j].field;
+ type= field->key_type();
+ keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
+
+ if (options & HA_OPTION_PACK_KEYS ||
+ (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
+ HA_SPACE_PACK_USED)))
+ {
+ if (pos->key_part[j].length > 8 &&
+ (type == HA_KEYTYPE_TEXT ||
+ type == HA_KEYTYPE_NUM ||
+ (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
+ {
+ /* No blobs here */
+ if (j == 0)
+ keydef[i].flag|= HA_PACK_KEY;
+ if (!(field->flags & ZEROFILL_FLAG) &&
+ (field->type() == MYSQL_TYPE_STRING ||
+ field->type() == MYSQL_TYPE_VAR_STRING ||
+ ((int) (pos->key_part[j].length - field->decimals())) >= 4))
+ keydef[i].seg[j].flag|= HA_SPACE_PACK;
+ }
+ else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
+ keydef[i].flag|= HA_BINARY_PACK_KEY;
+ }
+ keydef[i].seg[j].type= (int) type;
+ keydef[i].seg[j].start= pos->key_part[j].offset;
+ keydef[i].seg[j].length= pos->key_part[j].length;
+ keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
+ keydef[i].seg[j].bit_length= 0;
+ keydef[i].seg[j].bit_pos= 0;
+ keydef[i].seg[j].language= field->charset()->number;
+
+ if (field->null_ptr)
+ {
+ keydef[i].seg[j].null_bit= field->null_bit;
+ keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
+ (uchar*) table_arg->record[0]);
+ }
+ else
+ {
+ keydef[i].seg[j].null_bit= 0;
+ keydef[i].seg[j].null_pos= 0;
+ }
+ if (field->type() == MYSQL_TYPE_BLOB ||
+ field->type() == MYSQL_TYPE_GEOMETRY)
+ {
+ keydef[i].seg[j].flag|= HA_BLOB_PART;
+ /* save number of bytes used to pack length */
+ keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
+ share->blob_ptr_size);
+ }
+ else if (field->type() == MYSQL_TYPE_BIT)
+ {
+ keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
+ keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
+ keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
+ (uchar*) table_arg->record[0]);
+ }
+ }
+ keyseg+= pos->key_parts;
+ }
+ if (table_arg->found_next_number_field)
+ keydef[share->next_number_index].flag|= HA_AUTO_KEY;
+ record= table_arg->record[0];
+ recpos= 0;
+ recinfo_pos= recinfo;
+ create_info->null_bytes= table_arg->s->null_bytes;
+
+ while (recpos < (uint) share->reclength)
+ {
+ Field **field, *found= 0;
+ minpos= share->reclength;
+ length= 0;
+
+ for (field= table_arg->field; *field; field++)
+ {
+ if ((fieldpos= (*field)->offset(record)) >= recpos &&
+ fieldpos <= minpos)
+ {
+ /* skip null fields */
+ if (!(temp_length= (*field)->pack_length_in_rec()))
+ continue; /* Skip null-fields */
+ if (! found || fieldpos < minpos ||
+ (fieldpos == minpos && temp_length < length))
+ {
+ minpos= fieldpos;
+ found= *field;
+ length= temp_length;
+ }
+ }
+ }
+ DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d",
+ (long) found, recpos, minpos, length));
+ if (!found)
+ break;
+
+ if (found->flags & BLOB_FLAG)
+ recinfo_pos->type= FIELD_BLOB;
+ else if (found->type() == MYSQL_TYPE_VARCHAR)
+ recinfo_pos->type= FIELD_VARCHAR;
+ else if (!(options & HA_OPTION_PACK_RECORD) ||
+ (found->zero_pack() && (found->flags & PRI_KEY_FLAG)))
+ recinfo_pos->type= FIELD_NORMAL;
+ else if (found->zero_pack())
+ recinfo_pos->type= FIELD_SKIP_ZERO;
+ else
+ recinfo_pos->type= ((length <= 3 ||
+ (found->flags & ZEROFILL_FLAG)) ?
+ FIELD_NORMAL :
+ found->type() == MYSQL_TYPE_STRING ||
+ found->type() == MYSQL_TYPE_VAR_STRING ?
+ FIELD_SKIP_ENDSPACE :
+ FIELD_SKIP_PRESPACE);
+ if (found->null_ptr)
+ {
+ recinfo_pos->null_bit= found->null_bit;
+ recinfo_pos->null_pos= (uint) (found->null_ptr -
+ (uchar*) table_arg->record[0]);
+ }
+ else
+ {
+ recinfo_pos->null_bit= 0;
+ recinfo_pos->null_pos= 0;
+ }
+ (recinfo_pos++)->length= (uint16) length;
+ recpos= minpos + length;
+ DBUG_PRINT("loop", ("length: %d type: %d",
+ recinfo_pos[-1].length,recinfo_pos[-1].type));
+ }
+ *records_out= (uint) (recinfo_pos - recinfo);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Check for underlying table conformance
+
+ SYNOPSIS
+ maria_check_definition()
+ t1_keyinfo in First table key definition
+ t1_recinfo in First table record definition
+ t1_keys in Number of keys in first table
+ t1_recs in Number of records in first table
+ t2_keyinfo in Second table key definition
+ t2_recinfo in Second table record definition
+ t2_keys in Number of keys in second table
+ t2_recs in Number of records in second table
+ strict in Strict check switch
+
+ DESCRIPTION
+ This function compares two Maria definitions. By intention it was done
+ to compare merge table definition against underlying table definition.
+ It may also be used to compare dot-frm and MAI definitions of Maria
+ table as well to compare different Maria table definitions.
+
+ For merge table it is not required that number of keys in merge table
+ must exactly match number of keys in underlying table. When calling this
+ function for underlying table conformance check, 'strict' flag must be
+ set to false, and converted merge definition must be passed as t1_*.
+
+ Otherwise 'strict' flag must be set to 1 and it is not required to pass
+ converted dot-frm definition as t1_*.
+
+ RETURN VALUE
+ 0 - Equal definitions.
+ 1 - Different definitions.
+
+ TODO
+ - compare FULLTEXT keys;
+ - compare SPATIAL keys;
+ - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
+ (should be correctly detected in table2maria).
+*/
+
+int maria_check_definition(MARIA_KEYDEF *t1_keyinfo,
+ MARIA_COLUMNDEF *t1_recinfo,
+ uint t1_keys, uint t1_recs,
+ MARIA_KEYDEF *t2_keyinfo,
+ MARIA_COLUMNDEF *t2_recinfo,
+ uint t2_keys, uint t2_recs, bool strict)
+{
+ uint i, j;
+ DBUG_ENTER("maria_check_definition");
+ if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
+ {
+ DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
+ t1_keys, t2_keys));
+ DBUG_RETURN(1);
+ }
+ if (t1_recs != t2_recs)
+ {
+ DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u",
+ t1_recs, t2_recs));
+ DBUG_RETURN(1);
+ }
+ for (i= 0; i < t1_keys; i++)
+ {
+ HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
+ HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
+ if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT)
+ continue;
+ else if (t1_keyinfo[i].flag & HA_FULLTEXT ||
+ t2_keyinfo[i].flag & HA_FULLTEXT)
+ {
+ DBUG_PRINT("error", ("Key %d has different definition", i));
+ DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d",
+ test(t1_keyinfo[i].flag & HA_FULLTEXT),
+ test(t2_keyinfo[i].flag & HA_FULLTEXT)));
+ DBUG_RETURN(1);
+ }
+ if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL)
+ continue;
+ else if (t1_keyinfo[i].flag & HA_SPATIAL ||
+ t2_keyinfo[i].flag & HA_SPATIAL)
+ {
+ DBUG_PRINT("error", ("Key %d has different definition", i));
+ DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d",
+ test(t1_keyinfo[i].flag & HA_SPATIAL),
+ test(t2_keyinfo[i].flag & HA_SPATIAL)));
+ DBUG_RETURN(1);
+ }
+ if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
+ t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
+ {
+ DBUG_PRINT("error", ("Key %d has different definition", i));
+ DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d",
+ t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg));
+ DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d",
+ t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg));
+ DBUG_RETURN(1);
+ }
+ for (j= t1_keyinfo[i].keysegs; j--;)
+ {
+ uint8 t1_keysegs_j__type= t1_keysegs[j].type;
+ /*
+ Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
+ always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of
+ HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM
+ level, we can ignore a mismatch between these types.
+ */
+ if ((t1_keysegs[j].flag & HA_BLOB_PART) &&
+ (t2_keysegs[j].flag & HA_BLOB_PART))
+ {
+ if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
+ (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
+ t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
+ else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
+ (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
+ t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
+ }
+
+ if (t1_keysegs_j__type != t2_keysegs[j].type ||
+ t1_keysegs[j].language != t2_keysegs[j].language ||
+ t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
+ t1_keysegs[j].length != t2_keysegs[j].length)
+ {
+ DBUG_PRINT("error", ("Key segment %d (key %d) has different "
+ "definition", j, i));
+ DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, "
+ "t1_length=%d",
+ t1_keysegs[j].type, t1_keysegs[j].language,
+ t1_keysegs[j].null_bit, t1_keysegs[j].length));
+ DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, "
+ "t2_length=%d",
+ t2_keysegs[j].type, t2_keysegs[j].language,
+ t2_keysegs[j].null_bit, t2_keysegs[j].length));
+
+ DBUG_RETURN(1);
+ }
+ }
+ }
+
+ for (i= 0; i < t1_recs; i++)
+ {
+ MARIA_COLUMNDEF *t1_rec= &t1_recinfo[i];
+ MARIA_COLUMNDEF *t2_rec= &t2_recinfo[i];
+ /*
+ FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in maria_create,
+ see NOTE1 in ma_create.c
+ */
+ if ((t1_rec->type != t2_rec->type &&
+ !(t1_rec->type == (int) FIELD_SKIP_ZERO &&
+ t1_rec->length == 1 &&
+ t2_rec->type == (int) FIELD_NORMAL)) ||
+ t1_rec->length != t2_rec->length ||
+ t1_rec->null_bit != t2_rec->null_bit)
+ {
+ DBUG_PRINT("error", ("Field %d has different definition", i));
+ DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d",
+ t1_rec->type, t1_rec->length, t1_rec->null_bit));
+ DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d",
+ t2_rec->type, t2_rec->length, t2_rec->null_bit));
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+extern "C" {
+
+volatile int *_ma_killed_ptr(HA_CHECK *param)
+{
+ /* In theory Unsafe conversion, but should be ok for now */
+ return (int*) &(((THD *) (param->thd))->killed);
+}
+
+
+void _ma_check_print_error(HA_CHECK *param, const char *fmt, ...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_error");
+ param->error_printed |= 1;
+ param->out_flag |= O_DATA_LOST;
+ va_start(args, fmt);
+ _ma_check_print_msg(param, "error", fmt, args);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+
+void _ma_check_print_info(HA_CHECK *param, const char *fmt, ...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_info");
+ va_start(args, fmt);
+ _ma_check_print_msg(param, "info", fmt, args);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+
+void _ma_check_print_warning(HA_CHECK *param, const char *fmt, ...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_warning");
+ param->warning_printed= 1;
+ param->out_flag |= O_DATA_LOST;
+ va_start(args, fmt);
+ _ma_check_print_msg(param, "warning", fmt, args);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+}
+
+/**
+ Transactional table doing bulk insert with one single UNDO
+ (UNDO_BULK_INSERT) and with repair.
+*/
+#define BULK_INSERT_SINGLE_UNDO_AND_REPAIR 1
+/**
+ Transactional table doing bulk insert with one single UNDO
+ (UNDO_BULK_INSERT) and without repair.
+*/
+#define BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR 2
+/**
+ None of BULK_INSERT_SINGLE_UNDO_AND_REPAIR and
+ BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR.
+*/
+#define BULK_INSERT_NONE 0
+
+ha_maria::ha_maria(handlerton *hton, TABLE_SHARE *table_arg):
+handler(hton, table_arg), file(0),
+int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
+ HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
+ HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
+ HA_FILE_BASED | HA_CAN_GEOMETRY | CANNOT_ROLLBACK_FLAG |
+ HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
+ HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT),
+can_enable_indexes(1), bulk_insert_single_undo(BULK_INSERT_NONE)
+{}
+
+
+handler *ha_maria::clone(MEM_ROOT *mem_root)
+{
+ ha_maria *new_handler= static_cast <ha_maria *>(handler::clone(mem_root));
+ if (new_handler)
+ new_handler->file->state= file->state;
+ return new_handler;
+}
+
+
+static const char *ha_maria_exts[]=
+{
+ MARIA_NAME_IEXT,
+ MARIA_NAME_DEXT,
+ NullS
+};
+
+
+const char **ha_maria::bas_ext() const
+{
+ return ha_maria_exts;
+}
+
+
+const char *ha_maria::index_type(uint key_number)
+{
+ return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
+ "FULLTEXT" :
+ (table->key_info[key_number].flags & HA_SPATIAL) ?
+ "SPATIAL" :
+ (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
+ "RTREE" : "BTREE");
+}
+
+
+double ha_maria::scan_time()
+{
+ if (file->s->data_file_type == BLOCK_RECORD)
+ return ulonglong2double(stats.data_file_length - file->s->block_size) / max(file->s->block_size / 2, IO_SIZE) + 2;
+ return handler::scan_time();
+}
+
+/*
+ We need to be able to store at least two keys on an index page as the
+ splitting algorithms depends on this. (With only one key on a page
+ we also can't use any compression, which may make the index file much
+ larger)
+ We use HA_MAX_KEY_BUFF as this is a stack restriction imposed by the
+ handler interface.
+
+ We also need to reserve place for a record pointer (8) and 3 bytes
+ per key segment to store the length of the segment + possible null bytes.
+ These extra bytes are required here so that maria_create() will surely
+ accept any keys created which the returned key data storage length.
+*/
+
+uint ha_maria::max_supported_key_length() const
+{
+ uint tmp= (maria_max_key_length() - 8 - HA_MAX_KEY_SEG*3);
+ return min(HA_MAX_KEY_BUFF, tmp);
+}
+
+
+#ifdef HAVE_REPLICATION
+int ha_maria::net_read_dump(NET * net)
+{
+ int data_fd= file->dfile.file;
+ int error= 0;
+
+ my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
+ for (;;)
+ {
+ ulong packet_len= my_net_read(net);
+ if (!packet_len)
+ break; // end of file
+ if (packet_len == packet_error)
+ {
+ sql_print_error("ha_maria::net_read_dump - read error ");
+ error= -1;
+ goto err;
+ }
+ if (my_write(data_fd, (uchar *) net->read_pos, (uint) packet_len,
+ MYF(MY_WME | MY_FNABP)))
+ {
+ error= errno;
+ goto err;
+ }
+ }
+err:
+ return error;
+}
+
+
+int ha_maria::dump(THD * thd, int fd)
+{
+ MARIA_SHARE *share= file->s;
+ NET *net= &thd->net;
+ uint block_size= share->block_size;
+ my_off_t bytes_to_read= share->state.state.data_file_length;
+ int data_fd= file->dfile.file;
+ uchar *buf= (uchar *) my_malloc(block_size, MYF(MY_WME));
+ if (!buf)
+ return ENOMEM;
+
+ int error= 0;
+ my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
+ for (; bytes_to_read > 0;)
+ {
+ size_t bytes= my_read(data_fd, buf, block_size, MYF(MY_WME));
+ if (bytes == MY_FILE_ERROR)
+ {
+ error= errno;
+ goto err;
+ }
+
+ if (fd >= 0)
+ {
+ if (my_write(fd, buf, bytes, MYF(MY_WME | MY_FNABP)))
+ {
+ error= errno ? errno : EPIPE;
+ goto err;
+ }
+ }
+ else
+ {
+ if (my_net_write(net, buf, bytes))
+ {
+ error= errno ? errno : EPIPE;
+ goto err;
+ }
+ }
+ bytes_to_read -= bytes;
+ }
+
+ if (fd < 0)
+ {
+ if (my_net_write(net, (uchar*) "", 0))
+ error= errno ? errno : EPIPE;
+ net_flush(net);
+ }
+
+err:
+ my_free((uchar*) buf, MYF(0));
+ return error;
+}
+#endif /* HAVE_REPLICATION */
+
+ /* Name is here without an extension */
+
+int ha_maria::open(const char *name, int mode, uint test_if_locked)
+{
+ uint i;
+
+#ifdef NOT_USED
+ /*
+ If the user wants to have memory mapped data files, add an
+ open_flag. Do not memory map temporary tables because they are
+ expected to be inserted and thus extended a lot. Memory mapping is
+ efficient for files that keep their size, but very inefficient for
+ growing files. Using an open_flag instead of calling ma_extra(...
+ HA_EXTRA_MMAP ...) after maxs_open() has the advantage that the
+ mapping is not repeated for every open, but just done on the initial
+ open, when the MyISAM share is created. Every time the server
+ requires to open a new instance of a table it calls this method. We
+ will always supply HA_OPEN_MMAP for a permanent table. However, the
+ Maria storage engine will ignore this flag if this is a secondary
+ open of a table that is in use by other threads already (if the
+ Maria share exists already).
+ */
+ if (!(test_if_locked & HA_OPEN_TMP_TABLE) && opt_maria_use_mmap)
+ test_if_locked|= HA_OPEN_MMAP;
+#endif
+
+ if (unlikely(maria_recover_options != HA_RECOVER_NONE))
+ {
+ /* user asked to trigger a repair if table was not properly closed */
+ test_if_locked|= HA_OPEN_ABORT_IF_CRASHED;
+ }
+
+ if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
+ return (my_errno ? my_errno : -1);
+
+ if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
+ VOID(maria_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
+
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
+ VOID(maria_extra(file, HA_EXTRA_WAIT_LOCK, 0));
+ if ((data_file_type= file->s->data_file_type) != STATIC_RECORD)
+ int_table_flags |= HA_REC_NOT_IN_SEQ;
+ if (!file->s->base.born_transactional)
+ {
+ /*
+ INSERT DELAYED cannot work with transactional tables (because it cannot
+ stand up to "when client gets ok the data is safe on disk": the record
+ may not even be inserted). In the future, we could enable it back (as a
+ client doing INSERT DELAYED knows the specificities; but we then should
+ make sure to regularly commit in the delayed_insert thread).
+ */
+ int_table_flags|= HA_CAN_INSERT_DELAYED;
+ }
+ if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
+ int_table_flags |= HA_HAS_NEW_CHECKSUM;
+
+ for (i= 0; i < table->s->keys; i++)
+ {
+ plugin_ref parser= table->key_info[i].parser;
+ if (table->key_info[i].flags & HA_USES_PARSER)
+ file->s->keyinfo[i].parser=
+ (struct st_mysql_ftparser *)plugin_decl(parser)->info;
+ table->key_info[i].block_size= file->s->keyinfo[i].block_length;
+ }
+ my_errno= 0;
+ return my_errno;
+}
+
+
+int ha_maria::close(void)
+{
+ MARIA_HA *tmp= file;
+ file= 0;
+ return maria_close(tmp);
+}
+
+
+int ha_maria::write_row(uchar * buf)
+{
+ ha_statistic_increment(&SSV::ha_write_count);
+
+ /* If we have a timestamp column, update it to the current time */
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
+ table->timestamp_field->set_time();
+
+ /*
+ If we have an auto_increment column and we are writing a changed row
+ or a new row, then update the auto_increment value in the record.
+ */
+ if (table->next_number_field && buf == table->record[0])
+ {
+ int error;
+ if ((error= update_auto_increment()))
+ return error;
+ }
+ return maria_write(file, buf);
+}
+
+
+int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
+{
+ if (!file)
+ return HA_ADMIN_INTERNAL_ERROR;
+ int error;
+ HA_CHECK param;
+ MARIA_SHARE *share= file->s;
+ const char *old_proc_info= thd_proc_info(thd, "Checking table");
+
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "check";
+ param.db_name= table->s->db.str;
+ param.table_name= table->alias;
+ param.testflag= check_opt->flags | T_CHECK | T_SILENT;
+ param.stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
+
+ if (!(table->db_stat & HA_READ_ONLY))
+ param.testflag |= T_STATISTICS;
+ param.using_global_keycache= 1;
+
+ if (!maria_is_crashed(file) &&
+ (((param.testflag & T_CHECK_ONLY_CHANGED) &&
+ !(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
+ STATE_CRASHED_ON_REPAIR)) &&
+ share->state.open_count == 0) ||
+ ((param.testflag & T_FAST) && (share->state.open_count ==
+ (uint) (share->global_changed ? 1 :
+ 0)))))
+ return HA_ADMIN_ALREADY_DONE;
+
+ maria_chk_init_for_check(&param, file);
+ (void) maria_chk_status(&param, file); // Not fatal
+ error= maria_chk_size(&param, file);
+ if (!error)
+ error|= maria_chk_del(&param, file, param.testflag);
+ if (!error)
+ error= maria_chk_key(&param, file);
+ if (!error)
+ {
+ if ((!(param.testflag & T_QUICK) &&
+ ((share->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
+ (param.testflag & (T_EXTEND | T_MEDIUM)))) || maria_is_crashed(file))
+ {
+ ulonglong old_testflag= param.testflag;
+ param.testflag |= T_MEDIUM;
+ if (!(error= init_io_cache(&param.read_cache, file->dfile.file,
+ my_default_record_cache_size, READ_CACHE,
+ share->pack.header_length, 1, MYF(MY_WME))))
+ {
+ error= maria_chk_data_link(&param, file,
+ test(param.testflag & T_EXTEND));
+ end_io_cache(&(param.read_cache));
+ }
+ param.testflag= old_testflag;
+ }
+ }
+ if (!error)
+ {
+ if ((share->state.changed & (STATE_CHANGED |
+ STATE_CRASHED_ON_REPAIR |
+ STATE_CRASHED | STATE_NOT_ANALYZED)) ||
+ (param.testflag & T_STATISTICS) || maria_is_crashed(file))
+ {
+ file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ pthread_mutex_lock(&share->intern_lock);
+ share->state.changed &= ~(STATE_CHANGED | STATE_CRASHED |
+ STATE_CRASHED_ON_REPAIR);
+ if (!(table->db_stat & HA_READ_ONLY))
+ error= maria_update_state_info(&param, file,
+ UPDATE_TIME | UPDATE_OPEN_COUNT |
+ UPDATE_STAT);
+ pthread_mutex_unlock(&share->intern_lock);
+ info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
+ HA_STATUS_CONST);
+ }
+ }
+ else if (!maria_is_crashed(file) && !thd->killed)
+ {
+ maria_mark_crashed(file);
+ file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ }
+
+ thd_proc_info(thd, old_proc_info);
+ return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
+}
+
+
+/*
+ Analyze the key distribution in the table
+ As the table may be only locked for read, we have to take into account that
+ two threads may do an analyze at the same time!
+*/
+
+int ha_maria::analyze(THD *thd, HA_CHECK_OPT * check_opt)
+{
+ int error= 0;
+ HA_CHECK param;
+ MARIA_SHARE *share= file->s;
+
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "analyze";
+ param.db_name= table->s->db.str;
+ param.table_name= table->alias;
+ param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
+ T_DONT_CHECK_CHECKSUM);
+ param.using_global_keycache= 1;
+ param.stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
+
+ if (!(share->state.changed & STATE_NOT_ANALYZED))
+ return HA_ADMIN_ALREADY_DONE;
+
+ error= maria_chk_key(&param, file);
+ if (!error)
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ error= maria_update_state_info(&param, file, UPDATE_STAT);
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ else if (!maria_is_crashed(file) && !thd->killed)
+ maria_mark_crashed(file);
+ return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
+}
+
+
+int ha_maria::restore(THD * thd, HA_CHECK_OPT *check_opt)
+{
+ HA_CHECK_OPT tmp_check_opt;
+ char *backup_dir= thd->lex->backup_dir;
+ char src_path[FN_REFLEN], dst_path[FN_REFLEN];
+ char table_name[FN_REFLEN];
+ int error;
+ const char *errmsg;
+ DBUG_ENTER("restore");
+
+ VOID(tablename_to_filename(table->s->table_name.str, table_name,
+ sizeof(table_name)));
+
+ if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
+ MARIA_NAME_DEXT))
+ DBUG_RETURN(HA_ADMIN_INVALID);
+
+ strxmov(dst_path, table->s->normalized_path.str, MARIA_NAME_DEXT, NullS);
+ if (my_copy(src_path, dst_path, MYF(MY_WME)))
+ {
+ error= HA_ADMIN_FAILED;
+ errmsg= "Failed in my_copy (Error %d)";
+ goto err;
+ }
+
+ tmp_check_opt.init();
+ tmp_check_opt.flags |= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
+ DBUG_RETURN(repair(thd, &tmp_check_opt));
+
+err:
+ {
+ HA_CHECK param;
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "restore";
+ param.db_name= table->s->db.str;
+ param.table_name= table->s->table_name.str;
+ param.testflag= 0;
+ _ma_check_print_error(&param, errmsg, my_errno);
+ DBUG_RETURN(error);
+ }
+}
+
+
+int ha_maria::backup(THD * thd, HA_CHECK_OPT *check_opt)
+{
+ char *backup_dir= thd->lex->backup_dir;
+ char src_path[FN_REFLEN], dst_path[FN_REFLEN];
+ char table_name[FN_REFLEN];
+ int error;
+ const char *errmsg;
+ DBUG_ENTER("ha_maria::backup");
+
+ VOID(tablename_to_filename(table->s->table_name.str, table_name,
+ sizeof(table_name)));
+
+ if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
+ reg_ext))
+ {
+ errmsg= "Failed in fn_format() for .frm file (errno: %d)";
+ error= HA_ADMIN_INVALID;
+ goto err;
+ }
+
+ strxmov(src_path, table->s->normalized_path.str, reg_ext, NullS);
+ if (my_copy(src_path, dst_path,
+ MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
+ {
+ error= HA_ADMIN_FAILED;
+ errmsg= "Failed copying .frm file (errno: %d)";
+ goto err;
+ }
+
+ /* Change extension */
+ if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
+ MARIA_NAME_DEXT))
+ {
+ errmsg= "Failed in fn_format() for .MYD file (errno: %d)";
+ error= HA_ADMIN_INVALID;
+ goto err;
+ }
+
+ strxmov(src_path, table->s->normalized_path.str, MARIA_NAME_DEXT, NullS);
+ if (_ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_FORCE_WRITE,
+ FLUSH_KEEP))
+ {
+ error= HA_ADMIN_FAILED;
+ errmsg= "Failed in flush (Error %d)";
+ goto err;
+ }
+ if (my_copy(src_path, dst_path,
+ MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
+ {
+ errmsg= "Failed copying .MYD file (errno: %d)";
+ error= HA_ADMIN_FAILED;
+ goto err;
+ }
+ DBUG_RETURN(HA_ADMIN_OK);
+
+err:
+ {
+ HA_CHECK param;
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "backup";
+ param.db_name= table->s->db.str;
+ param.table_name= table->s->table_name.str;
+ param.testflag= 0;
+ _ma_check_print_error(&param, errmsg, my_errno);
+ DBUG_RETURN(error);
+ }
+}
+
+
+int ha_maria::repair(THD * thd, HA_CHECK_OPT *check_opt)
+{
+ int error;
+ HA_CHECK param;
+ ha_rows start_records;
+
+ if (!file)
+ return HA_ADMIN_INTERNAL_ERROR;
+
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "repair";
+ param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
+ T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
+ (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
+ param.sort_buffer_length= THDVAR(thd, sort_buffer_size);
+ start_records= file->state->records;
+ while ((error= repair(thd, &param, 0)) && param.retry_repair)
+ {
+ param.retry_repair= 0;
+ if (test_all_bits(param.testflag,
+ (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
+ {
+ param.testflag&= ~(T_RETRY_WITHOUT_QUICK | T_QUICK);
+ /* Ensure we don't loose any rows when retrying without quick */
+ param.testflag|= T_SAFE_REPAIR;
+ if (thd->vio_ok())
+ _ma_check_print_info(&param, "Retrying repair without quick");
+ else
+ sql_print_information("Retrying repair of: '%s' without quick",
+ table->s->path.str);
+ continue;
+ }
+ param.testflag &= ~T_QUICK;
+ if ((param.testflag & T_REP_BY_SORT))
+ {
+ param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
+ sql_print_information("Retrying repair of: '%s' with keycache",
+ table->s->path.str);
+ continue;
+ }
+ break;
+ }
+ if (!error && start_records != file->state->records &&
+ !(check_opt->flags & T_VERY_SILENT))
+ {
+ char llbuff[22], llbuff2[22];
+ sql_print_information("Found %s of %s rows when repairing '%s'",
+ llstr(file->state->records, llbuff),
+ llstr(start_records, llbuff2),
+ table->s->path.str);
+ }
+ return error;
+}
+
+int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt)
+{
+ int error;
+ HA_CHECK param;
+ MARIA_SHARE *share= file->s;
+
+ if (!file)
+ return HA_ADMIN_INTERNAL_ERROR;
+
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "zerofill";
+ param.testflag= check_opt->flags | T_SILENT | T_ZEROFILL;
+ param.sort_buffer_length= THDVAR(thd, sort_buffer_size);
+ error=maria_zerofill(&param, file, share->open_file_name.str);
+
+ if (!error)
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ maria_update_state_info(&param, file, UPDATE_TIME | UPDATE_OPEN_COUNT);
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ return error;
+}
+
+int ha_maria::optimize(THD * thd, HA_CHECK_OPT *check_opt)
+{
+ int error;
+ HA_CHECK param;
+ if (!file)
+ return HA_ADMIN_INTERNAL_ERROR;
+
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "optimize";
+ param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
+ T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
+ param.sort_buffer_length= THDVAR(thd, sort_buffer_size);
+ if ((error= repair(thd, &param, 1)) && param.retry_repair)
+ {
+ sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
+ my_errno, param.db_name, param.table_name);
+ param.testflag &= ~T_REP_BY_SORT;
+ error= repair(thd, &param, 1);
+ }
+ return error;
+}
+
+
+int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
+{
+ int error= 0;
+ ulonglong local_testflag= param->testflag;
+ bool optimize_done= !do_optimize, statistics_done= 0;
+ const char *old_proc_info= thd->proc_info;
+ char fixed_name[FN_REFLEN];
+ MARIA_SHARE *share= file->s;
+ ha_rows rows= file->state->records;
+ DBUG_ENTER("ha_maria::repair");
+
+ /*
+ Normally this method is entered with a properly opened table. If the
+ repair fails, it can be repeated with more elaborate options. Under
+ special circumstances it can happen that a repair fails so that it
+ closed the data file and cannot re-open it. In this case file->dfile
+ is set to -1. We must not try another repair without an open data
+ file. (Bug #25289)
+ */
+ if (file->dfile.file == -1)
+ {
+ sql_print_information("Retrying repair of: '%s' failed. "
+ "Please try REPAIR EXTENDED or maria_chk",
+ table->s->path.str);
+ DBUG_RETURN(HA_ADMIN_FAILED);
+ }
+
+ /*
+ If transactions was not enabled for a transactional table then
+ file->s->status is not up to date. This is needed for repair_by_sort
+ to work
+ */
+ if (share->base.born_transactional && !share->now_transactional)
+ _ma_copy_nontrans_state_information(file);
+
+ param->db_name= table->s->db.str;
+ param->table_name= table->alias;
+ param->tmpfile_createflag= O_RDWR | O_TRUNC;
+ param->using_global_keycache= 1;
+ param->thd= thd;
+ param->tmpdir= &mysql_tmpdir_list;
+ param->out_flag= 0;
+ strmov(fixed_name, share->open_file_name.str);
+
+ // Don't lock tables if we have used LOCK TABLE
+ if (!thd->locked_tables &&
+ maria_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
+ {
+ _ma_check_print_error(param, ER(ER_CANT_LOCK), my_errno);
+ DBUG_RETURN(HA_ADMIN_FAILED);
+ }
+
+ if (!do_optimize ||
+ ((share->data_file_type == BLOCK_RECORD) ?
+ (share->state.changed & STATE_NOT_OPTIMIZED_ROWS) :
+ (file->state->del || share->state.split != file->state->records)) &&
+ (!(param->testflag & T_QUICK) ||
+ (share->state.changed & (STATE_NOT_OPTIMIZED_KEYS |
+ STATE_NOT_OPTIMIZED_ROWS))))
+ {
+ ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
+ maria_get_mask_all_keys_active(share->base.keys) :
+ share->state.key_map);
+ ulonglong save_testflag= param->testflag;
+ if (maria_test_if_sort_rep(file, file->state->records, key_map, 0) &&
+ (local_testflag & T_REP_BY_SORT))
+ {
+ local_testflag |= T_STATISTICS;
+ param->testflag |= T_STATISTICS; // We get this for free
+ statistics_done= 1;
+ /* TODO: Remove BLOCK_RECORD test when parallel works with blocks */
+ if (THDVAR(thd,repair_threads) > 1 &&
+ share->data_file_type != BLOCK_RECORD)
+ {
+ char buf[40];
+ /* TODO: respect maria_repair_threads variable */
+ my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
+ thd_proc_info(thd, buf);
+ param->testflag|= T_REP_PARALLEL;
+ error= maria_repair_parallel(param, file, fixed_name,
+ test(param->testflag & T_QUICK));
+ /* to reset proc_info, as it was pointing to local buffer */
+ thd_proc_info(thd, "Repair done");
+ }
+ else
+ {
+ thd_proc_info(thd, "Repair by sorting");
+ param->testflag|= T_REP_BY_SORT;
+ error= maria_repair_by_sort(param, file, fixed_name,
+ test(param->testflag & T_QUICK));
+ }
+ }
+ else
+ {
+ thd_proc_info(thd, "Repair with keycache");
+ param->testflag &= ~(T_REP_BY_SORT | T_REP_PARALLEL);
+ error= maria_repair(param, file, fixed_name,
+ test(param->testflag & T_QUICK));
+ }
+ param->testflag= save_testflag | (param->testflag & T_RETRY_WITHOUT_QUICK);
+ optimize_done= 1;
+ }
+ if (!error)
+ {
+ if ((local_testflag & T_SORT_INDEX) &&
+ (share->state.changed & STATE_NOT_SORTED_PAGES))
+ {
+ optimize_done= 1;
+ thd_proc_info(thd, "Sorting index");
+ error= maria_sort_index(param, file, fixed_name);
+ }
+ if (!statistics_done && (local_testflag & T_STATISTICS))
+ {
+ if (share->state.changed & STATE_NOT_ANALYZED)
+ {
+ optimize_done= 1;
+ thd_proc_info(thd, "Analyzing");
+ error= maria_chk_key(param, file);
+ }
+ else
+ local_testflag &= ~T_STATISTICS; // Don't update statistics
+ }
+ }
+ thd_proc_info(thd, "Saving state");
+ pthread_mutex_lock(&share->intern_lock);
+ if (!error)
+ {
+ if ((share->state.changed & STATE_CHANGED) || maria_is_crashed(file))
+ {
+ share->state.changed &= ~(STATE_CHANGED | STATE_CRASHED |
+ STATE_CRASHED_ON_REPAIR);
+ file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ }
+ /*
+ repair updates share->state.state. Ensure that file->state is up to date
+ */
+ if (file->state != &share->state.state)
+ *file->state= share->state.state;
+ if (share->base.auto_key)
+ _ma_update_auto_increment_key(param, file, 1);
+ if (optimize_done)
+ error= maria_update_state_info(param, file,
+ UPDATE_TIME | UPDATE_OPEN_COUNT |
+ (local_testflag &
+ T_STATISTICS ? UPDATE_STAT : 0));
+ info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
+ HA_STATUS_CONST, 0);
+ if (rows != file->state->records && !(param->testflag & T_VERY_SILENT))
+ {
+ char llbuff[22], llbuff2[22];
+ _ma_check_print_warning(param, "Number of rows changed from %s to %s",
+ llstr(rows, llbuff),
+ llstr(file->state->records, llbuff2));
+ /* Abort if warning was converted to error */
+ if (current_thd->is_error())
+ error= 1;
+ }
+ }
+ else
+ {
+ maria_mark_crashed_on_repair(file);
+ file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ maria_update_state_info(param, file, 0);
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+ thd_proc_info(thd, old_proc_info);
+ if (!thd->locked_tables)
+ maria_lock_database(file, F_UNLCK);
+ error= error ? HA_ADMIN_FAILED :
+ (optimize_done ?
+ (write_log_record_for_repair(param, file) ? HA_ADMIN_FAILED :
+ HA_ADMIN_OK) : HA_ADMIN_ALREADY_DONE);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Assign table indexes to a specific key cache.
+*/
+
+int ha_maria::assign_to_keycache(THD * thd, HA_CHECK_OPT *check_opt)
+{
+#if 0 && NOT_IMPLEMENTED
+ PAGECACHE *new_pagecache= check_opt->pagecache;
+ const char *errmsg= 0;
+ int error= HA_ADMIN_OK;
+ ulonglong map;
+ TABLE_LIST *table_list= table->pos_in_table_list;
+ DBUG_ENTER("ha_maria::assign_to_keycache");
+
+
+ table->keys_in_use_for_query.clear_all();
+
+ if (table_list->process_index_hints(table))
+ DBUG_RETURN(HA_ADMIN_FAILED);
+ map= ~(ulonglong) 0;
+ if (!table->keys_in_use_for_query.is_clear_all())
+ /* use all keys if there's no list specified by the user through hints */
+ map= table->keys_in_use_for_query.to_ulonglong();
+
+ if ((error= maria_assign_to_pagecache(file, map, new_pagecache)))
+ {
+ char buf[STRING_BUFFER_USUAL_SIZE];
+ my_snprintf(buf, sizeof(buf),
+ "Failed to flush to index file (errno: %d)", error);
+ errmsg= buf;
+ error= HA_ADMIN_CORRUPT;
+ }
+
+ if (error != HA_ADMIN_OK)
+ {
+ /* Send error to user */
+ HA_CHECK param;
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "assign_to_keycache";
+ param.db_name= table->s->db.str;
+ param.table_name= table->s->table_name.str;
+ param.testflag= 0;
+ _ma_check_print_error(&param, errmsg);
+ }
+ DBUG_RETURN(error);
+#else
+ return HA_ADMIN_NOT_IMPLEMENTED;
+#endif
+}
+
+
+/*
+ Preload pages of the index file for a table into the key cache.
+*/
+
+int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt)
+{
+ ulonglong map;
+ TABLE_LIST *table_list= table->pos_in_table_list;
+
+ DBUG_ENTER("ha_maria::preload_keys");
+
+ table->keys_in_use_for_query.clear_all();
+
+ if (table_list->process_index_hints(table))
+ DBUG_RETURN(HA_ADMIN_FAILED);
+
+ map= ~(ulonglong) 0;
+ /* Check validity of the index references */
+ if (!table->keys_in_use_for_query.is_clear_all())
+ /* use all keys if there's no list specified by the user through hints */
+ map= table->keys_in_use_for_query.to_ulonglong();
+
+ maria_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
+ (void*) &thd->variables.preload_buff_size);
+
+ int error;
+
+ if ((error= maria_preload(file, map, table_list->ignore_leaves)))
+ {
+ char buf[ERRMSGSIZE+20];
+ const char *errmsg;
+
+ switch (error) {
+ case HA_ERR_NON_UNIQUE_BLOCK_SIZE:
+ errmsg= "Indexes use different block sizes";
+ break;
+ case HA_ERR_OUT_OF_MEM:
+ errmsg= "Failed to allocate buffer";
+ break;
+ default:
+ my_snprintf(buf, ERRMSGSIZE,
+ "Failed to read from index file (errno: %d)", my_errno);
+ errmsg= buf;
+ }
+
+ HA_CHECK param;
+ maria_chk_init(&param);
+ param.thd= thd;
+ param.op_name= "preload_keys";
+ param.db_name= table->s->db.str;
+ param.table_name= table->s->table_name.str;
+ param.testflag= 0;
+ _ma_check_print_error(&param, errmsg);
+ DBUG_RETURN(HA_ADMIN_FAILED);
+ }
+ DBUG_RETURN(HA_ADMIN_OK);
+}
+
+
+/*
+ Disable indexes, making it persistent if requested.
+
+ SYNOPSIS
+ disable_indexes()
+ mode mode of operation:
+ HA_KEY_SWITCH_NONUNIQ disable all non-unique keys
+ HA_KEY_SWITCH_ALL disable all keys
+ HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
+ HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent
+
+ IMPLEMENTATION
+ HA_KEY_SWITCH_NONUNIQ is not implemented.
+ HA_KEY_SWITCH_ALL_SAVE is not implemented.
+
+ RETURN
+ 0 ok
+ HA_ERR_WRONG_COMMAND mode not implemented.
+*/
+
+int ha_maria::disable_indexes(uint mode)
+{
+ int error;
+
+ if (mode == HA_KEY_SWITCH_ALL)
+ {
+ /* call a storage engine function to switch the key map */
+ error= maria_disable_indexes(file);
+ }
+ else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
+ {
+ maria_extra(file, HA_EXTRA_NO_KEYS, 0);
+ info(HA_STATUS_CONST); // Read new key info
+ error= 0;
+ }
+ else
+ {
+ /* mode not implemented */
+ error= HA_ERR_WRONG_COMMAND;
+ }
+ return error;
+}
+
+
+/*
+ Enable indexes, making it persistent if requested.
+
+ SYNOPSIS
+ enable_indexes()
+ mode mode of operation:
+ HA_KEY_SWITCH_NONUNIQ enable all non-unique keys
+ HA_KEY_SWITCH_ALL enable all keys
+ HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
+ HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent
+
+ DESCRIPTION
+ Enable indexes, which might have been disabled by disable_index() before.
+ The modes without _SAVE work only if both data and indexes are empty,
+ since the MARIA repair would enable them persistently.
+ To be sure in these cases, call handler::delete_all_rows() before.
+
+ IMPLEMENTATION
+ HA_KEY_SWITCH_NONUNIQ is not implemented.
+ HA_KEY_SWITCH_ALL_SAVE is not implemented.
+
+ RETURN
+ 0 ok
+ !=0 Error, among others:
+ HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry.
+ HA_ERR_WRONG_COMMAND mode not implemented.
+*/
+
+int ha_maria::enable_indexes(uint mode)
+{
+ int error;
+ DBUG_PRINT("info", ("ha_maria::enable_indexes mode: %d", mode));
+ if (maria_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
+ {
+ /* All indexes are enabled already. */
+ return 0;
+ }
+
+ if (mode == HA_KEY_SWITCH_ALL)
+ {
+ error= maria_enable_indexes(file);
+ /*
+ Do not try to repair on error,
+ as this could make the enabled state persistent,
+ but mode==HA_KEY_SWITCH_ALL forbids it.
+ */
+ }
+ else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
+ {
+ THD *thd= current_thd;
+ HA_CHECK param;
+ const char *save_proc_info= thd_proc_info(thd, "Creating index");
+ maria_chk_init(&param);
+ param.op_name= "recreating_index";
+ param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
+ T_CREATE_MISSING_KEYS | T_SAFE_REPAIR);
+ if (bulk_insert_single_undo == BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR)
+ {
+ bulk_insert_single_undo= BULK_INSERT_SINGLE_UNDO_AND_REPAIR;
+ /*
+ Don't bump create_rename_lsn, because UNDO_BULK_INSERT
+ should not be skipped in case of crash during repair.
+ */
+ param.testflag|= T_NO_CREATE_RENAME_LSN;
+ }
+ param.myf_rw &= ~MY_WAIT_IF_FULL;
+ param.sort_buffer_length= THDVAR(thd,sort_buffer_size);
+ param.stats_method= (enum_handler_stats_method)THDVAR(thd,stats_method);
+ param.tmpdir= &mysql_tmpdir_list;
+ if ((error= (repair(thd, &param, 0) != HA_ADMIN_OK)) && param.retry_repair)
+ {
+ sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, "
+ "retrying",
+ my_errno, param.db_name, param.table_name);
+ /* This should never fail normally */
+ DBUG_ASSERT(0);
+ /* Repairing by sort failed. Now try standard repair method. */
+ param.testflag &= ~T_REP_BY_SORT;
+ error= (repair(thd, &param, 0) != HA_ADMIN_OK);
+ /*
+ If the standard repair succeeded, clear all error messages which
+ might have been set by the first repair. They can still be seen
+ with SHOW WARNINGS then.
+ */
+ if (!error)
+ thd->clear_error();
+ }
+ info(HA_STATUS_CONST);
+ thd_proc_info(thd, save_proc_info);
+ }
+ else
+ {
+ /* mode not implemented */
+ error= HA_ERR_WRONG_COMMAND;
+ }
+ DBUG_EXECUTE_IF("maria_flush_whole_log",
+ {
+ DBUG_PRINT("maria_flush_whole_log", ("now"));
+ translog_flush(translog_get_horizon());
+ });
+ DBUG_EXECUTE_IF("maria_crash_enable_index",
+ {
+ DBUG_PRINT("maria_crash_enable_index", ("now"));
+ DBUG_ABORT();
+ });
+ return error;
+}
+
+
+/*
+ Test if indexes are disabled.
+
+
+ SYNOPSIS
+ indexes_are_disabled()
+ no parameters
+
+
+ RETURN
+ 0 indexes are not disabled
+ 1 all indexes are disabled
+ [2 non-unique indexes are disabled - NOT YET IMPLEMENTED]
+*/
+
+int ha_maria::indexes_are_disabled(void)
+{
+ return maria_indexes_are_disabled(file);
+}
+
+
+/*
+ prepare for a many-rows insert operation
+ e.g. - disable indexes (if they can be recreated fast) or
+ activate special bulk-insert optimizations
+
+ SYNOPSIS
+ start_bulk_insert(rows)
+ rows Rows to be inserted
+ 0 if we don't know
+
+ NOTICE
+ Do not forget to call end_bulk_insert() later!
+*/
+
+void ha_maria::start_bulk_insert(ha_rows rows)
+{
+ DBUG_ENTER("ha_maria::start_bulk_insert");
+ THD *thd= current_thd;
+ ulong size= min(thd->variables.read_buff_size,
+ (ulong) (table->s->avg_row_length * rows));
+ MARIA_SHARE *share= file->s;
+ DBUG_PRINT("info", ("start_bulk_insert: rows %lu size %lu",
+ (ulong) rows, size));
+
+ /* don't enable row cache if too few rows */
+ if (!rows || (rows > MARIA_MIN_ROWS_TO_USE_WRITE_CACHE))
+ maria_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
+
+ can_enable_indexes= (maria_is_all_keys_active(share->state.key_map,
+ share->base.keys));
+ bulk_insert_single_undo= BULK_INSERT_NONE;
+
+ if (!(specialflag & SPECIAL_SAFE_MODE))
+ {
+ /*
+ Only disable old index if the table was empty and we are inserting
+ a lot of rows.
+ We should not do this for only a few rows as this is slower and
+ we don't want to update the key statistics based of only a few rows.
+ Index file rebuild requires an exclusive lock, so if versioning is on
+ don't do it (see how ha_maria::store_lock() tries to predict repair).
+ We can repair index only if we have an exclusive (TL_WRITE) lock. To
+ see if table is empty, we shouldn't rely on the old records' count from
+ our transaction's start (if that old count is 0 but now there are
+ records in the table, we would wrongly destroy them).
+ So we need to look at share->state.state.records.
+ As a safety net for now, we don't remove the test of
+ file->state->records, because there is uncertainty on what will happen
+ during repair if the two states disagree.
+ */
+ if ((file->state->records == 0) &&
+ (share->state.state.records == 0) && can_enable_indexes &&
+ (!rows || rows >= MARIA_MIN_ROWS_TO_DISABLE_INDEXES) &&
+ (file->lock.type == TL_WRITE))
+ {
+ /**
+ @todo for a single-row INSERT SELECT, we will go into repair, which
+ is more costly (flushes, syncs) than a row write.
+ */
+ maria_disable_non_unique_index(file, rows);
+ if (share->now_transactional)
+ {
+ bulk_insert_single_undo= BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR;
+ write_log_record_for_bulk_insert(file);
+ _ma_tmp_disable_logging_for_table(file, TRUE);
+ /*
+ Pages currently in the page cache have type PAGECACHE_LSN_PAGE, we
+ are not allowed to overwrite them with PAGECACHE_PLAIN_PAGE, so
+ throw them away. It is not losing data, because we just wrote and
+ forced an UNDO which will for sure empty the table if we crash. The
+ upcoming unique-key insertions however need a proper index, so we
+ cannot leave the corrupted on-disk index file, thus we truncate it.
+ */
+ maria_delete_all_rows(file);
+ }
+ }
+ else if (!file->bulk_insert &&
+ (!rows || rows >= MARIA_MIN_ROWS_TO_USE_BULK_INSERT))
+ {
+ maria_init_bulk_insert(file, thd->variables.bulk_insert_buff_size, rows);
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ end special bulk-insert optimizations,
+ which have been activated by start_bulk_insert().
+
+ SYNOPSIS
+ end_bulk_insert()
+ no arguments
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
+int ha_maria::end_bulk_insert(bool table_will_be_deleted)
+{
+ int err;
+ DBUG_ENTER("ha_maria::end_bulk_insert");
+ maria_end_bulk_insert(file, table_will_be_deleted);
+ if ((err= maria_extra(file, HA_EXTRA_NO_CACHE, 0)))
+ goto end;
+ if (can_enable_indexes && !table_will_be_deleted)
+ err= enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
+end:
+ if (bulk_insert_single_undo != BULK_INSERT_NONE)
+ {
+ DBUG_ASSERT(can_enable_indexes);
+ /*
+ Table was transactional just before start_bulk_insert().
+ No need to flush pages if we did a repair (which already flushed).
+ */
+ err|=
+ _ma_reenable_logging_for_table(file,
+ bulk_insert_single_undo ==
+ BULK_INSERT_SINGLE_UNDO_AND_NO_REPAIR);
+ }
+ DBUG_RETURN(err);
+}
+
+
+bool ha_maria::check_and_repair(THD *thd)
+{
+ int error, crashed;
+ char *old_query;
+ uint old_query_length;
+ HA_CHECK_OPT check_opt;
+ DBUG_ENTER("ha_maria::check_and_repair");
+
+ check_opt.init();
+
+ if (file->s->state.changed & STATE_MOVED)
+ {
+ sql_print_information("Zerofilling table: '%s'", table->s->path.str);
+ if (!(error= zerofill(thd, &check_opt)))
+ DBUG_RETURN(0);
+ }
+ else
+ error= 1;
+
+ /*
+ if we got this far - the table is crashed.
+ but don't auto-repair if maria_recover_options is not set
+ */
+ if (!maria_recover_options)
+ DBUG_RETURN(error);
+
+ error= 0;
+ check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
+ // Don't use quick if deleted rows
+ if (!file->state->del && (maria_recover_options & HA_RECOVER_QUICK))
+ check_opt.flags |= T_QUICK;
+
+ old_query= thd->query;
+ old_query_length= thd->query_length;
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->query= table->s->table_name.str;
+ thd->query_length= table->s->table_name.length;
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ if (!(crashed= maria_is_crashed(file)))
+ {
+ sql_print_warning("Checking table: '%s'", table->s->path.str);
+ crashed= check(thd, &check_opt);
+ }
+
+ if (crashed)
+ {
+ sql_print_warning("Recovering table: '%s'", table->s->path.str);
+ check_opt.flags=
+ ((maria_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
+ (maria_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
+ T_AUTO_REPAIR);
+ if (repair(thd, &check_opt))
+ error= 1;
+ }
+ pthread_mutex_lock(&LOCK_thread_count);
+ thd->query= old_query;
+ thd->query_length= old_query_length;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_RETURN(error);
+}
+
+
+bool ha_maria::is_crashed() const
+{
+ return (file->s->state.changed & (STATE_CRASHED | STATE_MOVED) ||
+ (my_disable_locking && file->s->state.open_count));
+}
+
+#define CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING(msg) \
+ do { \
+ if (file->lock.type == TL_WRITE_CONCURRENT_INSERT) \
+ { \
+ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), msg); \
+ return 1; \
+ } \
+ } while(0)
+
+int ha_maria::update_row(const uchar * old_data, uchar * new_data)
+{
+ CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("UPDATE in WRITE CONCURRENT");
+ ha_statistic_increment(&SSV::ha_update_count);
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
+ table->timestamp_field->set_time();
+ return maria_update(file, old_data, new_data);
+}
+
+
+int ha_maria::delete_row(const uchar * buf)
+{
+ CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("DELETE in WRITE CONCURRENT");
+ ha_statistic_increment(&SSV::ha_delete_count);
+ return maria_delete(file, buf);
+}
+
+
+int ha_maria::index_read_map(uchar * buf, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+{
+ DBUG_ASSERT(inited == INDEX);
+ ha_statistic_increment(&SSV::ha_read_key_count);
+ int error= maria_rkey(file, buf, active_index, key, keypart_map, find_flag);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::index_read_idx_map(uchar * buf, uint index, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+{
+ ha_statistic_increment(&SSV::ha_read_key_count);
+ int error= maria_rkey(file, buf, index, key, keypart_map, find_flag);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::index_read_last_map(uchar * buf, const uchar * key,
+ key_part_map keypart_map)
+{
+ DBUG_ENTER("ha_maria::index_read_last_map");
+ DBUG_ASSERT(inited == INDEX);
+ ha_statistic_increment(&SSV::ha_read_key_count);
+ int error= maria_rkey(file, buf, active_index, key, keypart_map,
+ HA_READ_PREFIX_LAST);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ DBUG_RETURN(error);
+}
+
+
+int ha_maria::index_next(uchar * buf)
+{
+ DBUG_ASSERT(inited == INDEX);
+ ha_statistic_increment(&SSV::ha_read_next_count);
+ int error= maria_rnext(file, buf, active_index);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::index_prev(uchar * buf)
+{
+ DBUG_ASSERT(inited == INDEX);
+ ha_statistic_increment(&SSV::ha_read_prev_count);
+ int error= maria_rprev(file, buf, active_index);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::index_first(uchar * buf)
+{
+ DBUG_ASSERT(inited == INDEX);
+ ha_statistic_increment(&SSV::ha_read_first_count);
+ int error= maria_rfirst(file, buf, active_index);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::index_last(uchar * buf)
+{
+ DBUG_ASSERT(inited == INDEX);
+ ha_statistic_increment(&SSV::ha_read_last_count);
+ int error= maria_rlast(file, buf, active_index);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::index_next_same(uchar * buf,
+ const uchar *key __attribute__ ((unused)),
+ uint length __attribute__ ((unused)))
+{
+ int error;
+ DBUG_ASSERT(inited == INDEX);
+ ha_statistic_increment(&SSV::ha_read_next_count);
+ /*
+ TODO: Delete this loop in Maria 1.5 as versioning will ensure this never
+ happens
+ */
+ do
+ {
+ error= maria_rnext_same(file,buf);
+ } while (error == HA_ERR_RECORD_DELETED);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::rnd_init(bool scan)
+{
+ if (scan)
+ return maria_scan_init(file);
+ return maria_reset(file); // Free buffers
+}
+
+
+int ha_maria::rnd_end()
+{
+ /* Safe to call even if we don't have started a scan */
+ maria_scan_end(file);
+ return 0;
+}
+
+
+int ha_maria::rnd_next(uchar *buf)
+{
+ ha_statistic_increment(&SSV::ha_read_rnd_next_count);
+ int error= maria_scan(file, buf);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+int ha_maria::remember_rnd_pos()
+{
+ return (*file->s->scan_remember_pos)(file, &remember_pos);
+}
+
+
+int ha_maria::restart_rnd_next(uchar *buf)
+{
+ (*file->s->scan_restore_pos)(file, remember_pos);
+ return rnd_next(buf);
+}
+
+
+int ha_maria::rnd_pos(uchar *buf, uchar *pos)
+{
+ ha_statistic_increment(&SSV::ha_read_rnd_count);
+ int error= maria_rrnd(file, buf, my_get_ptr(pos, ref_length));
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+void ha_maria::position(const uchar *record)
+{
+ my_off_t row_position= maria_position(file);
+ my_store_ptr(ref, ref_length, row_position);
+}
+
+
+int ha_maria::info(uint flag)
+{
+ return info(flag, table->s->tmp_table == NO_TMP_TABLE);
+}
+
+int ha_maria::info(uint flag, my_bool lock_table_share)
+{
+ MARIA_INFO maria_info;
+ char name_buff[FN_REFLEN];
+
+ (void) maria_status(file, &maria_info, flag);
+ if (flag & HA_STATUS_VARIABLE)
+ {
+ stats.records= maria_info.records;
+ stats.deleted= maria_info.deleted;
+ stats.data_file_length= maria_info.data_file_length;
+ stats.index_file_length= maria_info.index_file_length;
+ stats.delete_length= maria_info.delete_length;
+ stats.check_time= maria_info.check_time;
+ stats.mean_rec_length= maria_info.mean_reclength;
+ }
+ if (flag & HA_STATUS_CONST)
+ {
+ TABLE_SHARE *share= table->s;
+ stats.max_data_file_length= maria_info.max_data_file_length;
+ stats.max_index_file_length= maria_info.max_index_file_length;
+ stats.create_time= maria_info.create_time;
+ ref_length= maria_info.reflength;
+ share->db_options_in_use= maria_info.options;
+ stats.block_size= maria_block_size;
+
+ /* Update share */
+ if (lock_table_share)
+ pthread_mutex_lock(&share->mutex);
+ share->keys_in_use.set_prefix(share->keys);
+ share->keys_in_use.intersect_extended(maria_info.key_map);
+ share->keys_for_keyread.intersect(share->keys_in_use);
+ share->db_record_offset= maria_info.record_offset;
+ if (share->key_parts)
+ {
+ ulong *to= table->key_info[0].rec_per_key, *end;
+ double *from= maria_info.rec_per_key;
+ for (end= to+ share->key_parts ; to < end ; to++, from++)
+ *to= (ulong) (*from + 0.5);
+ }
+ if (lock_table_share)
+ pthread_mutex_unlock(&share->mutex);
+
+ /*
+ Set data_file_name and index_file_name to point at the symlink value
+ if table is symlinked (Ie; Real name is not same as generated name)
+ */
+ data_file_name= index_file_name= 0;
+ fn_format(name_buff, file->s->open_file_name.str, "", MARIA_NAME_DEXT,
+ MY_APPEND_EXT | MY_UNPACK_FILENAME);
+ if (strcmp(name_buff, maria_info.data_file_name))
+ data_file_name =maria_info.data_file_name;
+ fn_format(name_buff, file->s->open_file_name.str, "", MARIA_NAME_IEXT,
+ MY_APPEND_EXT | MY_UNPACK_FILENAME);
+ if (strcmp(name_buff, maria_info.index_file_name))
+ index_file_name=maria_info.index_file_name;
+ }
+ if (flag & HA_STATUS_ERRKEY)
+ {
+ errkey= maria_info.errkey;
+ my_store_ptr(dup_ref, ref_length, maria_info.dup_key_pos);
+ }
+ /* Faster to always update, than to do it based on flag */
+ stats.update_time= maria_info.update_time;
+ stats.auto_increment_value= maria_info.auto_increment;
+
+ return 0;
+}
+
+
+int ha_maria::extra(enum ha_extra_function operation)
+{
+ if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD)
+ return 0;
+
+ /*
+ We have to set file->trn here because in some cases we call
+ extern_lock(F_UNLOCK) (which resets file->trn) followed by maria_close()
+ without calling commit/rollback in between. If file->trn is not set
+ we can't remove file->share from the transaction list in the extra() call.
+ */
+
+ if (!file->trn &&
+ (operation == HA_EXTRA_PREPARE_FOR_DROP ||
+ operation == HA_EXTRA_PREPARE_FOR_RENAME))
+ {
+ THD *thd= table->in_use;
+ TRN *trn= THD_TRN;
+ _ma_set_trn_for_table(file, trn);
+ }
+ return maria_extra(file, operation, 0);
+}
+
+int ha_maria::reset(void)
+{
+ return maria_reset(file);
+}
+
+/* To be used with WRITE_CACHE and EXTRA_CACHE */
+
+int ha_maria::extra_opt(enum ha_extra_function operation, ulong cache_size)
+{
+ if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
+ return 0;
+ return maria_extra(file, operation, (void*) &cache_size);
+}
+
+
+int ha_maria::delete_all_rows()
+{
+ THD *thd= current_thd;
+ (void) translog_log_debug_info(file->trn, LOGREC_DEBUG_INFO_QUERY,
+ (uchar*) thd->query, thd->query_length);
+ if (file->s->now_transactional &&
+ ((table->in_use->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
+ table->in_use->locked_tables))
+ {
+ /*
+ We are not in autocommit mode or user have done LOCK TABLES.
+ We must do the delete row by row to be able to rollback the command
+ */
+ return HA_ERR_WRONG_COMMAND;
+ }
+ return maria_delete_all_rows(file);
+}
+
+
+int ha_maria::delete_table(const char *name)
+{
+ THD *thd= current_thd;
+ (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY,
+ (uchar*) thd->query, thd->query_length);
+ return maria_delete_table(name);
+}
+
+int ha_maria::external_lock(THD *thd, int lock_type)
+{
+ TRN *trn= THD_TRN;
+ DBUG_ENTER("ha_maria::external_lock");
+ /*
+ We don't test now_transactional because it may vary between lock/unlock
+ and thus confuse our reference counting.
+ It is critical to skip non-transactional tables: user-visible temporary
+ tables get an external_lock() when read/written for the first time, but no
+ corresponding unlock (they just stay locked and are later dropped while
+ locked); if a tmp table was transactional, "SELECT FROM non_tmp, tmp"
+ would never commit as its "locked_tables" count would stay 1.
+ When Maria has has_transactions()==TRUE, open_temporary_table()
+ (sql_base.cc) will use TRANSACTIONAL_TMP_TABLE and thus the
+ external_lock(F_UNLCK) will happen and we can then allow the user to
+ create transactional temporary tables.
+ */
+ if (file->s->base.born_transactional)
+ {
+ /* Transactional table */
+ if (lock_type != F_UNLCK)
+ {
+ /* Start of new statement */
+ if (!trn) /* no transaction yet - open it now */
+ {
+ trn= trnman_new_trn(& thd->transaction.wt);
+ if (unlikely(!trn))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ THD_TRN= trn;
+ if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+ trans_register_ha(thd, TRUE, maria_hton);
+ }
+ _ma_set_trn_for_table(file, trn);
+ if (!trnman_increment_locked_tables(trn))
+ {
+ trans_register_ha(thd, FALSE, maria_hton);
+ trnman_new_statement(trn);
+ }
+
+ if (!file->s->lock_key_trees) // If we don't use versioning
+ {
+ /*
+ We come here in the following cases:
+ - The table is a temporary table
+ - It's a table which is crash safe but not yet versioned, for
+ example a table with fulltext or rtree keys
+
+ Set the current state to point to save_state so that the
+ block_format code don't count the same record twice.
+ Copy also the current state. This may have been wrong if the
+ same file was used several times in the last statement
+ */
+ file->state= file->state_start;
+ *file->state= file->s->state.state;
+ }
+
+ if (!thd->transaction.on)
+ {
+ /*
+ No need to log REDOs/UNDOs. If this is an internal temporary table
+ which will be renamed to a permanent table (like in ALTER TABLE),
+ the rename happens after unlocking so will be durable (and the table
+ will get its create_rename_lsn).
+ Note: if we wanted to enable users to have an old backup and apply
+ tons of archived logs to roll-forward, we could then not disable
+ REDOs/UNDOs in this case.
+ */
+ DBUG_PRINT("info", ("Disabling logging for table"));
+ _ma_tmp_disable_logging_for_table(file, TRUE);
+ }
+#ifdef EXTRA_DEBUG
+ if (lock_type == F_WRLCK &&
+ ! (trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED))
+ {
+ trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED |
+ TRN_STATE_TABLES_CAN_CHANGE);
+ (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY,
+ (uchar*) thd->query, thd->query_length);
+ }
+#endif
+ }
+ else
+ {
+ /* End of transaction */
+
+ /*
+ We always re-enable, don't rely on thd->transaction.on as it is
+ sometimes reset to true after unlocking (see mysql_truncate() for a
+ partitioned table based on Maria).
+ Note that we can come here without having an exclusive lock on the
+ table, for example in this case:
+ external_lock(F_(WR|RD)LCK); thr_lock() which fails due to lock
+ abortion; external_lock(F_UNLCK). Fortunately, the re-enabling happens
+ only if we were the thread which disabled logging.
+ */
+ if (_ma_reenable_logging_for_table(file, TRUE))
+ DBUG_RETURN(1);
+ /** @todo zero file->trn also in commit and rollback */
+ _ma_set_trn_for_table(file, NULL); // Safety
+ /*
+ Ensure that file->state points to the current number of rows. This
+ is needed if someone calls maria_info() without first doing an
+ external lock of the table
+ */
+ file->state= &file->s->state.state;
+ if (trn)
+ {
+ if (trnman_has_locked_tables(trn) &&
+ !trnman_decrement_locked_tables(trn))
+ {
+ /*
+ OK should not have been sent to client yet (ACID).
+ This is a bit excessive, ACID requires this only if there are some
+ changes to commit (rollback shouldn't be tested).
+ */
+ DBUG_ASSERT(!thd->main_da.is_sent ||
+ thd->killed == THD::KILL_CONNECTION);
+ /* autocommit ? rollback a transaction */
+#ifdef MARIA_CANNOT_ROLLBACK
+ if (ma_commit(trn))
+ DBUG_RETURN(1);
+ THD_TRN= 0;
+#else
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ {
+ trnman_rollback_trn(trn);
+ DBUG_PRINT("info", ("THD_TRN set to 0x0"));
+ THD_TRN= 0;
+ }
+#endif
+ }
+ trnman_set_flags(trn, trnman_get_flags(trn) & ~ TRN_STATE_INFO_LOGGED);
+ }
+ }
+ } /* if transactional table */
+ DBUG_RETURN(maria_lock_database(file, !table->s->tmp_table ?
+ lock_type : ((lock_type == F_UNLCK) ?
+ F_UNLCK : F_EXTRA_LCK)));
+}
+
+int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
+{
+ TRN *trn;
+ if (file->s->base.born_transactional)
+ {
+ trn= THD_TRN;
+ DBUG_ASSERT(trn); // this may be called only after external_lock()
+ DBUG_ASSERT(trnman_has_locked_tables(trn));
+ DBUG_ASSERT(lock_type != TL_UNLOCK);
+ DBUG_ASSERT(file->trn == trn);
+
+ /*
+ If there was an implicit commit under this LOCK TABLES by a previous
+ statement (like a DDL), at least if that previous statement was about a
+ different ha_maria than 'this' then this->file->trn is a stale
+ pointer. We fix it:
+ */
+ _ma_set_trn_for_table(file, trn);
+ /*
+ As external_lock() was already called, don't increment locked_tables.
+ Note that we call the function below possibly several times when
+ statement starts (once per table). This is ok as long as that function
+ does cheap operations. Otherwise, we will need to do it only on first
+ call to start_stmt().
+ */
+ trnman_new_statement(trn);
+
+#ifdef EXTRA_DEBUG
+ if (!(trnman_get_flags(trn) & TRN_STATE_INFO_LOGGED) &&
+ trnman_get_flags(trn) & TRN_STATE_TABLES_CAN_CHANGE)
+ {
+ trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED);
+ (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY,
+ (uchar*) thd->query, thd->query_length);
+ }
+#endif
+ }
+ return 0;
+}
+
+
+/**
+ Performs an implicit commit of the Maria transaction and creates a new
+ one.
+
+ This can be considered a hack. When Maria loses HA_NO_TRANSACTIONS it will
+ be participant in the connection's transaction and so the implicit commits
+ (ha_commit()) (like in end_active_trans()) will do the implicit commit
+ without need to call this function which can then be removed.
+
+ @param thd THD object
+ @param new_trn if a new transaction should be created; a new
+ transaction is not needed when we know that the
+ tables will be unlocked very soon.
+*/
+
+int ha_maria::implicit_commit(THD *thd, bool new_trn)
+{
+#ifndef MARIA_CANNOT_ROLLBACK
+#error this method should be removed
+#endif
+ TRN *trn;
+ int error= 0;
+ TABLE *table;
+ DBUG_ENTER("ha_maria::implicit_commit");
+ if (!new_trn && thd->locked_tables)
+ {
+ /*
+ "we are under LOCK TABLES" <=> "we shouldn't commit".
+ As thd->locked_tables is true, we are either under LOCK TABLES, or in
+ prelocking; prelocking can be under LOCK TABLES, or not (and in this
+ latter case only we should commit).
+ Note that we come here only at the end of the top statement
+ (dispatch_command()), we are never committing inside a sub-statement./
+ */
+ enum prelocked_mode_type prelocked_mode= thd->prelocked_mode;
+ if ((prelocked_mode == NON_PRELOCKED) ||
+ (prelocked_mode == PRELOCKED_UNDER_LOCK_TABLES))
+ {
+ DBUG_PRINT("info", ("locked_tables, skipping"));
+ DBUG_RETURN(0);
+ }
+ }
+ if ((trn= THD_TRN) != NULL)
+ {
+ uint locked_tables= trnman_has_locked_tables(trn);
+ if (unlikely(ma_commit(trn)))
+ error= 1;
+ if (!new_trn)
+ {
+ THD_TRN= NULL;
+ goto end;
+ }
+ /*
+ We need to create a new transaction and put it in THD_TRN. Indeed,
+ tables may be under LOCK TABLES, and so they will start the next
+ statement assuming they have a trn (see ha_maria::start_stmt()).
+ */
+ trn= trnman_new_trn(& thd->transaction.wt);
+ /* This is just a commit, tables stay locked if they were: */
+ trnman_reset_locked_tables(trn, locked_tables);
+ THD_TRN= trn;
+ if (unlikely(trn == NULL))
+ error= HA_ERR_OUT_OF_MEM;
+
+ /*
+ Move all locked tables to the new transaction
+ We must do it here as otherwise file->thd and file->state may be
+ stale pointers. We can't do this in start_stmt() as we don't know
+ when we should call _ma_setup_live_state() and in some cases, like
+ in check table, we use the table without calling start_stmt().
+ */
+ for (table=thd->open_tables; table ; table=table->next)
+ {
+ if (table->db_stat && table->file->ht == maria_hton)
+ {
+ MARIA_HA *handler= ((ha_maria*) table->file)->file;
+ if (handler->s->base.born_transactional)
+ {
+ _ma_set_trn_for_table(handler, trn);
+ /* If handler uses versioning */
+ if (handler->s->lock_key_trees)
+ {
+ if (_ma_setup_live_state(handler))
+ error= HA_ERR_OUT_OF_MEM;
+ }
+ }
+ }
+ }
+ }
+end:
+ DBUG_RETURN(error);
+}
+
+
+THR_LOCK_DATA **ha_maria::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ /* Test if we can fix test below */
+ DBUG_ASSERT(lock_type != TL_UNLOCK &&
+ (lock_type == TL_IGNORE || file->lock.type == TL_UNLOCK));
+ if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
+ {
+ const enum enum_sql_command sql_command= thd->lex->sql_command;
+ /*
+ We have to disable concurrent inserts for INSERT ... SELECT or
+ INSERT/UPDATE/DELETE with sub queries if we are using statement based
+ logging. We take the safe route here and disable this for all commands
+ that only does reading that are not SELECT.
+ */
+ if (lock_type <= TL_READ_HIGH_PRIORITY &&
+ !thd->current_stmt_binlog_row_based &&
+ (sql_command != SQLCOM_SELECT &&
+ sql_command != SQLCOM_LOCK_TABLES) &&
+ (thd->options & OPTION_BIN_LOG) &&
+ mysql_bin_log.is_open())
+ lock_type= TL_READ_NO_INSERT;
+ else if (lock_type == TL_WRITE_CONCURRENT_INSERT)
+ {
+ const enum enum_duplicates duplicates= thd->lex->duplicates;
+ /*
+ Explanation for the 3 conditions below, in order:
+
+ - Bulk insert may use repair, which will cause problems if other
+ threads try to read/insert to the table: disable versioning.
+ Note that our read of file->state->records is incorrect, as such
+ variable may have changed when we come to start_bulk_insert() (worse
+ case: we see != 0 so allow versioning, start_bulk_insert() sees 0 and
+ uses repair). This is prevented because start_bulk_insert() will not
+ try repair if we enabled versioning.
+ - INSERT SELECT ON DUPLICATE KEY UPDATE comes here with
+ TL_WRITE_CONCURRENT_INSERT but shouldn't because it can do
+ update/delete of a row and versioning doesn't support that
+ - same for LOAD DATA CONCURRENT REPLACE.
+ */
+ if ((file->state->records == 0) ||
+ (sql_command == SQLCOM_INSERT_SELECT && duplicates == DUP_UPDATE) ||
+ (sql_command == SQLCOM_LOAD && duplicates == DUP_REPLACE))
+ lock_type= TL_WRITE;
+ }
+ file->lock.type= lock_type;
+ }
+ *to++= &file->lock;
+ return to;
+}
+
+
+void ha_maria::update_create_info(HA_CREATE_INFO *create_info)
+{
+ ha_maria::info(HA_STATUS_AUTO | HA_STATUS_CONST);
+ if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
+ {
+ create_info->auto_increment_value= stats.auto_increment_value;
+ }
+ create_info->data_file_name= data_file_name;
+ create_info->index_file_name= index_file_name;
+ /* We need to restore the row type as Maria can change it */
+ if (create_info->row_type != ROW_TYPE_DEFAULT &&
+ !(create_info->used_fields & HA_CREATE_USED_ROW_FORMAT))
+ create_info->row_type= get_row_type();
+ /*
+ Show always page checksums, as this can be forced with
+ maria_page_checksums variable
+ */
+ if (create_info->page_checksum == HA_CHOICE_UNDEF)
+ create_info->page_checksum=
+ (file->s->options & HA_OPTION_PAGE_CHECKSUM) ? HA_CHOICE_YES :
+ HA_CHOICE_NO;
+}
+
+
+enum row_type ha_maria::get_row_type() const
+{
+ switch (file->s->data_file_type) {
+ case STATIC_RECORD: return ROW_TYPE_FIXED;
+ case DYNAMIC_RECORD: return ROW_TYPE_DYNAMIC;
+ case BLOCK_RECORD: return ROW_TYPE_PAGE;
+ case COMPRESSED_RECORD: return ROW_TYPE_COMPRESSED;
+ default: return ROW_TYPE_NOT_USED;
+ }
+}
+
+
+static enum data_file_type maria_row_type(HA_CREATE_INFO *info)
+{
+ if (info->transactional == HA_CHOICE_YES)
+ return BLOCK_RECORD;
+ switch (info->row_type) {
+ case ROW_TYPE_FIXED: return STATIC_RECORD;
+ case ROW_TYPE_DYNAMIC: return DYNAMIC_RECORD;
+ default: return BLOCK_RECORD;
+ }
+}
+
+
+int ha_maria::create(const char *name, register TABLE *table_arg,
+ HA_CREATE_INFO *ha_create_info)
+{
+ int error;
+ uint create_flags= 0, record_count, i;
+ char buff[FN_REFLEN];
+ MARIA_KEYDEF *keydef;
+ MARIA_COLUMNDEF *recinfo;
+ MARIA_CREATE_INFO create_info;
+ TABLE_SHARE *share= table_arg->s;
+ uint options= share->db_options_in_use;
+ enum data_file_type row_type;
+ THD *thd= current_thd;
+ DBUG_ENTER("ha_maria::create");
+
+ for (i= 0; i < share->keys; i++)
+ {
+ if (table_arg->key_info[i].flags & HA_USES_PARSER)
+ {
+ create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
+ break;
+ }
+ }
+ /* Note: BLOCK_RECORD is used if table is transactional */
+ row_type= maria_row_type(ha_create_info);
+ if (ha_create_info->transactional == HA_CHOICE_YES &&
+ ha_create_info->row_type != ROW_TYPE_PAGE &&
+ ha_create_info->row_type != ROW_TYPE_NOT_USED &&
+ ha_create_info->row_type != ROW_TYPE_DEFAULT)
+ push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "Row format set to PAGE because of TRANSACTIONAL=1 option");
+
+ bzero((char*) &create_info, sizeof(create_info));
+ if ((error= table2maria(table_arg, row_type, &keydef, &recinfo,
+ &record_count, &create_info)))
+ DBUG_RETURN(error); /* purecov: inspected */
+ create_info.max_rows= share->max_rows;
+ create_info.reloc_rows= share->min_rows;
+ create_info.with_auto_increment= share->next_number_key_offset == 0;
+ create_info.auto_increment= (ha_create_info->auto_increment_value ?
+ ha_create_info->auto_increment_value -1 :
+ (ulonglong) 0);
+ create_info.data_file_length= ((ulonglong) share->max_rows *
+ share->avg_row_length);
+ create_info.data_file_name= ha_create_info->data_file_name;
+ create_info.index_file_name= ha_create_info->index_file_name;
+ create_info.language= share->table_charset->number;
+
+ /*
+ Table is transactional:
+ - If the user specify that table is transactional (in this case
+ row type is forced to BLOCK_RECORD)
+ - If they specify BLOCK_RECORD without specifying transactional behaviour
+
+ Shouldn't this test be pushed down to maria_create()? Because currently,
+ ma_test1 -T crashes: it creates a table with DYNAMIC_RECORD but has
+ born_transactional==1, which confuses some recovery-related code.
+ */
+ create_info.transactional= (row_type == BLOCK_RECORD &&
+ ha_create_info->transactional != HA_CHOICE_NO);
+
+ if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ create_flags|= HA_CREATE_TMP_TABLE;
+ if (ha_create_info->options & HA_CREATE_KEEP_FILES)
+ create_flags|= HA_CREATE_KEEP_FILES;
+ if (options & HA_OPTION_PACK_RECORD)
+ create_flags|= HA_PACK_RECORD;
+ if (options & HA_OPTION_CHECKSUM)
+ create_flags|= HA_CREATE_CHECKSUM;
+ if (options & HA_OPTION_DELAY_KEY_WRITE)
+ create_flags|= HA_CREATE_DELAY_KEY_WRITE;
+ if ((ha_create_info->page_checksum == HA_CHOICE_UNDEF &&
+ maria_page_checksums) ||
+ ha_create_info->page_checksum == HA_CHOICE_YES)
+ create_flags|= HA_CREATE_PAGE_CHECKSUM;
+
+ (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY,
+ (uchar*) thd->query, thd->query_length);
+
+ /* TODO: Check that the following fn_format is really needed */
+ error=
+ maria_create(fn_format(buff, name, "", "",
+ MY_UNPACK_FILENAME | MY_APPEND_EXT),
+ row_type, share->keys, keydef,
+ record_count, recinfo,
+ 0, (MARIA_UNIQUEDEF *) 0,
+ &create_info, create_flags);
+
+ my_free((uchar*) recinfo, MYF(0));
+ DBUG_RETURN(error);
+}
+
+
+int ha_maria::rename_table(const char *from, const char *to)
+{
+ THD *thd= current_thd;
+ (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY,
+ (uchar*) thd->query, thd->query_length);
+ return maria_rename(from, to);
+}
+
+
+void ha_maria::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
+{
+ ulonglong nr;
+ int error;
+ uchar key[HA_MAX_KEY_LENGTH];
+
+ if (!table->s->next_number_key_offset)
+ { // Autoincrement at key-start
+ ha_maria::info(HA_STATUS_AUTO);
+ *first_value= stats.auto_increment_value;
+ /* Maria has only table-level lock for now, so reserves to +inf */
+ *nb_reserved_values= ULONGLONG_MAX;
+ return;
+ }
+
+ /* it's safe to call the following if bulk_insert isn't on */
+ maria_flush_bulk_insert(file, table->s->next_number_index);
+
+ (void) extra(HA_EXTRA_KEYREAD);
+ key_copy(key, table->record[0],
+ table->key_info + table->s->next_number_index,
+ table->s->next_number_key_offset);
+ error= maria_rkey(file, table->record[1], (int) table->s->next_number_index,
+ key, make_prev_keypart_map(table->s->next_number_keypart),
+ HA_READ_PREFIX_LAST);
+ if (error)
+ nr= 1;
+ else
+ {
+ /* Get data from record[1] */
+ nr= ((ulonglong) table->next_number_field->
+ val_int_offset(table->s->rec_buff_length) + 1);
+ }
+ extra(HA_EXTRA_NO_KEYREAD);
+ *first_value= nr;
+ /*
+ MySQL needs to call us for next row: assume we are inserting ("a",null)
+ here, we return 3, and next this statement will want to insert ("b",null):
+ there is no reason why ("b",3+1) would be the good row to insert: maybe it
+ already exists, maybe 3+1 is too large...
+ */
+ *nb_reserved_values= 1;
+}
+
+
+/*
+ Find out how many rows there is in the given range
+
+ SYNOPSIS
+ records_in_range()
+ inx Index to use
+ min_key Start of range. Null pointer if from first key
+ max_key End of range. Null pointer if to last key
+
+ NOTES
+ min_key.flag can have one of the following values:
+ HA_READ_KEY_EXACT Include the key in the range
+ HA_READ_AFTER_KEY Don't include key in range
+
+ max_key.flag can have one of the following values:
+ HA_READ_BEFORE_KEY Don't include key in range
+ HA_READ_AFTER_KEY Include all 'end_key' values in the range
+
+ RETURN
+ HA_POS_ERROR Something is wrong with the index tree.
+ 0 There is no matching keys in the given range
+ number > 0 There is approximately 'number' matching rows in
+ the range.
+*/
+
+ha_rows ha_maria::records_in_range(uint inx, key_range *min_key,
+ key_range *max_key)
+{
+ return (ha_rows) maria_records_in_range(file, (int) inx, min_key, max_key);
+}
+
+
+int ha_maria::ft_read(uchar * buf)
+{
+ int error;
+
+ if (!ft_handler)
+ return -1;
+
+ thread_safe_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status); // why ?
+
+ error= ft_handler->please->read_next(ft_handler, (char*) buf);
+
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
+
+uint ha_maria::checksum() const
+{
+ return (uint) file->state->checksum;
+}
+
+
+bool ha_maria::check_if_incompatible_data(HA_CREATE_INFO *create_info,
+ uint table_changes)
+{
+ uint options= table->s->db_options_in_use;
+
+ if (create_info->auto_increment_value != stats.auto_increment_value ||
+ create_info->data_file_name != data_file_name ||
+ create_info->index_file_name != index_file_name ||
+ (maria_row_type(create_info) != data_file_type &&
+ create_info->row_type != ROW_TYPE_DEFAULT) ||
+ table_changes == IS_EQUAL_NO ||
+ table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
+ return COMPATIBLE_DATA_NO;
+
+ if ((options & (HA_OPTION_CHECKSUM |
+ HA_OPTION_DELAY_KEY_WRITE)) !=
+ (create_info->table_options & (HA_OPTION_CHECKSUM |
+ HA_OPTION_DELAY_KEY_WRITE)))
+ return COMPATIBLE_DATA_NO;
+ return COMPATIBLE_DATA_YES;
+}
+
+
+static int maria_hton_panic(handlerton *hton, ha_panic_function flag)
+{
+ /* If no background checkpoints, we need to do one now */
+ return ((checkpoint_interval == 0) ?
+ ma_checkpoint_execute(CHECKPOINT_FULL, FALSE) : 0) | maria_panic(flag);
+}
+
+
+static int maria_commit(handlerton *hton __attribute__ ((unused)),
+ THD *thd, bool all)
+{
+ TRN *trn= THD_TRN;
+ DBUG_ENTER("maria_commit");
+ trnman_reset_locked_tables(trn, 0);
+ trnman_set_flags(trn, trnman_get_flags(trn) & ~TRN_STATE_INFO_LOGGED);
+
+ /* statement or transaction ? */
+ if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all)
+ DBUG_RETURN(0); // end of statement
+ DBUG_PRINT("info", ("THD_TRN set to 0x0"));
+ THD_TRN= 0;
+ DBUG_RETURN(ma_commit(trn)); // end of transaction
+}
+
+
+static int maria_rollback(handlerton *hton __attribute__ ((unused)),
+ THD *thd, bool all)
+{
+ TRN *trn= THD_TRN;
+ DBUG_ENTER("maria_rollback");
+ trnman_reset_locked_tables(trn, 0);
+ /* statement or transaction ? */
+ if ((thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all)
+ {
+ trnman_rollback_statement(trn);
+ DBUG_RETURN(0); // end of statement
+ }
+ DBUG_PRINT("info", ("THD_TRN set to 0x0"));
+ THD_TRN= 0;
+ DBUG_RETURN(trnman_rollback_trn(trn) ?
+ HA_ERR_OUT_OF_MEM : 0); // end of transaction
+}
+
+
+
+/**
+ @brief flush log handler
+
+ @param hton maria handlerton (unused)
+
+ @retval FALSE OK
+ @retval TRUE Error
+*/
+
+bool maria_flush_logs(handlerton *hton)
+{
+ return test(translog_purge_at_flush());
+}
+
+
+#define SHOW_MSG_LEN (FN_REFLEN + 20)
+/**
+ @brief show status handler
+
+ @param hton maria handlerton
+ @param thd thread handler
+ @param print print function
+ @param stat type of status
+*/
+
+bool maria_show_status(handlerton *hton,
+ THD *thd,
+ stat_print_fn *print,
+ enum ha_stat_type stat)
+{
+ const LEX_STRING *engine_name= hton_name(hton);
+ switch (stat) {
+ case HA_ENGINE_LOGS:
+ {
+ TRANSLOG_ADDRESS horizon= translog_get_horizon();
+ uint32 last_file= LSN_FILE_NO(horizon);
+ uint32 first_needed= translog_get_first_needed_file();
+ uint32 first_file= translog_get_first_file(horizon);
+ uint32 i;
+ const char unknown[]= "unknown";
+ const char needed[]= "in use";
+ const char unneeded[]= "free";
+ char path[FN_REFLEN];
+
+ if (first_file == 0)
+ {
+ const char error[]= "error";
+ print(thd, engine_name->str, engine_name->length,
+ STRING_WITH_LEN(""), error, sizeof(error) - 1);
+ break;
+ }
+
+ for (i= first_file; i <= last_file; i++)
+ {
+ char *file;
+ const char *status;
+ uint length, status_len;
+ MY_STAT stat_buff, *stat;
+ const char error[]= "can't stat";
+ char object[SHOW_MSG_LEN];
+ file= translog_filename_by_fileno(i, path);
+ if (!(stat= my_stat(file, &stat_buff, MYF(0))))
+ {
+ status= error;
+ status_len= sizeof(error) - 1;
+ length= my_snprintf(object, SHOW_MSG_LEN, "Size unknown ; %s", file);
+ }
+ else
+ {
+ if (first_needed == 0)
+ {
+ status= unknown;
+ status_len= sizeof(unknown) - 1;
+ }
+ else if (i < first_needed)
+ {
+ status= unneeded;
+ status_len= sizeof(unneeded) - 1;
+ }
+ else
+ {
+ status= needed;
+ status_len= sizeof(needed) - 1;
+ }
+ length= my_snprintf(object, SHOW_MSG_LEN, "Size %12lu ; %s",
+ (ulong) stat->st_size, file);
+ }
+
+ print(thd, engine_name->str, engine_name->length,
+ object, length, status, status_len);
+ }
+ break;
+ }
+ case HA_ENGINE_STATUS:
+ case HA_ENGINE_MUTEX:
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/**
+ Callback to delete all logs in directory. This is lower-level than other
+ functions in ma_loghandler.c which delete logs, as it does not rely on
+ translog_init() having been called first.
+
+ @param directory directory where file is
+ @param filename base name of the file to delete
+*/
+
+static my_bool translog_callback_delete_all(const char *directory,
+ const char *filename)
+{
+ char complete_name[FN_REFLEN];
+ fn_format(complete_name, filename, directory, "", MYF(MY_UNPACK_FILENAME));
+ return my_delete(complete_name, MYF(MY_WME));
+}
+
+
+/**
+ Helper function for option maria-force-start-after-recovery-failures.
+ Deletes logs if too many failures. Otherwise, increments the counter of
+ failures in the control file.
+ Notice how this has to be called _before_ translog_init() (if log is
+ corrupted, translog_init() might crash the server, so we need to remove logs
+ before).
+
+ @param log_dir directory where logs to be deleted are
+*/
+
+static int mark_recovery_start(const char* log_dir)
+{
+ int res;
+ DBUG_ENTER("mark_recovery_start");
+ if (unlikely(maria_recover_options == HA_RECOVER_NONE))
+ ma_message_no_user(ME_JUST_WARNING, "Please consider using option"
+ " --maria-recover[=...] to automatically check and"
+ " repair tables when logs are removed by option"
+ " --maria-force-start-after-recovery-failures=#");
+ if (recovery_failures >= force_start_after_recovery_failures)
+ {
+ /*
+ Remove logs which cause the problem; keep control file which has
+ critical info like uuid, max_trid (removing control file may make
+ correct tables look corrupted!).
+ */
+ char msg[100];
+ res= translog_walk_filenames(log_dir, &translog_callback_delete_all);
+ my_snprintf(msg, sizeof(msg),
+ "%s logs after %u consecutive failures of"
+ " recovery from logs",
+ (res ? "failed to remove some" : "removed all"),
+ recovery_failures);
+ ma_message_no_user((res ? 0 : ME_JUST_WARNING), msg);
+ }
+ else
+ res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
+ max_trid_in_control_file,
+ recovery_failures + 1);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Helper function for option maria-force-start-after-recovery-failures.
+ Records in the control file that recovery was a success, so that it's not
+ counted for maria-force-start-after-recovery-failures.
+*/
+
+static int mark_recovery_success(void)
+{
+ /* success of recovery, reset recovery_failures: */
+ int res;
+ DBUG_ENTER("mark_recovery_success");
+ res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
+ max_trid_in_control_file, 0);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Return 1 if table has changed during the current transaction
+*/
+
+bool ha_maria::is_changed() const
+{
+ return file->state->changed;
+}
+
+
+static int ha_maria_init(void *p)
+{
+ int res;
+ const char *log_dir= maria_data_root;
+ maria_hton= (handlerton *)p;
+ maria_hton->state= SHOW_OPTION_YES;
+ maria_hton->db_type= DB_TYPE_UNKNOWN;
+ maria_hton->create= maria_create_handler;
+ maria_hton->panic= maria_hton_panic;
+ maria_hton->commit= maria_commit;
+ maria_hton->rollback= maria_rollback;
+ maria_hton->flush_logs= maria_flush_logs;
+ maria_hton->show_status= maria_show_status;
+ /* TODO: decide if we support Maria being used for log tables */
+ maria_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
+ bzero(maria_log_pagecache, sizeof(*maria_log_pagecache));
+ maria_tmpdir= &mysql_tmpdir_list; /* For REDO */
+ res= maria_init() || ma_control_file_open(TRUE, TRUE) ||
+ ((force_start_after_recovery_failures != 0) &&
+ mark_recovery_start(log_dir)) ||
+ !init_pagecache(maria_pagecache,
+ (size_t) pagecache_buffer_size, pagecache_division_limit,
+ pagecache_age_threshold, maria_block_size, 0) ||
+ !init_pagecache(maria_log_pagecache,
+ TRANSLOG_PAGECACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, 0) ||
+ translog_init(maria_data_root, log_file_size,
+ MYSQL_VERSION_ID, server_id, maria_log_pagecache,
+ TRANSLOG_DEFAULT_FLAGS, 0) ||
+ maria_recovery_from_log() ||
+ ((force_start_after_recovery_failures != 0) && mark_recovery_success()) ||
+ ma_checkpoint_init(checkpoint_interval);
+ maria_multi_threaded= maria_in_ha_maria= TRUE;
+
+#if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH)
+ /* We can only test for sub paths if my_symlink.c is using realpath */
+ maria_test_invalid_symlink= test_if_data_home_dir;
+#endif
+ return res ? HA_ERR_INITIALIZATION : 0;
+}
+
+
+#ifdef HAVE_QUERY_CACHE
+/**
+ @brief Register a named table with a call back function to the query cache.
+
+ @param thd The thread handle
+ @param table_key A pointer to the table name in the table cache
+ @param key_length The length of the table name
+ @param[out] engine_callback The pointer to the storage engine call back
+ function, currently 0
+ @param[out] engine_data Engine data will be set to 0.
+
+ @note Despite the name of this function, it is used to check each statement
+ before it is cached and not to register a table or callback function.
+
+ @see handler::register_query_cache_table
+
+ @return The error code. The engine_data and engine_callback will be set to 0.
+ @retval TRUE Success
+ @retval FALSE An error occurred
+*/
+
+my_bool ha_maria::register_query_cache_table(THD *thd, char *table_name,
+ uint table_name_len,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+{
+ ulonglong actual_data_file_length;
+ ulonglong current_data_file_length;
+ DBUG_ENTER("ha_maria::register_query_cache_table");
+
+ /*
+ No call back function is needed to determine if a cached statement
+ is valid or not.
+ */
+ *engine_callback= 0;
+
+ /*
+ No engine data is needed.
+ */
+ *engine_data= 0;
+
+ /*
+ If a concurrent INSERT has happened just before the currently processed
+ SELECT statement, the total size of the table is unknown.
+
+ To determine if the table size is known, the current thread's snap shot of
+ the table size with the actual table size are compared.
+
+ If the table size is unknown the SELECT statement can't be cached.
+ */
+
+ /*
+ POSIX visibility rules specify that "2. Whatever memory values a
+ thread can see when it unlocks a mutex <...> can also be seen by any
+ thread that later locks the same mutex". In this particular case,
+ concurrent insert thread had modified the data_file_length in
+ MYISAM_SHARE before it has unlocked (or even locked)
+ structure_guard_mutex. So, here we're guaranteed to see at least that
+ value after we've locked the same mutex. We can see a later value
+ (modified by some other thread) though, but it's ok, as we only want
+ to know if the variable was changed, the actual new value doesn't matter
+ */
+ actual_data_file_length= file->s->state.state.data_file_length;
+ current_data_file_length= file->state->data_file_length;
+
+ /* Return whether is ok to try to cache current statement. */
+ DBUG_RETURN(!(file->s->non_transactional_concurrent_insert &&
+ current_data_file_length != actual_data_file_length));
+}
+#endif
+
+static struct st_mysql_sys_var* system_variables[]= {
+ MYSQL_SYSVAR(block_size),
+ MYSQL_SYSVAR(checkpoint_interval),
+ MYSQL_SYSVAR(force_start_after_recovery_failures),
+ MYSQL_SYSVAR(page_checksum),
+ MYSQL_SYSVAR(log_dir_path),
+ MYSQL_SYSVAR(log_file_size),
+ MYSQL_SYSVAR(log_purge_type),
+ MYSQL_SYSVAR(max_sort_file_size),
+ MYSQL_SYSVAR(pagecache_age_threshold),
+ MYSQL_SYSVAR(pagecache_buffer_size),
+ MYSQL_SYSVAR(pagecache_division_limit),
+ MYSQL_SYSVAR(recover),
+ MYSQL_SYSVAR(repair_threads),
+ MYSQL_SYSVAR(sort_buffer_size),
+ MYSQL_SYSVAR(stats_method),
+ MYSQL_SYSVAR(sync_log_dir),
+ NULL
+};
+
+
+/**
+ @brief Updates the checkpoint interval and restarts the background thread.
+*/
+
+static void update_checkpoint_interval(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ ma_checkpoint_end();
+ ma_checkpoint_init(*(ulong *)var_ptr= (ulong)(*(long *)save));
+}
+
+/**
+ @brief Updates the transaction log file limit.
+*/
+
+static void update_log_file_size(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ uint32 size= (uint32)((ulong)(*(long *)save));
+ translog_set_file_size(size);
+ *(ulong *)var_ptr= size;
+}
+
+
+static SHOW_VAR status_variables[]= {
+ {"Maria_pagecache_blocks_not_flushed", (char*) &maria_pagecache_var.global_blocks_changed, SHOW_LONG_NOFLUSH},
+ {"Maria_pagecache_blocks_unused", (char*) &maria_pagecache_var.blocks_unused, SHOW_LONG_NOFLUSH},
+ {"Maria_pagecache_blocks_used", (char*) &maria_pagecache_var.blocks_used, SHOW_LONG_NOFLUSH},
+ {"Maria_pagecache_read_requests", (char*) &maria_pagecache_var.global_cache_r_requests, SHOW_LONGLONG},
+ {"Maria_pagecache_reads", (char*) &maria_pagecache_var.global_cache_read, SHOW_LONGLONG},
+ {"Maria_pagecache_write_requests", (char*) &maria_pagecache_var.global_cache_w_requests, SHOW_LONGLONG},
+ {"Maria_pagecache_writes", (char*) &maria_pagecache_var.global_cache_write, SHOW_LONGLONG},
+ {NullS, NullS, SHOW_LONG}
+};
+
+struct st_mysql_storage_engine maria_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+mysql_declare_plugin(maria)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &maria_storage_engine,
+ "MARIA",
+ "MySQL AB",
+ "Crash-safe tables with MyISAM heritage",
+ PLUGIN_LICENSE_GPL,
+ ha_maria_init, /* Plugin Init */
+ NULL, /* Plugin Deinit */
+ 0x0100, /* 1.0 */
+ status_variables, /* status variables */
+ system_variables, /* system variables */
+ NULL
+}
+mysql_declare_plugin_end;
diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h
new file mode 100644
index 00000000000..23fb74f1c27
--- /dev/null
+++ b/storage/maria/ha_maria.h
@@ -0,0 +1,167 @@
+/* Copyright (C) 2006,2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the maria handler */
+
+#include <maria.h>
+
+#define HA_RECOVER_NONE 0 /* No automatic recover */
+#define HA_RECOVER_DEFAULT 1 /* Automatic recover active */
+#define HA_RECOVER_BACKUP 2 /* Make a backupfile on recover */
+#define HA_RECOVER_FORCE 4 /* Recover even if we loose rows */
+#define HA_RECOVER_QUICK 8 /* Don't check rows in data file */
+
+extern ulong maria_sort_buffer_size;
+extern TYPELIB maria_recover_typelib;
+extern ulong maria_recover_options;
+
+class ha_maria :public handler
+{
+ MARIA_HA *file;
+ ulonglong int_table_flags;
+ MARIA_RECORD_POS remember_pos;
+ char *data_file_name, *index_file_name;
+ enum data_file_type data_file_type;
+ bool can_enable_indexes;
+ /**
+ If a transactional table is doing bulk insert with a single
+ UNDO_BULK_INSERT with/without repair.
+ */
+ uint8 bulk_insert_single_undo;
+ int repair(THD * thd, HA_CHECK *param, bool optimize);
+ int zerofill(THD * thd, HA_CHECK_OPT *check_opt);
+
+public:
+ ha_maria(handlerton *hton, TABLE_SHARE * table_arg);
+ ~ha_maria() {}
+ handler *clone(MEM_ROOT *mem_root);
+ const char *table_type() const
+ { return "MARIA"; }
+ const char *index_type(uint key_number);
+ const char **bas_ext() const;
+ ulonglong table_flags() const
+ { return int_table_flags; }
+ ulong index_flags(uint inx, uint part, bool all_parts) const
+ {
+ return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
+ 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
+ HA_READ_ORDER | HA_KEYREAD_ONLY);
+ }
+ uint max_supported_keys() const
+ { return MARIA_MAX_KEY; }
+ uint max_supported_key_length() const;
+ uint max_supported_key_part_length() const
+ { return max_supported_key_length(); }
+ enum row_type get_row_type() const;
+ uint checksum() const;
+ virtual double scan_time();
+
+ int open(const char *name, int mode, uint test_if_locked);
+ int close(void);
+ int write_row(uchar * buf);
+ int update_row(const uchar * old_data, uchar * new_data);
+ int delete_row(const uchar * buf);
+ int index_read_map(uchar * buf, const uchar * key, key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+ int index_read_idx_map(uchar * buf, uint idx, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+ int index_read_last_map(uchar * buf, const uchar * key,
+ key_part_map keypart_map);
+ int index_next(uchar * buf);
+ int index_prev(uchar * buf);
+ int index_first(uchar * buf);
+ int index_last(uchar * buf);
+ int index_next_same(uchar * buf, const uchar * key, uint keylen);
+ int ft_init()
+ {
+ if (!ft_handler)
+ return 1;
+ ft_handler->please->reinit_search(ft_handler);
+ return 0;
+ }
+ FT_INFO *ft_init_ext(uint flags, uint inx, String * key)
+ {
+ return maria_ft_init_search(flags, file, inx,
+ (uchar *) key->ptr(), key->length(),
+ key->charset(), table->record[0]);
+ }
+ int ft_read(uchar * buf);
+ int rnd_init(bool scan);
+ int rnd_end(void);
+ int rnd_next(uchar * buf);
+ int rnd_pos(uchar * buf, uchar * pos);
+ int remember_rnd_pos();
+ int restart_rnd_next(uchar * buf);
+ void position(const uchar * record);
+ int info(uint);
+ int info(uint, my_bool);
+ int extra(enum ha_extra_function operation);
+ int extra_opt(enum ha_extra_function operation, ulong cache_size);
+ int reset(void);
+ int external_lock(THD * thd, int lock_type);
+ int start_stmt(THD *thd, thr_lock_type lock_type);
+ int delete_all_rows(void);
+ int disable_indexes(uint mode);
+ int enable_indexes(uint mode);
+ int indexes_are_disabled(void);
+ void start_bulk_insert(ha_rows rows);
+ int end_bulk_insert(bool abort);
+ ha_rows records_in_range(uint inx, key_range * min_key, key_range * max_key);
+ void update_create_info(HA_CREATE_INFO * create_info);
+ int create(const char *name, TABLE * form, HA_CREATE_INFO * create_info);
+ THR_LOCK_DATA **store_lock(THD * thd, THR_LOCK_DATA ** to,
+ enum thr_lock_type lock_type);
+ virtual void get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
+ int rename_table(const char *from, const char *to);
+ int delete_table(const char *name);
+ int check(THD * thd, HA_CHECK_OPT * check_opt);
+ int analyze(THD * thd, HA_CHECK_OPT * check_opt);
+ int repair(THD * thd, HA_CHECK_OPT * check_opt);
+ bool check_and_repair(THD * thd);
+ bool is_crashed() const;
+ bool is_changed() const;
+ bool auto_repair() const { return 1; }
+ int optimize(THD * thd, HA_CHECK_OPT * check_opt);
+ int restore(THD * thd, HA_CHECK_OPT * check_opt);
+ int backup(THD * thd, HA_CHECK_OPT * check_opt);
+ int assign_to_keycache(THD * thd, HA_CHECK_OPT * check_opt);
+ int preload_keys(THD * thd, HA_CHECK_OPT * check_opt);
+ bool check_if_incompatible_data(HA_CREATE_INFO * info, uint table_changes);
+#ifdef HAVE_REPLICATION
+ int dump(THD * thd, int fd);
+ int net_read_dump(NET * net);
+#endif
+#ifdef HAVE_QUERY_CACHE
+ my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data);
+#endif
+ MARIA_HA *file_ptr(void)
+ {
+ return file;
+ }
+ static int implicit_commit(THD *thd, bool new_trn);
+};
diff --git a/storage/maria/lockman.c b/storage/maria/lockman.c
new file mode 100644
index 00000000000..e7f3c81b0fd
--- /dev/null
+++ b/storage/maria/lockman.c
@@ -0,0 +1,785 @@
+/* QQ: TODO - allocate everything from dynarrays !!! (benchmark) */
+/* QQ: TODO instant duration locks */
+/* QQ: #warning automatically place S instead of LS if possible */
+
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Generic Lock Manager
+
+ Lock manager handles locks on "resources", a resource must be uniquely
+ identified by a 64-bit number. Lock manager itself does not imply
+ anything about the nature of a resource - it can be a row, a table, a
+ database, or just anything.
+
+ Locks belong to "lock owners". A Lock owner is uniquely identified by a
+ 16-bit number. A function loid2lo must be provided by the application
+ that takes such a number as an argument and returns a LOCK_OWNER
+ structure.
+
+ Lock levels are completely defined by three tables. Lock compatibility
+ matrix specifies which locks can be held at the same time on a resource.
+ Lock combining matrix specifies what lock level has the same behaviour as
+ a pair of two locks of given levels. getlock_result matrix simplifies
+ intention locking and lock escalation for an application, basically it
+ defines which locks are intention locks and which locks are "loose"
+ locks. It is only used to provide better diagnostics for the
+ application, lock manager itself does not differentiate between normal,
+ intention, and loose locks.
+
+ Internally lock manager is based on a lock-free hash, see lf_hash.c for
+ details. All locks are stored in a hash, with a resource id as a search
+ key, so all locks for the same resource will be considered collisions and
+ will be put in a one (lock-free) linked list. The main lock-handling
+ logic is in the inner loop that searches for a lock in such a linked
+ list - lockfind().
+
+ This works as follows. Locks generally are added to the end of the list
+ (with one exception, see below). When scanning the list it is always
+ possible to determine what locks are granted (active) and what locks are
+ waiting - first lock is obviously active, the second is active if it's
+ compatible with the first, and so on, a lock is active if it's compatible
+ with all previous locks and all locks before it are also active.
+ To calculate the "compatible with all previous locks" all locks are
+ accumulated in prev_lock variable using lock_combining_matrix.
+
+ Lock upgrades: when a thread that has a lock on a given resource,
+ requests a new lock on the same resource and the old lock is not enough
+ to satisfy new lock requirements (which is defined by
+ lock_combining_matrix[old_lock][new_lock] != old_lock), a new lock is
+ placed in the list. Depending on other locks it is immediately active or
+ it will wait for other locks. Here's an exception to "locks are added
+ to the end" rule - upgraded locks are added after the last active lock
+ but before all waiting locks. Old lock (the one we upgraded from) is
+ not removed from the list, indeed it may be needed if the new lock was
+ in a savepoint that gets rolled back. So old lock is marked as "ignored"
+ (IGNORE_ME flag). New lock gets an UPGRADED flag.
+
+ Loose locks add an important exception to the above. Loose locks do not
+ always commute with other locks. In the list IX-LS both locks are active,
+ while in the LS-IX list only the first lock is active. This creates a
+ problem in lock upgrades. If the list was IX-LS and the owner of the
+ first lock wants to place LS lock (which can be immediately granted), the
+ IX lock is upgraded to LSIX and the list becomes IX-LS-LSIX, which,
+ according to the lock compatibility matrix means that the last lock is
+ waiting - of course it all happened because IX and LS were swapped and
+ they don't commute. To work around this there's ACTIVE flag which is set
+ in every lock that never waited (was placed active), and this flag
+ overrides "compatible with all previous locks" rule.
+
+ When a lock is placed to the end of the list it's either compatible with
+ all locks and all locks are active - new lock becomes active at once, or
+ it conflicts with some of the locks, in this case in the 'blocker'
+ variable a conflicting lock is returned and the calling thread waits on a
+ pthread condition in the LOCK_OWNER structure of the owner of the
+ conflicting lock. Or a new lock is compatible with all locks, but some
+ existing locks are not compatible with each other (example: request IS,
+ when the list is S-IX) - that is not all locks are active. In this case a
+ first waiting lock is returned in the 'blocker' variable, lockman_getlock()
+ notices that a "blocker" does not conflict with the requested lock, and
+ "dereferences" it, to find the lock that it's waiting on. The calling
+ thread than begins to wait on the same lock.
+
+ To better support table-row relations where one needs to lock the table
+ with an intention lock before locking the row, extended diagnostics is
+ provided. When an intention lock (presumably on a table) is granted,
+ lockman_getlock() returns one of GOT_THE_LOCK (no need to lock the row,
+ perhaps the thread already has a normal lock on this table),
+ GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE (need to lock the row, as usual),
+ GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE (only need to check
+ whether it's possible to lock the row, but no need to lock it - perhaps
+ the thread has a loose lock on this table). This is defined by
+ getlock_result[] table.
+*/
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_bit.h>
+#include <lf.h>
+#include "lockman.h"
+
+/*
+ Lock compatibility matrix.
+
+ It's asymmetric. Read it as "Somebody has the lock <value in the row
+ label>, can I set the lock <value in the column label> ?"
+
+ ') Though you can take LS lock while somebody has S lock, it makes no
+ sense - it's simpler to take S lock too.
+
+ 1 - compatible
+ 0 - incompatible
+ -1 - "impossible", so that we can assert the impossibility.
+*/
+static int lock_compatibility_matrix[10][10]=
+{ /* N S X IS IX SIX LS LX SLX LSIX */
+ { -1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* N */
+ { -1, 1, 0, 1, 0, 0, 1, 0, 0, 0 }, /* S */
+ { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* X */
+ { -1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, /* IS */
+ { -1, 0, 0, 1, 1, 0, 1, 1, 0, 1 }, /* IX */
+ { -1, 0, 0, 1, 0, 0, 1, 0, 0, 0 }, /* SIX */
+ { -1, 1, 0, 1, 0, 0, 1, 0, 0, 0 }, /* LS */
+ { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* LX */
+ { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* SLX */
+ { -1, 0, 0, 1, 0, 0, 1, 0, 0, 0 } /* LSIX */
+};
+
+/*
+ Lock combining matrix.
+
+ It's symmetric. Read it as "what lock level L is identical to the
+ set of two locks A and B"
+
+ One should never get N from it, we assert the impossibility
+*/
+static enum lockman_lock_type lock_combining_matrix[10][10]=
+{/* N S X IS IX SIX LS LX SLX LSIX */
+ { N, S, X, IS, IX, SIX, S, SLX, SLX, SIX}, /* N */
+ { S, S, X, S, SIX, SIX, S, SLX, SLX, SIX}, /* S */
+ { X, X, X, X, X, X, X, X, X, X}, /* X */
+ { IS, S, X, IS, IX, SIX, LS, LX, SLX, LSIX}, /* IS */
+ { IX, SIX, X, IX, IX, SIX, LSIX, LX, SLX, LSIX}, /* IX */
+ { SIX, SIX, X, SIX, SIX, SIX, SIX, SLX, SLX, SIX}, /* SIX */
+ { LS, S, X, LS, LSIX, SIX, LS, LX, SLX, LSIX}, /* LS */
+ { LX, SLX, X, LX, LX, SLX, LX, LX, SLX, LX}, /* LX */
+ { SLX, SLX, X, SLX, SLX, SLX, SLX, SLX, SLX, SLX}, /* SLX */
+ { LSIX, SIX, X, LSIX, LSIX, SIX, LSIX, LX, SLX, LSIX} /* LSIX */
+};
+
+#define REPEAT_ONCE_MORE 0
+#define OK_TO_PLACE_THE_LOCK 1
+#define OK_TO_PLACE_THE_REQUEST 2
+#define ALREADY_HAVE_THE_LOCK 4
+#define ALREADY_HAVE_THE_REQUEST 8
+#define PLACE_NEW_DISABLE_OLD 16
+#define REQUEST_NEW_DISABLE_OLD 32
+#define RESOURCE_WAS_UNLOCKED 64
+
+#define NEED_TO_WAIT (OK_TO_PLACE_THE_REQUEST | ALREADY_HAVE_THE_REQUEST |\
+ REQUEST_NEW_DISABLE_OLD)
+#define ALREADY_HAVE (ALREADY_HAVE_THE_LOCK | ALREADY_HAVE_THE_REQUEST)
+#define LOCK_UPGRADE (PLACE_NEW_DISABLE_OLD | REQUEST_NEW_DISABLE_OLD)
+
+
+/*
+ the return codes for lockman_getlock
+
+ It's asymmetric. Read it as "I have the lock <value in the row label>,
+ what value should be returned for <value in the column label> ?"
+
+ 0 means impossible combination (assert!)
+
+ Defines below help to preserve the table structure.
+ I/L/A values are self explanatory
+ x means the combination is possible (assert should not crash)
+ but it cannot happen in row locks, only in table locks (S,X),
+ or lock escalations (LS,LX)
+*/
+#define I GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE
+#define L GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE
+#define A GOT_THE_LOCK
+#define x GOT_THE_LOCK
+static enum lockman_getlock_result getlock_result[10][10]=
+{/* N S X IS IX SIX LS LX SLX LSIX */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* N */
+ { 0, x, 0, A, 0, 0, x, 0, 0, 0}, /* S */
+ { 0, x, x, A, A, 0, x, x, 0, 0}, /* X */
+ { 0, 0, 0, I, 0, 0, 0, 0, 0, 0}, /* IS */
+ { 0, 0, 0, I, I, 0, 0, 0, 0, 0}, /* IX */
+ { 0, x, 0, A, I, 0, x, 0, 0, 0}, /* SIX */
+ { 0, 0, 0, L, 0, 0, x, 0, 0, 0}, /* LS */
+ { 0, 0, 0, L, L, 0, x, x, 0, 0}, /* LX */
+ { 0, x, 0, A, L, 0, x, x, 0, 0}, /* SLX */
+ { 0, 0, 0, L, I, 0, x, 0, 0, 0} /* LSIX */
+};
+#undef I
+#undef L
+#undef A
+#undef x
+
+LF_REQUIRE_PINS(4)
+
+typedef struct lockman_lock {
+ uint64 resource;
+ struct lockman_lock *lonext;
+ intptr volatile link;
+ uint32 hashnr;
+ /* QQ: TODO - remove hashnr from LOCK */
+ uint16 loid;
+ uchar lock; /* sizeof(uchar) <= sizeof(enum) */
+ uchar flags;
+} LOCK;
+
+#define IGNORE_ME 1
+#define UPGRADED 2
+#define ACTIVE 4
+
+typedef struct {
+ intptr volatile *prev;
+ LOCK *curr, *next;
+ LOCK *blocker, *upgrade_from;
+} CURSOR;
+
+#define PTR(V) (LOCK *)((V) & (~(intptr)1))
+#define DELETED(V) ((V) & 1)
+
+/*
+ NOTE
+ cursor is positioned in either case
+ pins[0..3] are used, they are NOT removed on return
+*/
+static int lockfind(LOCK * volatile *head, LOCK *node,
+ CURSOR *cursor, LF_PINS *pins)
+{
+ uint32 hashnr, cur_hashnr;
+ uint64 resource, cur_resource;
+ intptr cur_link;
+ my_bool cur_active, compatible, upgrading, prev_active;
+ enum lockman_lock_type lock, prev_lock, cur_lock;
+ uint16 loid, cur_loid;
+ int cur_flags, flags;
+
+ hashnr= node->hashnr;
+ resource= node->resource;
+ lock= node->lock;
+ loid= node->loid;
+ flags= node->flags;
+
+retry:
+ cursor->prev= (intptr *)head;
+ prev_lock= N;
+ cur_active= TRUE;
+ compatible= TRUE;
+ upgrading= FALSE;
+ cursor->blocker= cursor->upgrade_from= 0;
+ _lf_unpin(pins, 3);
+ do {
+ cursor->curr= PTR(*cursor->prev);
+ _lf_pin(pins, 1, cursor->curr);
+ } while(*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
+ for (;;)
+ {
+ if (!cursor->curr)
+ break;
+ do {
+ cur_link= cursor->curr->link;
+ cursor->next= PTR(cur_link);
+ _lf_pin(pins, 0, cursor->next);
+ } while (cur_link != cursor->curr->link && LF_BACKOFF);
+ cur_hashnr= cursor->curr->hashnr;
+ cur_resource= cursor->curr->resource;
+ cur_lock= cursor->curr->lock;
+ cur_loid= cursor->curr->loid;
+ cur_flags= cursor->curr->flags;
+ if (*cursor->prev != (intptr)cursor->curr)
+ {
+ (void)LF_BACKOFF;
+ goto retry;
+ }
+ if (!DELETED(cur_link))
+ {
+ if (cur_hashnr > hashnr ||
+ (cur_hashnr == hashnr && cur_resource >= resource))
+ {
+ if (cur_hashnr > hashnr || cur_resource > resource)
+ break;
+ /* ok, we have a lock for this resource */
+ DBUG_ASSERT(lock_compatibility_matrix[prev_lock][cur_lock] >= 0);
+ DBUG_ASSERT(lock_compatibility_matrix[cur_lock][lock] >= 0);
+ if ((cur_flags & IGNORE_ME) && ! (flags & IGNORE_ME))
+ {
+ DBUG_ASSERT(cur_active);
+ if (cur_loid == loid)
+ cursor->upgrade_from= cursor->curr;
+ }
+ else
+ {
+ prev_active= cur_active;
+ if (cur_flags & ACTIVE)
+ DBUG_ASSERT(prev_active == TRUE);
+ else
+ cur_active&= lock_compatibility_matrix[prev_lock][cur_lock];
+ if (upgrading && !cur_active /*&& !(cur_flags & UPGRADED)*/)
+ break;
+ if (prev_active && !cur_active)
+ {
+ cursor->blocker= cursor->curr;
+ _lf_pin(pins, 3, cursor->curr);
+ }
+ if (cur_loid == loid)
+ {
+ /* we already have a lock on this resource */
+ DBUG_ASSERT(lock_combining_matrix[cur_lock][lock] != N);
+ DBUG_ASSERT(!upgrading || (flags & IGNORE_ME));
+ if (lock_combining_matrix[cur_lock][lock] == cur_lock)
+ {
+ /* new lock is compatible */
+ if (cur_active)
+ {
+ cursor->blocker= cursor->curr; /* loose-locks! */
+ _lf_unpin(pins, 3); /* loose-locks! */
+ return ALREADY_HAVE_THE_LOCK;
+ }
+ else
+ return ALREADY_HAVE_THE_REQUEST;
+ }
+ /* not compatible, upgrading */
+ upgrading= TRUE;
+ cursor->upgrade_from= cursor->curr;
+ }
+ else
+ {
+ if (!lock_compatibility_matrix[cur_lock][lock])
+ {
+ compatible= FALSE;
+ cursor->blocker= cursor->curr;
+ _lf_pin(pins, 3, cursor->curr);
+ }
+ }
+ prev_lock= lock_combining_matrix[prev_lock][cur_lock];
+ DBUG_ASSERT(prev_lock != N);
+ }
+ }
+ cursor->prev= &(cursor->curr->link);
+ _lf_pin(pins, 2, cursor->curr);
+ }
+ else
+ {
+ if (my_atomic_casptr((void **)cursor->prev,
+ (void **)&cursor->curr, cursor->next))
+ _lf_alloc_free(pins, cursor->curr);
+ else
+ {
+ (void)LF_BACKOFF;
+ goto retry;
+ }
+ }
+ cursor->curr= cursor->next;
+ _lf_pin(pins, 1, cursor->curr);
+ }
+ /*
+ either the end of lock list - no more locks for this resource,
+ or upgrading and the end of active lock list
+ */
+ if (upgrading)
+ {
+ if (compatible /*&& prev_active*/)
+ return PLACE_NEW_DISABLE_OLD;
+ else
+ return REQUEST_NEW_DISABLE_OLD;
+ }
+ if (cur_active && compatible)
+ {
+ /*
+ either no locks for this resource or all are compatible.
+ ok to place the lock in any case.
+ */
+ return prev_lock == N ? RESOURCE_WAS_UNLOCKED
+ : OK_TO_PLACE_THE_LOCK;
+ }
+ /* we have a lock conflict. ok to place a lock request. And wait */
+ return OK_TO_PLACE_THE_REQUEST;
+}
+
+/*
+ NOTE
+ it uses pins[0..3], on return pins 0..2 are removed, pin 3 (blocker) stays
+*/
+static int lockinsert(LOCK * volatile *head, LOCK *node, LF_PINS *pins,
+ LOCK **blocker)
+{
+ CURSOR cursor;
+ int res;
+
+ do
+ {
+ res= lockfind(head, node, &cursor, pins);
+ DBUG_ASSERT(res != ALREADY_HAVE_THE_REQUEST);
+ if (!(res & ALREADY_HAVE))
+ {
+ if (res & LOCK_UPGRADE)
+ {
+ node->flags|= UPGRADED;
+ node->lock= lock_combining_matrix[cursor.upgrade_from->lock][node->lock];
+ }
+ if (!(res & NEED_TO_WAIT))
+ node->flags|= ACTIVE;
+ node->link= (intptr)cursor.curr;
+ DBUG_ASSERT(node->link != (intptr)node);
+ DBUG_ASSERT(cursor.prev != &node->link);
+ if (!my_atomic_casptr((void **)cursor.prev, (void **)&cursor.curr, node))
+ {
+ res= REPEAT_ONCE_MORE;
+ node->flags&= ~ACTIVE;
+ }
+ if (res & LOCK_UPGRADE)
+ cursor.upgrade_from->flags|= IGNORE_ME;
+ /*
+ QQ: is this OK ? if a reader has already read upgrade_from,
+ it may find it conflicting with node :(
+ - see the last test from test_lockman_simple()
+ */
+ }
+
+ } while (res == REPEAT_ONCE_MORE);
+ _lf_unpin(pins, 0);
+ _lf_unpin(pins, 1);
+ _lf_unpin(pins, 2);
+ /*
+ note that blocker is not necessarily pinned here (when it's == curr).
+ this is ok as in such a case it's either a dummy node for
+ initialize_bucket() and dummy nodes don't need pinning,
+ or it's a lock of the same transaction for lockman_getlock,
+ and it cannot be removed by another thread
+ */
+ *blocker= cursor.blocker;
+ return res;
+}
+
+/*
+ NOTE
+ it uses pins[0..3], on return pins 0..2 are removed, pin 3 (blocker) stays
+*/
+static int lockpeek(LOCK * volatile *head, LOCK *node, LF_PINS *pins,
+ LOCK **blocker)
+{
+ CURSOR cursor;
+ int res;
+
+ res= lockfind(head, node, &cursor, pins);
+
+ _lf_unpin(pins, 0);
+ _lf_unpin(pins, 1);
+ _lf_unpin(pins, 2);
+ if (blocker)
+ *blocker= cursor.blocker;
+ return res;
+}
+
+/*
+ NOTE
+ it uses pins[0..3], on return all pins are removed.
+
+ One _must_ have the lock (or request) to call this
+*/
+static int lockdelete(LOCK * volatile *head, LOCK *node, LF_PINS *pins)
+{
+ CURSOR cursor;
+ int res;
+
+ do
+ {
+ res= lockfind(head, node, &cursor, pins);
+ DBUG_ASSERT(res & ALREADY_HAVE);
+
+ if (cursor.upgrade_from)
+ cursor.upgrade_from->flags&= ~IGNORE_ME;
+
+ /*
+ XXX this does not work with savepoints, as old lock is left ignored.
+ It cannot be unignored, as would basically mean moving the lock back
+ in the lock chain (from upgraded). And the latter is not allowed -
+ because it breaks list scanning. So old ignored lock must be deleted,
+ new - same - lock must be installed right after the lock we're deleting,
+ then we can delete. Good news is - this is only required when rolling
+ back a savepoint.
+ */
+ if (my_atomic_casptr((void **)&(cursor.curr->link),
+ (void **)&cursor.next, 1+(char *)cursor.next))
+ {
+ if (my_atomic_casptr((void **)cursor.prev,
+ (void **)&cursor.curr, cursor.next))
+ _lf_alloc_free(pins, cursor.curr);
+ else
+ lockfind(head, node, &cursor, pins);
+ }
+ else
+ {
+ res= REPEAT_ONCE_MORE;
+ if (cursor.upgrade_from)
+ cursor.upgrade_from->flags|= IGNORE_ME;
+ }
+ } while (res == REPEAT_ONCE_MORE);
+ _lf_unpin(pins, 0);
+ _lf_unpin(pins, 1);
+ _lf_unpin(pins, 2);
+ _lf_unpin(pins, 3);
+ return res;
+}
+
+void lockman_init(LOCKMAN *lm, loid_to_lo_func *func, uint timeout)
+{
+ lf_alloc_init(&lm->alloc, sizeof(LOCK), offsetof(LOCK, lonext));
+ lf_dynarray_init(&lm->array, sizeof(LOCK **));
+ lm->size= 1;
+ lm->count= 0;
+ lm->loid_to_lo= func;
+ lm->lock_timeout= timeout;
+}
+
+void lockman_destroy(LOCKMAN *lm)
+{
+ LOCK *el= *(LOCK **)_lf_dynarray_lvalue(&lm->array, 0);
+ while (el)
+ {
+ intptr next= el->link;
+ if (el->hashnr & 1)
+ lf_alloc_direct_free(&lm->alloc, el);
+ else
+ my_free((void *)el, MYF(0));
+ el= (LOCK *)next;
+ }
+ lf_alloc_destroy(&lm->alloc);
+ lf_dynarray_destroy(&lm->array);
+}
+
+/* TODO: optimize it */
+#define MAX_LOAD 1
+
+static void initialize_bucket(LOCKMAN *lm, LOCK * volatile *node,
+ uint bucket, LF_PINS *pins)
+{
+ int res;
+ uint parent= my_clear_highest_bit(bucket);
+ LOCK *dummy= (LOCK *)my_malloc(sizeof(LOCK), MYF(MY_WME));
+ LOCK **tmp= 0, *cur;
+ LOCK * volatile *el= _lf_dynarray_lvalue(&lm->array, parent);
+
+ if (*el == NULL && bucket)
+ initialize_bucket(lm, el, parent, pins);
+ dummy->hashnr= my_reverse_bits(bucket);
+ dummy->loid= 0;
+ dummy->lock= X; /* doesn't matter, in fact */
+ dummy->resource= 0;
+ dummy->flags= 0;
+ res= lockinsert(el, dummy, pins, &cur);
+ DBUG_ASSERT(res & (ALREADY_HAVE_THE_LOCK | RESOURCE_WAS_UNLOCKED));
+ if (res & ALREADY_HAVE_THE_LOCK)
+ {
+ my_free((void *)dummy, MYF(0));
+ dummy= cur;
+ }
+ my_atomic_casptr((void **)node, (void **)&tmp, dummy);
+}
+
+static inline uint calc_hash(uint64 resource)
+{
+ const uchar *pos= (uchar *)&resource;
+ ulong nr1= 1, nr2= 4, i;
+ for (i= 0; i < sizeof(resource) ; i++, pos++)
+ {
+ nr1^= (ulong) ((((uint) nr1 & 63)+nr2) * ((uint)*pos)) + (nr1 << 8);
+ nr2+= 3;
+ }
+ return nr1 & INT_MAX32;
+}
+
+/*
+ RETURN
+ see enum lockman_getlock_result
+ NOTE
+ uses pins[0..3], they're removed on return
+*/
+enum lockman_getlock_result lockman_getlock(LOCKMAN *lm, LOCK_OWNER *lo,
+ uint64 resource,
+ enum lockman_lock_type lock)
+{
+ int res;
+ uint csize, bucket, hashnr;
+ LOCK *node, * volatile *el, *blocker;
+ LF_PINS *pins= lo->pins;
+ enum lockman_lock_type old_lock;
+
+ DBUG_ASSERT(lo->loid);
+ lf_rwlock_by_pins(pins);
+ node= (LOCK *)_lf_alloc_new(pins);
+ node->flags= 0;
+ node->lock= lock;
+ node->loid= lo->loid;
+ node->resource= resource;
+ hashnr= calc_hash(resource);
+ bucket= hashnr % lm->size;
+ el= _lf_dynarray_lvalue(&lm->array, bucket);
+ if (*el == NULL)
+ initialize_bucket(lm, el, bucket, pins);
+ node->hashnr= my_reverse_bits(hashnr) | 1;
+ res= lockinsert(el, node, pins, &blocker);
+ if (res & ALREADY_HAVE)
+ {
+ int r;
+ old_lock= blocker->lock;
+ _lf_alloc_free(pins, node);
+ lf_rwunlock_by_pins(pins);
+ r= getlock_result[old_lock][lock];
+ DBUG_ASSERT(r);
+ return r;
+ }
+ /* a new value was added to the hash */
+ csize= lm->size;
+ if ((my_atomic_add32(&lm->count, 1)+1.0) / csize > MAX_LOAD)
+ my_atomic_cas32(&lm->size, (int*) &csize, csize*2);
+ node->lonext= lo->all_locks;
+ lo->all_locks= node;
+ for ( ; res & NEED_TO_WAIT; res= lockpeek(el, node, pins, &blocker))
+ {
+ LOCK_OWNER *wait_for_lo;
+ ulonglong deadline;
+ struct timespec timeout;
+
+ _lf_assert_pin(pins, 3); /* blocker must be pinned here */
+ wait_for_lo= lm->loid_to_lo(blocker->loid);
+
+ /*
+ now, this is tricky. blocker is not necessarily a LOCK
+ we're waiting for. If it's compatible with what we want,
+ then we're waiting for a lock that blocker is waiting for
+ (see two places where blocker is set in lockfind)
+ In the latter case, let's "dereference" it
+ */
+ if (lock_compatibility_matrix[blocker->lock][lock])
+ {
+ blocker= wait_for_lo->all_locks;
+ _lf_pin(pins, 3, blocker);
+ if (blocker != wait_for_lo->all_locks)
+ continue;
+ wait_for_lo= wait_for_lo->waiting_for;
+ }
+
+ /*
+ note that the blocker transaction may have ended by now,
+ its LOCK_OWNER and short id were reused, so 'wait_for_lo' may point
+ to an unrelated - albeit valid - LOCK_OWNER
+ */
+ if (!wait_for_lo)
+ continue;
+
+ lo->waiting_for= wait_for_lo;
+ lf_rwunlock_by_pins(pins);
+
+ /*
+ We lock a mutex - it may belong to a wrong LOCK_OWNER, but it must
+ belong to _some_ LOCK_OWNER. It means, we can never free() a LOCK_OWNER,
+ if there're other active LOCK_OWNERs.
+ */
+ /* QQ: race condition here */
+ pthread_mutex_lock(wait_for_lo->mutex);
+ if (DELETED(blocker->link))
+ {
+ /*
+ blocker transaction was ended, or a savepoint that owned
+ the lock was rolled back. Either way - the lock was removed
+ */
+ pthread_mutex_unlock(wait_for_lo->mutex);
+ lf_rwlock_by_pins(pins);
+ continue;
+ }
+
+ /* yuck. waiting */
+ deadline= my_getsystime() + lm->lock_timeout * 10000;
+ set_timespec_nsec(timeout,lm->lock_timeout * 1000000);
+ do
+ {
+ pthread_cond_timedwait(wait_for_lo->cond, wait_for_lo->mutex, &timeout);
+ } while (!DELETED(blocker->link) && my_getsystime() < deadline);
+ pthread_mutex_unlock(wait_for_lo->mutex);
+ lf_rwlock_by_pins(pins);
+ if (!DELETED(blocker->link))
+ {
+ /*
+ timeout.
+ note that we _don't_ release the lock request here.
+ Instead we're relying on the caller to abort the transaction,
+ and release all locks at once - see lockman_release_locks()
+ */
+ _lf_unpin(pins, 3);
+ lf_rwunlock_by_pins(pins);
+ return DIDNT_GET_THE_LOCK;
+ }
+ }
+ lo->waiting_for= 0;
+ _lf_assert_unpin(pins, 3); /* unpin should not be needed */
+ lf_rwunlock_by_pins(pins);
+ return getlock_result[lock][lock];
+}
+
+/*
+ RETURN
+ 0 - deleted
+ 1 - didn't (not found)
+ NOTE
+ see lockdelete() for pin usage notes
+*/
+int lockman_release_locks(LOCKMAN *lm, LOCK_OWNER *lo)
+{
+ LOCK * volatile *el, *node, *next;
+ uint bucket;
+ LF_PINS *pins= lo->pins;
+
+ pthread_mutex_lock(lo->mutex);
+ lf_rwlock_by_pins(pins);
+ for (node= lo->all_locks; node; node= next)
+ {
+ next= node->lonext;
+ bucket= calc_hash(node->resource) % lm->size;
+ el= _lf_dynarray_lvalue(&lm->array, bucket);
+ if (*el == NULL)
+ initialize_bucket(lm, el, bucket, pins);
+ lockdelete(el, node, pins);
+ my_atomic_add32(&lm->count, -1);
+ }
+ lf_rwunlock_by_pins(pins);
+ lo->all_locks= 0;
+ /* now signal all waiters */
+ pthread_cond_broadcast(lo->cond);
+ pthread_mutex_unlock(lo->mutex);
+ return 0;
+}
+
+#ifdef MY_LF_EXTRA_DEBUG
+static const char *lock2str[]=
+{ "N", "S", "X", "IS", "IX", "SIX", "LS", "LX", "SLX", "LSIX" };
+/*
+ NOTE
+ the function below is NOT thread-safe !!!
+*/
+void print_lockhash(LOCKMAN *lm)
+{
+ LOCK *el= *(LOCK **)_lf_dynarray_lvalue(&lm->array, 0);
+ printf("hash: size %u count %u\n", lm->size, lm->count);
+ while (el)
+ {
+ intptr next= el->link;
+ if (el->hashnr & 1)
+ {
+ printf("0x%08lx { resource %lu, loid %u, lock %s",
+ (long) el->hashnr, (ulong) el->resource, el->loid,
+ lock2str[el->lock]);
+ if (el->flags & IGNORE_ME) printf(" IGNORE_ME");
+ if (el->flags & UPGRADED) printf(" UPGRADED");
+ if (el->flags & ACTIVE) printf(" ACTIVE");
+ if (DELETED(next)) printf(" ***DELETED***");
+ printf("}\n");
+ }
+ else
+ {
+ /*printf("0x%08x { dummy }\n", el->hashnr);*/
+ DBUG_ASSERT(el->resource == 0 && el->loid == 0 && el->lock == X);
+ }
+ el= PTR(next);
+ }
+}
+#endif
diff --git a/storage/maria/lockman.h b/storage/maria/lockman.h
new file mode 100644
index 00000000000..82ab483896f
--- /dev/null
+++ b/storage/maria/lockman.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _lockman_h
+#define _lockman_h
+
+/*
+ Lock levels:
+ ^^^^^^^^^^^
+
+ N - "no lock", not a lock, used sometimes internally to simplify the code
+ S - Shared
+ X - eXclusive
+ IS - Intention Shared
+ IX - Intention eXclusive
+ SIX - Shared + Intention eXclusive
+ LS - Loose Shared
+ LX - Loose eXclusive
+ SLX - Shared + Loose eXclusive
+ LSIX - Loose Shared + Intention eXclusive
+*/
+enum lockman_lock_type { N, S, X, IS, IX, SIX, LS, LX, SLX, LSIX, LOCK_TYPE_LAST };
+
+struct lockman_lock;
+
+typedef struct st_lock_owner LOCK_OWNER;
+struct st_lock_owner {
+ LF_PINS *pins; /* must be allocated from lockman's pinbox */
+ struct lockman_lock *all_locks; /* a LIFO */
+ LOCK_OWNER *waiting_for;
+ pthread_cond_t *cond; /* transactions waiting for this, wait on 'cond' */
+ pthread_mutex_t *mutex; /* mutex is required to use 'cond' */
+ uint16 loid;
+};
+
+typedef LOCK_OWNER *loid_to_lo_func(uint16);
+typedef struct {
+ LF_DYNARRAY array; /* hash itself */
+ LF_ALLOCATOR alloc; /* allocator for elements */
+ int32 volatile size; /* size of array */
+ int32 volatile count; /* number of elements in the hash */
+ uint lock_timeout;
+ loid_to_lo_func *loid_to_lo;
+} LOCKMAN;
+#define DIDNT_GET_THE_LOCK 0
+enum lockman_getlock_result {
+ NO_MEMORY_FOR_LOCK=1, DEADLOCK, LOCK_TIMEOUT,
+ GOT_THE_LOCK,
+ GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE,
+ GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE
+};
+
+void lockman_init(LOCKMAN *, loid_to_lo_func *, uint);
+void lockman_destroy(LOCKMAN *);
+enum lockman_getlock_result lockman_getlock(LOCKMAN *lm, LOCK_OWNER *lo,
+ uint64 resource,
+ enum lockman_lock_type lock);
+int lockman_release_locks(LOCKMAN *, LOCK_OWNER *);
+
+#ifdef EXTRA_DEBUG
+void print_lockhash(LOCKMAN *lm);
+#endif
+
+#endif
diff --git a/storage/maria/ma_bitmap.c b/storage/maria/ma_bitmap.c
new file mode 100644
index 00000000000..bf2c9291981
--- /dev/null
+++ b/storage/maria/ma_bitmap.c
@@ -0,0 +1,2808 @@
+/* Copyright (C) 2007 Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Bitmap handling (for records in block)
+
+ The data file starts with a bitmap page, followed by as many data
+ pages as the bitmap can cover. After this there is a new bitmap page
+ and more data pages etc.
+
+ The bitmap code assumes there is always an active bitmap page and thus
+ that there is at least one bitmap page in the file
+
+ Structure of bitmap page:
+
+ Fixed size records (to be implemented later):
+
+ 2 bits are used to indicate:
+
+ 0 Empty
+ 1 0-75 % full (at least room for 2 records)
+ 2 75-100 % full (at least room for one record)
+ 3 100 % full (no more room for records)
+
+ Assuming 8K pages, this will allow us to map:
+ 8192 (bytes per page) * 4 (pages mapped per byte) * 8192 (page size)= 256M
+
+ (For Maria this will be 7*4 * 8192 = 224K smaller because of LSN)
+
+ Note that for fixed size rows, we can't add more columns without doing
+ a full reorganization of the table. The user can always force a dynamic
+ size row format by specifying ROW_FORMAT=dynamic.
+
+
+ Dynamic size records:
+
+ 3 bits are used to indicate Bytes free in 8K page
+
+ 0 Empty page 8176 (head or tail)
+ 1 0-30 % full (at least room for 3 records) 5724
+ 2 30-60 % full (at least room for 2 records) 3271
+ 3 60-90 % full (at least room for one record) 818
+ 4 100 % full (no more room for records) 0
+ 5 Tail page, 0-40 % full 4906
+ 6 Tail page, 40-80 % full 1636
+ 7 Full tail page or full blob page 0
+
+ Assuming 8K pages, this will allow us to map:
+ 8192 (bytes per page) * 8 bits/byte / 3 bits/page * 8192 (page size)= 170.7M
+
+ Note that values 1-3 may be adjust for each individual table based on
+ 'min record length'. Tail pages are for overflow data which can be of
+ any size and thus doesn't have to be adjusted for different tables.
+ If we add more columns to the table, some of the originally calculated
+ 'cut off' points may not be optimal, but they shouldn't be 'drasticly
+ wrong'.
+
+ When allocating data from the bitmap, we are trying to do it in a
+ 'best fit' manner. Blobs and varchar blocks are given out in large
+ continuous extents to allow fast access to these. Before allowing a
+ row to 'flow over' to other blocks, we will compact the page and use
+ all space on it. If there is many rows in the page, we will ensure
+ there is *LEFT_TO_GROW_ON_SPLIT* bytes left on the page to allow other
+ rows to grow.
+
+ The bitmap format allows us to extend the row file in big chunks, if needed.
+
+ When calculating the size for a packed row, we will calculate the following
+ things separately:
+ - Row header + null_bits + empty_bits fixed size segments etc.
+ - Size of all char/varchar fields
+ - Size of each blob field
+
+ The bitmap handler will get all the above information and return
+ either one page or a set of pages to put the different parts.
+
+ Bitmaps are read on demand in response to insert/delete/update operations.
+ The following bitmap pointers will be cached and stored on disk on close:
+ - Current insert_bitmap; When inserting new data we will first try to
+ fill this one.
+ - First bitmap which is not completely full. This is updated when we
+ free data with an update or delete.
+
+ While flushing out bitmaps, we will cache the status of the bitmap in memory
+ to avoid having to read a bitmap for insert of new data that will not
+ be of any use
+ - Total empty space
+ - Largest number of continuous pages
+
+ Bitmap ONLY goes to disk in the following scenarios
+ - The file is closed (and we flush all changes to disk)
+ - On checkpoint
+ (Ie: When we do a checkpoint, we have to ensure that all bitmaps are
+ put on disk even if they are not in the page cache).
+ - When explicitely requested (for example on backup or after recvoery,
+ to simplify things)
+
+ The flow of writing a row is that:
+ - Lock the bitmap
+ - Decide which data pages we will write to
+ - Mark them full in the bitmap page so that other threads do not try to
+ use the same data pages as us
+ - We unlock the bitmap
+ - Write the data pages
+ - Lock the bitmap
+ - Correct the bitmap page with the true final occupation of the data
+ pages (that is, we marked pages full but when we are done we realize
+ we didn't fill them)
+ - Unlock the bitmap.
+*/
+
+#include "maria_def.h"
+#include "ma_blockrec.h"
+
+#define FULL_HEAD_PAGE 4
+#define FULL_TAIL_PAGE 7
+
+/*#define WRONG_BITMAP_FLUSH 1*/ /*define only for provoking bugs*/
+#undef WRONG_BITMAP_FLUSH
+
+static my_bool _ma_read_bitmap_page(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page);
+static my_bool _ma_bitmap_create_missing(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page);
+
+/* Write bitmap page to key cache */
+
+static inline my_bool write_changed_bitmap(MARIA_SHARE *share,
+ MARIA_FILE_BITMAP *bitmap)
+{
+ DBUG_ENTER("write_changed_bitmap");
+ DBUG_ASSERT(share->pagecache->block_size == bitmap->block_size);
+ DBUG_ASSERT(bitmap->file.write_callback != 0);
+ DBUG_PRINT("info", ("bitmap->non_flushable: %u", bitmap->non_flushable));
+
+ if ((bitmap->non_flushable == 0)
+#ifdef WRONG_BITMAP_FLUSH
+ || 1
+#endif
+ )
+ {
+ my_bool res= pagecache_write(share->pagecache,
+ &bitmap->file, bitmap->page, 0,
+ (uchar*) bitmap->map, PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY, 0, LSN_IMPOSSIBLE);
+ DBUG_RETURN(res);
+ }
+ else
+ {
+ MARIA_PINNED_PAGE page_link;
+ int res= pagecache_write(share->pagecache,
+ &bitmap->file, bitmap->page, 0,
+ (uchar*) bitmap->map, PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, PAGECACHE_PIN,
+ PAGECACHE_WRITE_DELAY, &page_link.link,
+ LSN_IMPOSSIBLE);
+ page_link.unlock= PAGECACHE_LOCK_LEFT_UNLOCKED;
+ page_link.changed= 1;
+ push_dynamic(&bitmap->pinned_pages, (void*) &page_link);
+ DBUG_RETURN(res);
+ }
+}
+
+/*
+ Initialize bitmap variables in share
+
+ SYNOPSIS
+ _ma_bitmap_init()
+ share Share handler
+ file data file handler
+
+ NOTES
+ This is called the first time a file is opened.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+my_bool _ma_bitmap_init(MARIA_SHARE *share, File file)
+{
+ uint aligned_bit_blocks;
+ uint max_page_size;
+ MARIA_FILE_BITMAP *bitmap= &share->bitmap;
+ uint size= share->block_size;
+#ifndef DBUG_OFF
+ /* We want to have a copy of the bitmap to be able to print differences */
+ size*= 2;
+#endif
+
+ if (((bitmap->map= (uchar*) my_malloc(size, MYF(MY_WME))) == NULL) ||
+ my_init_dynamic_array(&bitmap->pinned_pages,
+ sizeof(MARIA_PINNED_PAGE), 1, 1))
+ return 1;
+
+ bitmap->block_size= share->block_size;
+ bitmap->file.file= file;
+ _ma_bitmap_set_pagecache_callbacks(&bitmap->file, share);
+
+ /* Size needs to be aligned on 6 */
+ aligned_bit_blocks= (share->block_size - PAGE_SUFFIX_SIZE) / 6;
+ bitmap->total_size= aligned_bit_blocks * 6;
+ /*
+ In each 6 bytes, we have 6*8/3 = 16 pages covered
+ The +1 is to add the bitmap page, as this doesn't have to be covered
+ */
+ bitmap->pages_covered= aligned_bit_blocks * 16 + 1;
+ bitmap->flush_all_requested= bitmap->non_flushable= 0;
+
+ /* Update size for bits */
+ /* TODO; Make this dependent of the row size */
+ max_page_size= share->block_size - PAGE_OVERHEAD_SIZE + DIR_ENTRY_SIZE;
+ bitmap->sizes[0]= max_page_size; /* Empty page */
+ bitmap->sizes[1]= max_page_size - max_page_size * 30 / 100;
+ bitmap->sizes[2]= max_page_size - max_page_size * 60 / 100;
+ bitmap->sizes[3]= max_page_size - max_page_size * 90 / 100;
+ bitmap->sizes[4]= 0; /* Full page */
+ bitmap->sizes[5]= max_page_size - max_page_size * 40 / 100;
+ bitmap->sizes[6]= max_page_size - max_page_size * 80 / 100;
+ bitmap->sizes[7]= 0;
+
+ pthread_mutex_init(&share->bitmap.bitmap_lock, MY_MUTEX_INIT_SLOW);
+ pthread_cond_init(&share->bitmap.bitmap_cond, 0);
+
+ _ma_bitmap_reset_cache(share);
+
+ if (share->state.first_bitmap_with_space == ~(pgcache_page_no_t) 0)
+ {
+ /* Start scanning for free space from start of file */
+ share->state.first_bitmap_with_space = 0;
+ }
+ return 0;
+}
+
+
+/*
+ Free data allocated by _ma_bitmap_init
+
+ SYNOPSIS
+ _ma_bitmap_end()
+ share Share handler
+*/
+
+my_bool _ma_bitmap_end(MARIA_SHARE *share)
+{
+ my_bool res= _ma_bitmap_flush(share);
+ safe_mutex_assert_owner(&share->close_lock);
+ pthread_mutex_destroy(&share->bitmap.bitmap_lock);
+ pthread_cond_destroy(&share->bitmap.bitmap_cond);
+ delete_dynamic(&share->bitmap.pinned_pages);
+ my_free((uchar*) share->bitmap.map, MYF(MY_ALLOW_ZERO_PTR));
+ share->bitmap.map= 0;
+ return res;
+}
+
+
+/*
+ Send updated bitmap to the page cache
+
+ SYNOPSIS
+ _ma_bitmap_flush()
+ share Share handler
+
+ NOTES
+ In the future, _ma_bitmap_flush() will be called to flush changes don't
+ by this thread (ie, checking the changed flag is ok). The reason we
+ check it again in the mutex is that if someone else did a flush at the
+ same time, we don't have to do the write.
+ This is also ok for _ma_scan_init_block_record() which does not want to
+ miss rows: it cares only for committed rows, that is, rows for which there
+ was a commit before our transaction started; as commit and transaction's
+ start are protected by the same LOCK_trn_list mutex, we see memory at
+ least as new as at other transaction's commit time, so if the committed
+ rows caused bitmap->changed to be true, we see it; if we see 0 it really
+ means a flush happened since then. So, it's ok to read without bitmap's
+ mutex.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+my_bool _ma_bitmap_flush(MARIA_SHARE *share)
+{
+ my_bool res= 0;
+ DBUG_ENTER("_ma_bitmap_flush");
+ if (share->bitmap.changed)
+ {
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+ if (share->bitmap.changed)
+ {
+ share->bitmap.changed= 0;
+ res= write_changed_bitmap(share, &share->bitmap);
+ }
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ }
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Dirty-page filtering criteria for bitmap pages
+
+ @param type Page's type
+ @param pageno Page's number
+ @param rec_lsn Page's rec_lsn
+ @param arg pages_covered of bitmap
+*/
+
+static enum pagecache_flush_filter_result
+filter_flush_bitmap_pages(enum pagecache_page_type type
+ __attribute__ ((unused)),
+ pgcache_page_no_t pageno,
+ LSN rec_lsn __attribute__ ((unused)),
+ void *arg)
+{
+ return ((pageno % (*(ulong*)arg)) == 0);
+}
+
+
+/**
+ Flushes current bitmap page to the pagecache, and then all bitmap pages
+ from pagecache to the file. Used by Checkpoint.
+
+ @param share Table's share
+*/
+
+my_bool _ma_bitmap_flush_all(MARIA_SHARE *share)
+{
+ my_bool res= 0;
+ MARIA_FILE_BITMAP *bitmap= &share->bitmap;
+ DBUG_ENTER("_ma_bitmap_flush_all");
+ pthread_mutex_lock(&bitmap->bitmap_lock);
+ if (bitmap->changed)
+ {
+ bitmap->flush_all_requested= TRUE;
+#ifndef WRONG_BITMAP_FLUSH
+ while (bitmap->non_flushable > 0)
+ {
+ DBUG_PRINT("info", ("waiting for bitmap to be flushable"));
+ pthread_cond_wait(&bitmap->bitmap_cond, &bitmap->bitmap_lock);
+ }
+#endif
+ /*
+ Bitmap is in a flushable state: its contents in memory are reflected by
+ log records (complete REDO-UNDO groups) and all bitmap pages are
+ unpinned. We keep the mutex to preserve this situation, and flush to the
+ file.
+ */
+ if (bitmap->changed)
+ {
+ res= write_changed_bitmap(share, bitmap);
+ bitmap->changed= FALSE;
+ }
+ /*
+ We do NOT use FLUSH_KEEP_LAZY because we must be sure that bitmap
+ pages have been flushed. That's a condition of correctness of
+ Recovery: data pages may have been all flushed, if we write the
+ checkpoint record Recovery will start from after their REDOs. If
+ bitmap page was not flushed, as the REDOs about it will be skipped, it
+ will wrongly not be recovered. If bitmap pages had a rec_lsn it would
+ be different.
+ There should be no pinned pages as bitmap->non_flushable==0.
+ */
+ if (flush_pagecache_blocks_with_filter(share->pagecache,
+ &bitmap->file, FLUSH_KEEP,
+ filter_flush_bitmap_pages,
+ &bitmap->pages_covered) &
+ PCFLUSH_PINNED_AND_ERROR)
+ res= TRUE;
+ bitmap->flush_all_requested= FALSE;
+ /*
+ Some well-behaved threads may be waiting for flush_all_requested to
+ become false, wake them up.
+ */
+ DBUG_PRINT("info", ("bitmap flusher waking up others"));
+ pthread_cond_broadcast(&bitmap->bitmap_cond);
+ }
+ pthread_mutex_unlock(&bitmap->bitmap_lock);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Unpin all pinned bitmap pages
+
+ @param share Table's share
+
+ @return Operation status
+ @retval 0 ok
+
+ @note This unpins pages pinned by other threads.
+*/
+
+static void _ma_bitmap_unpin_all(MARIA_SHARE *share)
+{
+ MARIA_FILE_BITMAP *bitmap= &share->bitmap;
+ MARIA_PINNED_PAGE *page_link= ((MARIA_PINNED_PAGE*)
+ dynamic_array_ptr(&bitmap->pinned_pages, 0));
+ MARIA_PINNED_PAGE *pinned_page= page_link + bitmap->pinned_pages.elements;
+ DBUG_ENTER("_ma_bitmap_unpin_all");
+ DBUG_PRINT("info", ("pinned: %u", bitmap->pinned_pages.elements));
+ while (pinned_page-- != page_link)
+ pagecache_unlock_by_link(share->pagecache, pinned_page->link,
+ pinned_page->unlock, PAGECACHE_UNPIN,
+ LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, TRUE, TRUE);
+ bitmap->pinned_pages.elements= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Intialize bitmap in memory to a zero bitmap
+
+ SYNOPSIS
+ _ma_bitmap_delete_all()
+ share Share handler
+
+ NOTES
+ This is called on maria_delete_all_rows (truncate data file).
+*/
+
+void _ma_bitmap_delete_all(MARIA_SHARE *share)
+{
+ MARIA_FILE_BITMAP *bitmap= &share->bitmap;
+ DBUG_ENTER("_ma_bitmap_delete_all");
+ if (bitmap->map) /* Not in create */
+ {
+ bzero(bitmap->map, bitmap->block_size);
+ bitmap->changed= 1;
+ bitmap->page= 0;
+ bitmap->used_size= bitmap->total_size;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Reset bitmap caches
+
+ @fn _ma_bitmap_reset_cache()
+ @param share Maria share
+
+ @notes
+ This is called after we have swapped file descriptors and we want
+ bitmap to forget all cached information
+*/
+
+void _ma_bitmap_reset_cache(MARIA_SHARE *share)
+{
+ MARIA_FILE_BITMAP *bitmap= &share->bitmap;
+
+ if (bitmap->map) /* If using bitmap */
+ {
+ /* Forget changes in current bitmap page */
+ bitmap->changed= 0;
+
+ /*
+ We can't read a page yet, as in some case we don't have an active
+ page cache yet.
+ Pretend we have a dummy, full and not changed bitmap page in memory.
+ */
+ bitmap->page= ~(ulonglong) 0;
+ bitmap->used_size= bitmap->total_size;
+ bfill(bitmap->map, share->block_size, 255);
+#ifndef DBUG_OFF
+ memcpy(bitmap->map + bitmap->block_size, bitmap->map, bitmap->block_size);
+#endif
+ }
+}
+
+
+/*
+ Return bitmap pattern for the smallest head block that can hold 'size'
+
+ SYNOPSIS
+ size_to_head_pattern()
+ bitmap Bitmap
+ size Requested size
+
+ RETURN
+ 0-3 For a description of the bitmap sizes, see the header
+*/
+
+static uint size_to_head_pattern(MARIA_FILE_BITMAP *bitmap, uint size)
+{
+ if (size <= bitmap->sizes[3])
+ return 3;
+ if (size <= bitmap->sizes[2])
+ return 2;
+ if (size <= bitmap->sizes[1])
+ return 1;
+ DBUG_ASSERT(size <= bitmap->sizes[0]);
+ return 0;
+}
+
+
+/*
+ Return bitmap pattern for head block where there is size bytes free
+
+ SYNOPSIS
+ _ma_free_size_to_head_pattern()
+ bitmap Bitmap
+ size Requested size
+
+ RETURN
+ 0-4 (Possible bitmap patterns for head block)
+*/
+
+uint _ma_free_size_to_head_pattern(MARIA_FILE_BITMAP *bitmap, uint size)
+{
+ if (size < bitmap->sizes[3])
+ return 4;
+ if (size < bitmap->sizes[2])
+ return 3;
+ if (size < bitmap->sizes[1])
+ return 2;
+ return (size < bitmap->sizes[0]) ? 1 : 0;
+}
+
+
+/*
+ Return bitmap pattern for the smallest tail block that can hold 'size'
+
+ SYNOPSIS
+ size_to_tail_pattern()
+ bitmap Bitmap
+ size Requested size
+
+ RETURN
+ 0, 5 or 6 For a description of the bitmap sizes, see the header
+*/
+
+static uint size_to_tail_pattern(MARIA_FILE_BITMAP *bitmap, uint size)
+{
+ if (size <= bitmap->sizes[6])
+ return 6;
+ if (size <= bitmap->sizes[5])
+ return 5;
+ DBUG_ASSERT(size <= bitmap->sizes[0]);
+ return 0;
+}
+
+
+/*
+ Return bitmap pattern for tail block where there is size bytes free
+
+ SYNOPSIS
+ free_size_to_tail_pattern()
+ bitmap Bitmap
+ size Requested size
+
+ RETURN
+ 0, 5, 6, 7 For a description of the bitmap sizes, see the header
+*/
+
+static uint free_size_to_tail_pattern(MARIA_FILE_BITMAP *bitmap, uint size)
+{
+ if (size >= bitmap->sizes[0])
+ return 0; /* Revert to empty page */
+ if (size < bitmap->sizes[6])
+ return 7;
+ if (size < bitmap->sizes[5])
+ return 6;
+ return 5;
+}
+
+
+/*
+ Return size guranteed to be available on a page
+
+ SYNOPSIS
+ pattern_to_head_size()
+ bitmap Bitmap
+ pattern Pattern (0-7)
+
+ RETURN
+ 0 - block_size
+*/
+
+static inline uint pattern_to_size(MARIA_FILE_BITMAP *bitmap, uint pattern)
+{
+ DBUG_ASSERT(pattern <= 7);
+ return bitmap->sizes[pattern];
+}
+
+
+/*
+ Print bitmap for debugging
+
+ SYNOPSIS
+ _ma_print_bitmap()
+ bitmap Bitmap to print
+
+ IMPLEMENTATION
+ Prints all changed bits since last call to _ma_print_bitmap().
+ This is done by having a copy of the last bitmap in
+ bitmap->map+bitmap->block_size.
+*/
+
+#ifndef DBUG_OFF
+
+const char *bits_to_txt[]=
+{
+ "empty", "00-30% full", "30-60% full", "60-90% full", "full",
+ "tail 00-40 % full", "tail 40-80 % full", "tail/blob full"
+};
+
+static void _ma_print_bitmap_changes(MARIA_FILE_BITMAP *bitmap)
+{
+ uchar *pos, *end, *org_pos;
+ ulong page;
+
+ end= bitmap->map + bitmap->used_size;
+ DBUG_LOCK_FILE;
+ fprintf(DBUG_FILE,"\nBitmap page changes at page %lu\n",
+ (ulong) bitmap->page);
+
+ page= (ulong) bitmap->page+1;
+ for (pos= bitmap->map, org_pos= bitmap->map + bitmap->block_size ;
+ pos < end ;
+ pos+= 6, org_pos+= 6)
+ {
+ ulonglong bits= uint6korr(pos); /* 6 bytes = 6*8/3= 16 patterns */
+ ulonglong org_bits= uint6korr(org_pos);
+ uint i;
+
+ /*
+ Test if there is any changes in the next 16 bitmaps (to not have to
+ loop through all bits if we know they are the same)
+ */
+ if (bits != org_bits)
+ {
+ for (i= 0; i < 16 ; i++, bits>>= 3, org_bits>>= 3)
+ {
+ if ((bits & 7) != (org_bits & 7))
+ fprintf(DBUG_FILE, "Page: %8lu %s -> %s\n", page+i,
+ bits_to_txt[org_bits & 7], bits_to_txt[bits & 7]);
+ }
+ }
+ page+= 16;
+ }
+ fputc('\n', DBUG_FILE);
+ DBUG_UNLOCK_FILE;
+ memcpy(bitmap->map + bitmap->block_size, bitmap->map, bitmap->block_size);
+}
+
+
+/* Print content of bitmap for debugging */
+
+void _ma_print_bitmap(MARIA_FILE_BITMAP *bitmap, uchar *data,
+ pgcache_page_no_t page)
+{
+ uchar *pos, *end;
+ char llbuff[22];
+
+ end= bitmap->map + bitmap->used_size;
+ DBUG_LOCK_FILE;
+ fprintf(DBUG_FILE,"\nDump of bitmap page at %s\n", llstr(page, llbuff));
+
+ page++; /* Skip bitmap page */
+ for (pos= data, end= pos + bitmap->total_size;
+ pos < end ;
+ pos+= 6)
+ {
+ ulonglong bits= uint6korr(pos); /* 6 bytes = 6*8/3= 16 patterns */
+
+ /*
+ Test if there is any changes in the next 16 bitmaps (to not have to
+ loop through all bits if we know they are the same)
+ */
+ if (bits)
+ {
+ uint i;
+ for (i= 0; i < 16 ; i++, bits>>= 3)
+ {
+ if (bits & 7)
+ fprintf(DBUG_FILE, "Page: %8s %s\n", llstr(page+i, llbuff),
+ bits_to_txt[bits & 7]);
+ }
+ }
+ page+= 16;
+ }
+ fputc('\n', DBUG_FILE);
+ DBUG_UNLOCK_FILE;
+}
+
+#endif /* DBUG_OFF */
+
+
+/***************************************************************************
+ Reading & writing bitmap pages
+***************************************************************************/
+
+/*
+ Read a given bitmap page
+
+ SYNOPSIS
+ _ma_read_bitmap_page()
+ info Maria handler
+ bitmap Bitmap handler
+ page Page to read
+
+ TODO
+ Update 'bitmap->used_size' to real size of used bitmap
+
+ NOTE
+ We don't always have share->bitmap.bitmap_lock here
+ (when called from_ma_check_bitmap_data() for example).
+
+ RETURN
+ 0 ok
+ 1 error (Error writing old bitmap or reading bitmap page)
+*/
+
+static my_bool _ma_read_bitmap_page(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page)
+{
+ MARIA_SHARE *share= info->s;
+ my_bool res;
+ DBUG_ENTER("_ma_read_bitmap_page");
+ DBUG_ASSERT(page % bitmap->pages_covered == 0);
+ DBUG_ASSERT(!bitmap->changed);
+
+ bitmap->page= page;
+ if (((page + 1) * bitmap->block_size) > share->state.state.data_file_length)
+ {
+ /* Inexistent or half-created page */
+ res= _ma_bitmap_create_missing(info, bitmap, page);
+ DBUG_RETURN(res);
+ }
+ bitmap->used_size= bitmap->total_size;
+ DBUG_ASSERT(share->pagecache->block_size == bitmap->block_size);
+ res= pagecache_read(share->pagecache,
+ &bitmap->file, page, 0,
+ (uchar*) bitmap->map,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == NULL;
+
+ /*
+ We can't check maria_bitmap_marker here as if the bitmap page
+ previously had a true checksum and the user switched mode to not checksum
+ this may have any value, except maria_normal_page_marker.
+
+ Using maria_normal_page_marker gives us a protection against bugs
+ when running without any checksums.
+ */
+
+#ifndef DBUG_OFF
+ if (!res)
+ memcpy(bitmap->map + bitmap->block_size, bitmap->map, bitmap->block_size);
+#endif
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Change to another bitmap page
+
+ SYNOPSIS
+ _ma_change_bitmap_page()
+ info Maria handler
+ bitmap Bitmap handler
+ page Bitmap page to read
+
+ NOTES
+ If old bitmap was changed, write it out before reading new one
+ We return empty bitmap if page is outside of file size
+
+ RETURN
+ 0 ok
+ 1 error (Error writing old bitmap or reading bitmap page)
+*/
+
+static my_bool _ma_change_bitmap_page(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page)
+{
+ DBUG_ENTER("_ma_change_bitmap_page");
+
+ if (bitmap->changed)
+ {
+ if (write_changed_bitmap(info->s, bitmap))
+ DBUG_RETURN(1);
+ bitmap->changed= 0;
+ }
+ DBUG_RETURN(_ma_read_bitmap_page(info, bitmap, page));
+}
+
+
+/*
+ Read next suitable bitmap
+
+ SYNOPSIS
+ move_to_next_bitmap()
+ bitmap Bitmap handle
+
+ NOTES
+ The found bitmap may be full, so calling function may need to call this
+ repeatedly until it finds enough space.
+
+ TODO
+ Add cache of bitmaps to not read something that is not usable
+
+ RETURN
+ 0 ok
+ 1 error (either couldn't save old bitmap or read new one)
+*/
+
+static my_bool move_to_next_bitmap(MARIA_HA *info, MARIA_FILE_BITMAP *bitmap)
+{
+ pgcache_page_no_t page= bitmap->page;
+ MARIA_STATE_INFO *state= &info->s->state;
+ DBUG_ENTER("move_to_next_bitmap");
+
+ if (state->first_bitmap_with_space != ~(ulonglong) 0 &&
+ state->first_bitmap_with_space != page)
+ {
+ page= state->first_bitmap_with_space;
+ state->first_bitmap_with_space= ~(ulonglong) 0;
+ }
+ else
+ page+= bitmap->pages_covered;
+ DBUG_RETURN(_ma_change_bitmap_page(info, bitmap, page));
+}
+
+
+/****************************************************************************
+ Allocate data in bitmaps
+****************************************************************************/
+
+/*
+ Store data in 'block' and mark the place used in the bitmap
+
+ SYNOPSIS
+ fill_block()
+ bitmap Bitmap handle
+ block Store data about what we found
+ best_data Pointer to best 6 uchar aligned area in bitmap->map
+ best_pos Which bit in *best_data the area starts
+ 0 = first bit pattern, 1 second bit pattern etc
+ best_bits The original value of the bits at best_pos
+ fill_pattern Bitmap pattern to store in best_data[best_pos]
+
+ NOTES
+ We mark all pages to be 'TAIL's, which means that
+ block->page_count is really a row position inside the page.
+*/
+
+static void fill_block(MARIA_FILE_BITMAP *bitmap,
+ MARIA_BITMAP_BLOCK *block,
+ uchar *best_data, uint best_pos, uint best_bits,
+ uint fill_pattern)
+{
+ uint page, offset, tmp;
+ uchar *data;
+
+ /* For each 6 bytes we have 6*8/3= 16 patterns */
+ page= ((uint) (best_data - bitmap->map)) / 6 * 16 + best_pos;
+ DBUG_ASSERT(page + 1 < bitmap->pages_covered);
+ block->page= bitmap->page + 1 + page;
+ block->page_count= TAIL_PAGE_COUNT_MARKER;
+ block->empty_space= pattern_to_size(bitmap, best_bits);
+ block->sub_blocks= 0;
+ block->org_bitmap_value= best_bits;
+ block->used= BLOCKUSED_TAIL; /* See _ma_bitmap_release_unused() */
+
+ /*
+ Mark place used by reading/writing 2 bytes at a time to handle
+ bitmaps in overlapping bytes
+ */
+ best_pos*= 3;
+ data= best_data+ best_pos / 8;
+ offset= best_pos & 7;
+ tmp= uint2korr(data);
+
+ /* we turn off the 3 bits and replace them with fill_pattern */
+ tmp= (tmp & ~(7 << offset)) | (fill_pattern << offset);
+ int2store(data, tmp);
+ bitmap->changed= 1;
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
+}
+
+
+/*
+ Allocate data for head block
+
+ SYNOPSIS
+ allocate_head()
+ bitmap bitmap
+ size Size of data region we need to store
+ block Store found information here
+
+ IMPLEMENTATION
+ Find the best-fit page to put a region of 'size'
+ This is defined as the first page of the set of pages
+ with the smallest free space that can hold 'size'.
+
+ RETURN
+ 0 ok (block is updated)
+ 1 error (no space in bitmap; block is not touched)
+*/
+
+
+static my_bool allocate_head(MARIA_FILE_BITMAP *bitmap, uint size,
+ MARIA_BITMAP_BLOCK *block)
+{
+ uint min_bits= size_to_head_pattern(bitmap, size);
+ uchar *data= bitmap->map, *end= data + bitmap->used_size;
+ uchar *best_data= 0;
+ uint best_bits= (uint) -1, best_pos;
+ DBUG_ENTER("allocate_head");
+
+ LINT_INIT(best_pos);
+ DBUG_ASSERT(size <= FULL_PAGE_SIZE(bitmap->block_size));
+
+ for (; data < end; data+= 6)
+ {
+ ulonglong bits= uint6korr(data); /* 6 bytes = 6*8/3= 16 patterns */
+ uint i;
+
+ /*
+ Skip common patterns
+ We can skip empty pages (if we already found a match) or
+ anything matching the following pattern as this will be either
+ a full page or a tail page
+ */
+ if ((!bits && best_data) ||
+ ((bits & LL(04444444444444444)) == LL(04444444444444444)))
+ continue;
+ for (i= 0; i < 16 ; i++, bits >>= 3)
+ {
+ uint pattern= (uint) (bits & 7);
+ if (pattern <= min_bits)
+ {
+ /* There is enough space here */
+ if ((int) pattern > (int) best_bits)
+ {
+ /*
+ There is more than enough space here and it's better than what
+ we have found so far. Remember it, as we will choose it if we
+ don't find anything in this bitmap page.
+ */
+ best_bits= pattern;
+ best_data= data;
+ best_pos= i;
+ if (pattern == min_bits)
+ goto found; /* Best possible match */
+ }
+ }
+ }
+ }
+ if (!best_data) /* Found no place */
+ {
+ if (data >= bitmap->map + bitmap->total_size)
+ DBUG_RETURN(1); /* No space in bitmap */
+ /* Allocate data at end of bitmap */
+ bitmap->used_size+= 6;
+ set_if_smaller(bitmap->used_size, bitmap->total_size);
+ best_data= data;
+ best_pos= best_bits= 0;
+ }
+
+found:
+ fill_block(bitmap, block, best_data, best_pos, best_bits, FULL_HEAD_PAGE);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Allocate data for tail block
+
+ SYNOPSIS
+ allocate_tail()
+ bitmap bitmap
+ size Size of block we need to find
+ block Store found information here
+
+ RETURN
+ 0 ok (block is updated)
+ 1 error (no space in bitmap; block is not touched)
+*/
+
+
+static my_bool allocate_tail(MARIA_FILE_BITMAP *bitmap, uint size,
+ MARIA_BITMAP_BLOCK *block)
+{
+ uint min_bits= size_to_tail_pattern(bitmap, size);
+ uchar *data= bitmap->map, *end= data + bitmap->used_size;
+ uchar *best_data= 0;
+ uint best_bits= (uint) -1, best_pos;
+ DBUG_ENTER("allocate_tail");
+ DBUG_PRINT("enter", ("size: %u", size));
+
+ LINT_INIT(best_pos);
+ DBUG_ASSERT(size <= FULL_PAGE_SIZE(bitmap->block_size));
+
+ for (; data < end; data += 6)
+ {
+ ulonglong bits= uint6korr(data); /* 6 bytes = 6*8/3= 16 patterns */
+ uint i;
+
+ /*
+ Skip common patterns
+ We can skip empty pages (if we already found a match) or
+ the following patterns: 1-4 (head pages, not suitable for tail) or
+ 7 (full tail page). See 'Dynamic size records' comment at start of file.
+
+ At the moment we only skip full head and tail pages (ie, all bits are
+ set) as this is easy to detect with one simple test and is a
+ quite common case if we have blobs.
+ */
+
+ if ((!bits && best_data) || bits == LL(0xffffffffffff) ||
+ bits == LL(04444444444444444))
+ continue;
+ for (i= 0; i < 16; i++, bits >>= 3)
+ {
+ uint pattern= (uint) (bits & 7);
+ if (pattern <= min_bits && (!pattern || pattern >= 5))
+ {
+ if ((int) pattern > (int) best_bits)
+ {
+ best_bits= pattern;
+ best_data= data;
+ best_pos= i;
+ if (pattern == min_bits)
+ goto found; /* Can't be better */
+ }
+ }
+ }
+ }
+ if (!best_data)
+ {
+ if (data >= bitmap->map + bitmap->total_size)
+ DBUG_RETURN(1);
+ /* Allocate data at end of bitmap */
+ best_data= data;
+ bitmap->used_size+= 6;
+ set_if_smaller(bitmap->used_size, bitmap->total_size);
+ best_pos= best_bits= 0;
+ }
+
+found:
+ fill_block(bitmap, block, best_data, best_pos, best_bits, FULL_TAIL_PAGE);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Allocate data for full blocks
+
+ SYNOPSIS
+ allocate_full_pages()
+ bitmap bitmap
+ pages_needed Total size in pages (bitmap->total_size) we would like to have
+ block Store found information here
+ full_page 1 if we are not allowed to split extent
+
+ IMPLEMENTATION
+ We will return the smallest area >= size. If there is no such
+ block, we will return the biggest area that satisfies
+ area_size >= min(BLOB_SEGMENT_MIN_SIZE*full_page_size, size)
+
+ To speed up searches, we will only consider areas that has at least 16 free
+ pages starting on an even boundary. When finding such an area, we will
+ extend it with all previous and following free pages. This will ensure
+ we don't get holes between areas
+
+ RETURN
+ # Blocks used
+ 0 error (no space in bitmap; block is not touched)
+*/
+
+static ulong allocate_full_pages(MARIA_FILE_BITMAP *bitmap,
+ ulong pages_needed,
+ MARIA_BITMAP_BLOCK *block, my_bool full_page)
+{
+ uchar *data= bitmap->map, *data_end= data + bitmap->used_size;
+ uchar *page_end= data + bitmap->total_size;
+ uchar *best_data= 0;
+ uint min_size;
+ uint best_area_size, best_prefix_area_size, best_suffix_area_size;
+ uint page, size;
+ ulonglong best_prefix_bits;
+ DBUG_ENTER("allocate_full_pages");
+ DBUG_PRINT("enter", ("pages_needed: %lu", pages_needed));
+
+ /* Following variables are only used if best_data is set */
+ LINT_INIT(best_prefix_bits);
+ LINT_INIT(best_prefix_area_size);
+ LINT_INIT(best_suffix_area_size);
+
+ min_size= pages_needed;
+ if (!full_page && min_size > BLOB_SEGMENT_MIN_SIZE)
+ min_size= BLOB_SEGMENT_MIN_SIZE;
+ best_area_size= ~(uint) 0;
+
+ for (; data < page_end; data+= 6)
+ {
+ ulonglong bits= uint6korr(data); /* 6 bytes = 6*8/3= 16 patterns */
+ uchar *data_start;
+ ulonglong prefix_bits= 0;
+ uint area_size, prefix_area_size, suffix_area_size;
+
+ /* Find area with at least 16 free pages */
+ if (bits)
+ continue;
+ data_start= data;
+ /* Find size of area */
+ for (data+=6 ; data < data_end ; data+= 6)
+ {
+ if ((bits= uint6korr(data)))
+ break;
+ }
+ area_size= (uint) (data - data_start) / 6 * 16;
+ if (area_size >= best_area_size)
+ continue;
+ prefix_area_size= suffix_area_size= 0;
+ if (!bits)
+ {
+ /*
+ End of page; All the rest of the bits on page are part of area
+ This is needed because bitmap->used_size only covers the set bits
+ in the bitmap.
+ */
+ area_size+= (uint) (page_end - data) / 6 * 16;
+ if (area_size >= best_area_size)
+ break;
+ data= page_end;
+ }
+ else
+ {
+ /* Add bits at end of page */
+ for (; !(bits & 7); bits >>= 3)
+ suffix_area_size++;
+ area_size+= suffix_area_size;
+ }
+ if (data_start != bitmap->map)
+ {
+ /* Add bits before page */
+ bits= prefix_bits= uint6korr(data_start - 6);
+ DBUG_ASSERT(bits != 0);
+ /* 111 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 */
+ if (!(bits & LL(07000000000000000)))
+ {
+ data_start-= 6;
+ do
+ {
+ prefix_area_size++;
+ bits<<= 3;
+ } while (!(bits & LL(07000000000000000)));
+ area_size+= prefix_area_size;
+ /* Calculate offset to page from data_start */
+ prefix_area_size= 16 - prefix_area_size;
+ }
+ }
+ if (area_size >= min_size && area_size <= best_area_size)
+ {
+ best_data= data_start;
+ best_area_size= area_size;
+ best_prefix_bits= prefix_bits;
+ best_prefix_area_size= prefix_area_size;
+ best_suffix_area_size= suffix_area_size;
+
+ /* Prefer to put data in biggest possible area */
+ if (area_size <= pages_needed)
+ min_size= area_size;
+ else
+ min_size= pages_needed;
+ }
+ }
+ if (!best_data)
+ DBUG_RETURN(0); /* No room on page */
+
+ /*
+ Now allocate min(pages_needed, area_size), starting from
+ best_start + best_prefix_area_size
+ */
+ if (best_area_size > pages_needed)
+ best_area_size= pages_needed;
+
+ /* For each 6 bytes we have 6*8/3= 16 patterns */
+ page= ((uint) (best_data - bitmap->map) * 8) / 3 + best_prefix_area_size;
+ block->page= bitmap->page + 1 + page;
+ block->page_count= best_area_size;
+ block->empty_space= 0;
+ block->sub_blocks= 0;
+ block->org_bitmap_value= 0;
+ block->used= 0;
+ DBUG_ASSERT(page + best_area_size < bitmap->pages_covered);
+ DBUG_PRINT("info", ("page: %lu page_count: %u",
+ (ulong) block->page, block->page_count));
+
+ if (best_prefix_area_size)
+ {
+ ulonglong tmp;
+ /* Convert offset back to bits */
+ best_prefix_area_size= 16 - best_prefix_area_size;
+ if (best_area_size < best_prefix_area_size)
+ {
+ tmp= (LL(1) << best_area_size*3) - 1;
+ best_area_size= best_prefix_area_size; /* for easy end test */
+ }
+ else
+ tmp= (LL(1) << best_prefix_area_size*3) - 1;
+ tmp<<= (16 - best_prefix_area_size) * 3;
+ DBUG_ASSERT((best_prefix_bits & tmp) == 0);
+ best_prefix_bits|= tmp;
+ int6store(best_data, best_prefix_bits);
+ if (!(best_area_size-= best_prefix_area_size))
+ {
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
+ DBUG_RETURN(block->page_count);
+ }
+ best_data+= 6;
+ }
+ best_area_size*= 3; /* Bits to set */
+ size= best_area_size/8; /* Bytes to set */
+ bfill(best_data, size, 255);
+ best_data+= size;
+ if ((best_area_size-= size * 8))
+ {
+ /* fill last uchar */
+ *best_data|= (uchar) ((1 << best_area_size) -1);
+ best_data++;
+ }
+ if (data_end < best_data)
+ {
+ bitmap->used_size= (uint) (best_data - bitmap->map);
+ DBUG_ASSERT(bitmap->used_size <= bitmap->total_size);
+ }
+ bitmap->changed= 1;
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
+ DBUG_RETURN(block->page_count);
+}
+
+
+/****************************************************************************
+ Find right bitmaps where to store data
+****************************************************************************/
+
+/*
+ Find right bitmap and position for head block
+
+ SYNOPSIS
+ find_head()
+ info Maria handler
+ length Size of data region we need store
+ position Position in bitmap_blocks where to store the
+ information for the head block.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool find_head(MARIA_HA *info, uint length, uint position)
+{
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ MARIA_BITMAP_BLOCK *block;
+ /*
+ There is always place for the head block in bitmap_blocks as these are
+ preallocated at _ma_init_block_record().
+ */
+ block= dynamic_element(&info->bitmap_blocks, position, MARIA_BITMAP_BLOCK *);
+
+ /*
+ We need to have DIRENTRY_SIZE here to take into account that we may
+ need an extra directory entry for the row
+ */
+ while (allocate_head(bitmap, length + DIR_ENTRY_SIZE, block))
+ if (move_to_next_bitmap(info, bitmap))
+ return 1;
+ return 0;
+}
+
+
+/*
+ Find right bitmap and position for tail
+
+ SYNOPSIS
+ find_tail()
+ info Maria handler
+ length Size of data region we need store
+ position Position in bitmap_blocks where to store the
+ information for the head block.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool find_tail(MARIA_HA *info, uint length, uint position)
+{
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ MARIA_BITMAP_BLOCK *block;
+ DBUG_ENTER("find_tail");
+ DBUG_ASSERT(length <= info->s->block_size - PAGE_OVERHEAD_SIZE);
+
+ /* Needed, as there is no error checking in dynamic_element */
+ if (allocate_dynamic(&info->bitmap_blocks, position))
+ DBUG_RETURN(1);
+ block= dynamic_element(&info->bitmap_blocks, position, MARIA_BITMAP_BLOCK *);
+
+ /*
+ We have to add DIR_ENTRY_SIZE to ensure we have space for the tail and
+ it's directroy entry on the page
+ */
+ while (allocate_tail(bitmap, length + DIR_ENTRY_SIZE, block))
+ if (move_to_next_bitmap(info, bitmap))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Find right bitmap and position for full blocks in one extent
+
+ SYNOPSIS
+ find_mid()
+ info Maria handler.
+ pages How many pages to allocate.
+ position Position in bitmap_blocks where to store the
+ information for the head block.
+ NOTES
+ This is used to allocate the main extent after the 'head' block
+ (Ie, the middle part of the head-middle-tail entry)
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool find_mid(MARIA_HA *info, ulong pages, uint position)
+{
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ MARIA_BITMAP_BLOCK *block;
+ block= dynamic_element(&info->bitmap_blocks, position, MARIA_BITMAP_BLOCK *);
+
+ while (!allocate_full_pages(bitmap, pages, block, 1))
+ {
+ if (move_to_next_bitmap(info, bitmap))
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ Find right bitmap and position for putting a blob
+
+ SYNOPSIS
+ find_blob()
+ info Maria handler.
+ length Length of the blob
+
+ NOTES
+ The extents are stored last in info->bitmap_blocks
+
+ IMPLEMENTATION
+ Allocate all full pages for the block + optionally one tail
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool find_blob(MARIA_HA *info, ulong length)
+{
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ uint full_page_size= FULL_PAGE_SIZE(info->s->block_size);
+ ulong pages;
+ uint rest_length, used;
+ uint first_block_pos;
+ MARIA_BITMAP_BLOCK *first_block= 0;
+ DBUG_ENTER("find_blob");
+ DBUG_PRINT("enter", ("length: %lu", length));
+ LINT_INIT(first_block_pos);
+
+ pages= length / full_page_size;
+ rest_length= (uint) (length - pages * full_page_size);
+ if (rest_length >= MAX_TAIL_SIZE(info->s->block_size))
+ {
+ pages++;
+ rest_length= 0;
+ }
+
+ first_block_pos= info->bitmap_blocks.elements;
+ if (pages)
+ {
+ MARIA_BITMAP_BLOCK *block;
+ if (allocate_dynamic(&info->bitmap_blocks,
+ info->bitmap_blocks.elements +
+ pages / BLOB_SEGMENT_MIN_SIZE + 2))
+ DBUG_RETURN(1);
+ block= dynamic_element(&info->bitmap_blocks, info->bitmap_blocks.elements,
+ MARIA_BITMAP_BLOCK*);
+ do
+ {
+ /*
+ We use 0x3fff here as the two upmost bits are reserved for
+ TAIL_BIT and START_EXTENT_BIT
+ */
+ used= allocate_full_pages(bitmap,
+ (pages >= 0x3fff ? 0x3fff : (uint) pages),
+ block, 0);
+ if (!used)
+ {
+ if (move_to_next_bitmap(info, bitmap))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ pages-= used;
+ info->bitmap_blocks.elements++;
+ block++;
+ }
+ } while (pages != 0);
+ }
+ if (rest_length && find_tail(info, rest_length,
+ info->bitmap_blocks.elements++))
+ DBUG_RETURN(1);
+ first_block= dynamic_element(&info->bitmap_blocks, first_block_pos,
+ MARIA_BITMAP_BLOCK*);
+ first_block->sub_blocks= info->bitmap_blocks.elements - first_block_pos;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Find pages to put ALL blobs
+
+ SYNOPSIS
+ allocate_blobs()
+ info Maria handler
+ row Information of what is in the row (from calc_record_size())
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool allocate_blobs(MARIA_HA *info, MARIA_ROW *row)
+{
+ ulong *length, *end;
+ uint elements;
+ /*
+ Reserve size for:
+ head block
+ one extent
+ tail block
+ */
+ elements= info->bitmap_blocks.elements;
+ for (length= row->blob_lengths, end= length + info->s->base.blobs;
+ length < end; length++)
+ {
+ if (*length && find_blob(info, *length))
+ return 1;
+ }
+ row->extents_count= (info->bitmap_blocks.elements - elements);
+ return 0;
+}
+
+
+/*
+ Store in the bitmap the new size for a head page
+
+ SYNOPSIS
+ use_head()
+ info Maria handler
+ page Page number to update
+ (Note that caller guarantees this is in the active
+ bitmap)
+ size How much free space is left on the page
+ block_position In which info->bitmap_block we have the
+ information about the head block.
+
+ NOTES
+ This is used on update where we are updating an existing head page
+*/
+
+static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size,
+ uint block_position)
+{
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ MARIA_BITMAP_BLOCK *block;
+ uchar *data;
+ uint offset, tmp, offset_page;
+ DBUG_ASSERT(page % bitmap->pages_covered);
+
+ block= dynamic_element(&info->bitmap_blocks, block_position,
+ MARIA_BITMAP_BLOCK*);
+ block->page= page;
+ block->page_count= 1 + TAIL_BIT;
+ block->empty_space= size;
+ block->used= BLOCKUSED_TAIL;
+
+ /*
+ Mark place used by reading/writing 2 bytes at a time to handle
+ bitmaps in overlapping bytes
+ */
+ offset_page= (uint) (page - bitmap->page - 1) * 3;
+ offset= offset_page & 7;
+ data= bitmap->map + offset_page / 8;
+ tmp= uint2korr(data);
+ block->org_bitmap_value= (tmp >> offset) & 7;
+ tmp= (tmp & ~(7 << offset)) | (FULL_HEAD_PAGE << offset);
+ int2store(data, tmp);
+ bitmap->changed= 1;
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
+}
+
+
+/*
+ Find out where to split the row (ie, what goes in head, middle, tail etc)
+
+ SYNOPSIS
+ find_where_to_split_row()
+ share Maria share
+ row Information of what is in the row (from calc_record_size())
+ extents_length Number of bytes needed to store all extents
+ split_size Free size on the page (The head length must be less
+ than this)
+
+ RETURN
+ row_length for the head block.
+*/
+
+static uint find_where_to_split_row(MARIA_SHARE *share, MARIA_ROW *row,
+ uint extents_length, uint split_size)
+{
+ uint *lengths, *lengths_end;
+ /*
+ Ensure we have the minimum required space on head page:
+ - Header + length of field lengths (row->min_length)
+ - Number of extents
+ - One extent
+ */
+ uint row_length= (row->min_length +
+ size_to_store_key_length(extents_length) +
+ ROW_EXTENT_SIZE);
+ DBUG_ASSERT(row_length < split_size);
+ /*
+ Store first in all_field_lengths the different parts that are written
+ to the row. This needs to be in same order as in
+ ma_block_rec.c::write_block_record()
+ */
+ row->null_field_lengths[-3]= extents_length;
+ row->null_field_lengths[-2]= share->base.fixed_not_null_fields_length;
+ row->null_field_lengths[-1]= row->field_lengths_length;
+ for (lengths= row->null_field_lengths - EXTRA_LENGTH_FIELDS,
+ lengths_end= (lengths + share->base.pack_fields - share->base.blobs +
+ EXTRA_LENGTH_FIELDS); lengths < lengths_end; lengths++)
+ {
+ if (row_length + *lengths > split_size)
+ break;
+ row_length+= *lengths;
+ }
+ return row_length;
+}
+
+
+/*
+ Find where to write the middle parts of the row and the tail
+
+ SYNOPSIS
+ write_rest_of_head()
+ info Maria handler
+ position Position in bitmap_blocks. Is 0 for rows that needs
+ full blocks (ie, has a head, middle part and optional tail)
+ rest_length How much left of the head block to write.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool write_rest_of_head(MARIA_HA *info, uint position,
+ ulong rest_length)
+{
+ MARIA_SHARE *share= info->s;
+ uint full_page_size= FULL_PAGE_SIZE(share->block_size);
+ MARIA_BITMAP_BLOCK *block;
+ DBUG_ENTER("write_rest_of_head");
+ DBUG_PRINT("enter", ("position: %u rest_length: %lu", position,
+ rest_length));
+
+ if (position == 0)
+ {
+ /* Write out full pages */
+ uint pages= rest_length / full_page_size;
+
+ rest_length%= full_page_size;
+ if (rest_length >= MAX_TAIL_SIZE(share->block_size))
+ {
+ /* Put tail on a full page */
+ pages++;
+ rest_length= 0;
+ }
+ if (find_mid(info, pages, 1))
+ DBUG_RETURN(1);
+ /*
+ Insert empty block after full pages, to allow write_block_record() to
+ split segment into used + free page
+ */
+ block= dynamic_element(&info->bitmap_blocks, 2, MARIA_BITMAP_BLOCK*);
+ block->page_count= 0;
+ block->used= 0;
+ }
+ if (rest_length)
+ {
+ if (find_tail(info, rest_length, ELEMENTS_RESERVED_FOR_MAIN_PART - 1))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ /* Empty tail block */
+ block= dynamic_element(&info->bitmap_blocks,
+ ELEMENTS_RESERVED_FOR_MAIN_PART - 1,
+ MARIA_BITMAP_BLOCK *);
+ block->page_count= 0;
+ block->used= 0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Find where to store one row
+
+ SYNPOSIS
+ _ma_bitmap_find_place()
+ info Maria handler
+ row Information about row to write
+ blocks Store data about allocated places here
+
+ RETURN
+ 0 ok
+ row->space_on_head_page contains minimum number of bytes we
+ expect to put on the head page.
+ 1 error
+ my_errno is set to error
+*/
+
+my_bool _ma_bitmap_find_place(MARIA_HA *info, MARIA_ROW *row,
+ MARIA_BITMAP_BLOCKS *blocks)
+{
+ MARIA_SHARE *share= info->s;
+ my_bool res= 1;
+ uint full_page_size, position, max_page_size;
+ uint head_length, row_length, rest_length, extents_length;
+ DBUG_ENTER("_ma_bitmap_find_place");
+
+ blocks->count= 0;
+ blocks->tail_page_skipped= blocks->page_skipped= 0;
+ row->extents_count= 0;
+
+ /*
+ Reserve place for the following blocks:
+ - Head block
+ - Full page block
+ - Marker block to allow write_block_record() to split full page blocks
+ into full and free part
+ - Tail block
+ */
+
+ info->bitmap_blocks.elements= ELEMENTS_RESERVED_FOR_MAIN_PART;
+ max_page_size= (share->block_size - PAGE_OVERHEAD_SIZE);
+
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+
+ if (row->total_length <= max_page_size)
+ {
+ /* Row fits in one page */
+ position= ELEMENTS_RESERVED_FOR_MAIN_PART - 1;
+ if (find_head(info, (uint) row->total_length, position))
+ goto abort;
+ row->space_on_head_page= row->total_length;
+ goto end;
+ }
+
+ /*
+ First allocate all blobs so that we can find out the needed size for
+ the main block.
+ */
+ if (row->blob_length && allocate_blobs(info, row))
+ goto abort;
+
+ extents_length= row->extents_count * ROW_EXTENT_SIZE;
+ /*
+ The + 3 is reserved for storing the number of segments in the row header.
+ */
+ if ((head_length= (row->head_length + extents_length + 3)) <=
+ max_page_size)
+ {
+ /* Main row part fits into one page */
+ position= ELEMENTS_RESERVED_FOR_MAIN_PART - 1;
+ if (find_head(info, head_length, position))
+ goto abort;
+ row->space_on_head_page= head_length;
+ goto end;
+ }
+
+ /* Allocate enough space */
+ head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE;
+
+ /* The first segment size is stored in 'row_length' */
+ row_length= find_where_to_split_row(share, row, extents_length,
+ max_page_size);
+
+ full_page_size= FULL_PAGE_SIZE(share->block_size);
+ position= 0;
+ if (head_length - row_length <= full_page_size)
+ position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */
+ if (find_head(info, row_length, position))
+ goto abort;
+ row->space_on_head_page= row_length;
+
+ rest_length= head_length - row_length;
+ if (write_rest_of_head(info, position, rest_length))
+ goto abort;
+
+end:
+ blocks->block= dynamic_element(&info->bitmap_blocks, position,
+ MARIA_BITMAP_BLOCK*);
+ blocks->block->sub_blocks= ELEMENTS_RESERVED_FOR_MAIN_PART - position;
+ /* First block's page_count is for all blocks */
+ blocks->count= info->bitmap_blocks.elements - position;
+ res= 0;
+
+abort:
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Find where to put row on update (when head page is already defined)
+
+ SYNPOSIS
+ _ma_bitmap_find_new_place()
+ info Maria handler
+ row Information about row to write
+ page On which page original row was stored
+ free_size Free size on head page
+ blocks Store data about allocated places here
+
+ NOTES
+ This function is only called when the new row can't fit in the space of
+ the old row in the head page.
+
+ This is essently same as _ma_bitmap_find_place() except that
+ we don't call find_head() to search in bitmaps where to put the page.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+my_bool _ma_bitmap_find_new_place(MARIA_HA *info, MARIA_ROW *row,
+ pgcache_page_no_t page, uint free_size,
+ MARIA_BITMAP_BLOCKS *blocks)
+{
+ MARIA_SHARE *share= info->s;
+ my_bool res= 1;
+ uint position;
+ uint head_length, row_length, rest_length, extents_length;
+ ulonglong bitmap_page;
+ DBUG_ENTER("_ma_bitmap_find_new_place");
+
+ blocks->count= 0;
+ blocks->tail_page_skipped= blocks->page_skipped= 0;
+ row->extents_count= 0;
+ info->bitmap_blocks.elements= ELEMENTS_RESERVED_FOR_MAIN_PART;
+
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+
+ /*
+ First allocate all blobs (so that we can find out the needed size for
+ the main block.
+ */
+ if (row->blob_length && allocate_blobs(info, row))
+ goto abort;
+
+ /* Switch bitmap to current head page */
+ bitmap_page= page / share->bitmap.pages_covered;
+ bitmap_page*= share->bitmap.pages_covered;
+
+ if (share->bitmap.page != bitmap_page &&
+ _ma_change_bitmap_page(info, &share->bitmap, bitmap_page))
+ goto abort;
+
+ extents_length= row->extents_count * ROW_EXTENT_SIZE;
+ if ((head_length= (row->head_length + extents_length + 3)) <= free_size)
+ {
+ /* Main row part fits into one page */
+ position= ELEMENTS_RESERVED_FOR_MAIN_PART - 1;
+ use_head(info, page, head_length, position);
+ row->space_on_head_page= head_length;
+ goto end;
+ }
+
+ /* Allocate enough space */
+ head_length+= ELEMENTS_RESERVED_FOR_MAIN_PART * ROW_EXTENT_SIZE;
+
+ /* The first segment size is stored in 'row_length' */
+ row_length= find_where_to_split_row(share, row, extents_length, free_size);
+
+ position= 0;
+ if (head_length - row_length < MAX_TAIL_SIZE(share->block_size))
+ position= ELEMENTS_RESERVED_FOR_MAIN_PART -2; /* Only head and tail */
+ use_head(info, page, row_length, position);
+ row->space_on_head_page= row_length;
+
+ rest_length= head_length - row_length;
+ if (write_rest_of_head(info, position, rest_length))
+ goto abort;
+
+end:
+ blocks->block= dynamic_element(&info->bitmap_blocks, position,
+ MARIA_BITMAP_BLOCK*);
+ blocks->block->sub_blocks= ELEMENTS_RESERVED_FOR_MAIN_PART - position;
+ /* First block's page_count is for all blocks */
+ blocks->count= info->bitmap_blocks.elements - position;
+ res= 0;
+
+abort:
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ DBUG_RETURN(res);
+}
+
+
+/****************************************************************************
+ Clear and reset bits
+****************************************************************************/
+
+/*
+ Set fill pattern for a page
+
+ set_page_bits()
+ info Maria handler
+ bitmap Bitmap handler
+ page Adress to page
+ fill_pattern Pattern (not size) for page
+
+ NOTES
+ Page may not be part of active bitmap
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool set_page_bits(MARIA_HA *info, MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page, uint fill_pattern)
+{
+ pgcache_page_no_t bitmap_page;
+ uint offset_page, offset, tmp, org_tmp;
+ uchar *data;
+ DBUG_ENTER("set_page_bits");
+
+ bitmap_page= page - page % bitmap->pages_covered;
+ if (bitmap_page != bitmap->page &&
+ _ma_change_bitmap_page(info, bitmap, bitmap_page))
+ DBUG_RETURN(1);
+
+ /* Find page number from start of bitmap */
+ offset_page= (uint) (page - bitmap->page - 1);
+ /*
+ Mark place used by reading/writing 2 bytes at a time to handle
+ bitmaps in overlapping bytes
+ */
+ offset_page*= 3;
+ offset= offset_page & 7;
+ data= bitmap->map + offset_page / 8;
+ org_tmp= tmp= uint2korr(data);
+ tmp= (tmp & ~(7 << offset)) | (fill_pattern << offset);
+ if (tmp == org_tmp)
+ DBUG_RETURN(0); /* No changes */
+ int2store(data, tmp);
+
+ bitmap->changed= 1;
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
+ if (fill_pattern != 3 && fill_pattern != 7)
+ set_if_smaller(info->s->state.first_bitmap_with_space, bitmap_page);
+ /*
+ Note that if the condition above is false (page is full), and all pages of
+ this bitmap are now full, and that bitmap page was
+ first_bitmap_with_space, we don't modify first_bitmap_with_space, indeed
+ its value still tells us where to start our search for a bitmap with space
+ (which is for sure after this full one).
+ That does mean that first_bitmap_with_space is only a lower bound.
+ */
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Get bitmap pattern for a given page
+
+ SYNOPSIS
+ get_page_bits()
+ info Maria handler
+ bitmap Bitmap handler
+ page Page number
+
+ RETURN
+ 0-7 Bitmap pattern
+ ~0 Error (couldn't read page)
+*/
+
+uint _ma_bitmap_get_page_bits(MARIA_HA *info, MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page)
+{
+ pgcache_page_no_t bitmap_page;
+ uint offset_page, offset, tmp;
+ uchar *data;
+ DBUG_ENTER("_ma_bitmap_get_page_bits");
+
+ bitmap_page= page - page % bitmap->pages_covered;
+ if (bitmap_page != bitmap->page &&
+ _ma_change_bitmap_page(info, bitmap, bitmap_page))
+ DBUG_RETURN(~ (uint) 0);
+
+ /* Find page number from start of bitmap */
+ offset_page= (uint) (page - bitmap->page - 1);
+ /*
+ Mark place used by reading/writing 2 bytes at a time to handle
+ bitmaps in overlapping bytes
+ */
+ offset_page*= 3;
+ offset= offset_page & 7;
+ data= bitmap->map + offset_page / 8;
+ tmp= uint2korr(data);
+ DBUG_RETURN((tmp >> offset) & 7);
+}
+
+
+/*
+ Mark all pages in a region as free
+
+ SYNOPSIS
+ _ma_bitmap_reset_full_page_bits()
+ info Maria handler
+ bitmap Bitmap handler
+ page Start page
+ page_count Number of pages
+
+ NOTES
+ We assume that all pages in region is covered by same bitmap
+ One must have a lock on info->s->bitmap.bitmap_lock
+
+ RETURN
+ 0 ok
+ 1 Error (when reading bitmap)
+*/
+
+my_bool _ma_bitmap_reset_full_page_bits(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page,
+ uint page_count)
+{
+ ulonglong bitmap_page;
+ uint offset, bit_start, bit_count, tmp;
+ uchar *data;
+ DBUG_ENTER("_ma_bitmap_reset_full_page_bits");
+ DBUG_PRINT("enter", ("page: %lu page_count: %u", (ulong) page, page_count));
+ safe_mutex_assert_owner(&info->s->bitmap.bitmap_lock);
+
+ bitmap_page= page - page % bitmap->pages_covered;
+ DBUG_ASSERT(page != bitmap_page);
+
+ if (bitmap_page != bitmap->page &&
+ _ma_change_bitmap_page(info, bitmap, bitmap_page))
+ DBUG_RETURN(1);
+
+ /* Find page number from start of bitmap */
+ offset= (uint) (page - bitmap->page - 1);
+
+ /* Clear bits from 'page * 3' -> '(page + page_count) * 3' */
+ bit_start= offset * 3;
+ bit_count= page_count * 3;
+
+ data= bitmap->map + bit_start / 8;
+ offset= bit_start & 7;
+
+ tmp= (255 << offset); /* Bits to keep */
+ if (bit_count + offset < 8)
+ {
+ /* Only clear bits between 'offset' and 'offset+bit_count-1' */
+ tmp^= (255 << (offset + bit_count));
+ }
+ *data&= ~tmp;
+
+ if ((int) (bit_count-= (8 - offset)) > 0)
+ {
+ uint fill;
+ data++;
+ /*
+ -1 is here to avoid one 'if' statement and to let the following code
+ handle the last byte
+ */
+ if ((fill= (bit_count - 1) / 8))
+ {
+ bzero(data, fill);
+ data+= fill;
+ }
+ bit_count-= fill * 8; /* Bits left to clear */
+ tmp= (1 << bit_count) - 1;
+ *data&= ~tmp;
+ }
+ set_if_smaller(info->s->state.first_bitmap_with_space, bitmap_page);
+ bitmap->changed= 1;
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
+ DBUG_RETURN(0);
+}
+
+/*
+ Set all pages in a region as used
+
+ SYNOPSIS
+ _ma_bitmap_set_full_page_bits()
+ info Maria handler
+ bitmap Bitmap handler
+ page Start page
+ page_count Number of pages
+
+ NOTES
+ We assume that all pages in region is covered by same bitmap
+ One must have a lock on info->s->bitmap.bitmap_lock
+
+ RETURN
+ 0 ok
+ 1 Error (when reading bitmap)
+*/
+
+my_bool _ma_bitmap_set_full_page_bits(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page, uint page_count)
+{
+ ulonglong bitmap_page;
+ uint offset, bit_start, bit_count, tmp;
+ uchar *data;
+ DBUG_ENTER("_ma_bitmap_set_full_page_bits");
+ DBUG_PRINT("enter", ("page: %lu page_count: %u", (ulong) page, page_count));
+ safe_mutex_assert_owner(&info->s->bitmap.bitmap_lock);
+
+ bitmap_page= page - page % bitmap->pages_covered;
+ if (bitmap_page != bitmap->page &&
+ _ma_change_bitmap_page(info, bitmap, bitmap_page))
+ DBUG_RETURN(1);
+
+ /* Find page number from start of bitmap */
+ offset= (uint) (page - bitmap->page - 1);
+
+ /* Set bits from 'page * 3' -> '(page + page_count) * 3' */
+ bit_start= offset * 3;
+ bit_count= page_count * 3;
+
+ data= bitmap->map + bit_start / 8;
+ offset= bit_start & 7;
+
+ tmp= (255 << offset); /* Bits to keep */
+ if (bit_count + offset < 8)
+ {
+ /* Only set bits between 'offset' and 'offset+bit_count-1' */
+ tmp^= (255 << (offset + bit_count));
+ }
+ *data|= tmp;
+
+ if ((int) (bit_count-= (8 - offset)) > 0)
+ {
+ uint fill;
+ data++;
+ /*
+ -1 is here to avoid one 'if' statement and to let the following code
+ handle the last byte
+ */
+ if ((fill= (bit_count - 1) / 8))
+ {
+ bfill(data, fill, 255);
+ data+= fill;
+ }
+ bit_count-= fill * 8; /* Bits left to set */
+ tmp= (1 << bit_count) - 1;
+ *data|= tmp;
+ }
+ bitmap->changed= 1;
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief
+ Make a transition of MARIA_FILE_BITMAP::non_flushable.
+ If the bitmap becomes flushable, which requires that REDO-UNDO has been
+ logged and all bitmap pages touched by the thread have a correct
+ allocation, it unpins all bitmap pages, and if _ma_bitmap_flush_all() is
+ waiting (in practice it is a checkpoint), it wakes it up.
+ If the bitmap becomes or stays unflushable, the function merely records it
+ unless a concurrent _ma_bitmap_flush_all() is happening, in which case the
+ function first waits for the flush to be done.
+
+ @note
+ this sets info->non_flushable_state to 1 if we have incremented
+ bitmap->non_flushable and not yet decremented it.
+
+ @param share Table's share
+ @param non_flushable_inc Increment of MARIA_FILE_BITMAP::non_flushable
+ (-1 or +1).
+*/
+
+void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_FILE_BITMAP *bitmap;
+ DBUG_ENTER("_ma_bitmap_flushable");
+
+ /*
+ Not transactional tables are never automaticly flushed and needs no
+ protection
+ */
+ if (!share->now_transactional)
+ DBUG_VOID_RETURN;
+
+ bitmap= &share->bitmap;
+ if (non_flushable_inc == -1)
+ {
+ pthread_mutex_lock(&bitmap->bitmap_lock);
+ DBUG_ASSERT((int) bitmap->non_flushable > 0);
+ DBUG_ASSERT(info->non_flushable_state == 1);
+ info->non_flushable_state= 0;
+ if (--bitmap->non_flushable == 0)
+ {
+ /*
+ We unlock and unpin pages locked and pinned by other threads. It does
+ not seem to be an issue as all bitmap changes are serialized with
+ the bitmap's mutex.
+ */
+ _ma_bitmap_unpin_all(share);
+ if (unlikely(bitmap->flush_all_requested))
+ {
+ DBUG_PRINT("info", ("bitmap flushable waking up flusher"));
+ pthread_cond_broadcast(&bitmap->bitmap_cond);
+ }
+ }
+ DBUG_PRINT("info", ("bitmap->non_flushable: %u", bitmap->non_flushable));
+ pthread_mutex_unlock(&bitmap->bitmap_lock);
+ DBUG_VOID_RETURN;
+ }
+ DBUG_ASSERT(non_flushable_inc == 1);
+ DBUG_ASSERT(info->non_flushable_state == 0);
+ pthread_mutex_lock(&bitmap->bitmap_lock);
+ while (unlikely(bitmap->flush_all_requested))
+ {
+ /*
+ Some other thread is waiting for the bitmap to become
+ flushable. Not the moment to make the bitmap unflushable or more
+ unflushable; let's rather back off and wait. If we didn't do this, with
+ multiple writers, there may always be one thread causing the bitmap to
+ be unflushable and _ma_bitmap_flush_all() would wait for long.
+ There should not be a deadlock because if our thread increased
+ non_flushable (and thus _ma_bitmap_flush_all() is waiting for at least
+ our thread), it is not going to increase it more so is not going to come
+ here.
+ */
+ DBUG_PRINT("info", ("waiting for bitmap flusher"));
+ pthread_cond_wait(&bitmap->bitmap_cond, &bitmap->bitmap_lock);
+ }
+ bitmap->non_flushable++;
+ info->non_flushable_state= 1;
+ DBUG_PRINT("info", ("bitmap->non_flushable: %u", bitmap->non_flushable));
+ pthread_mutex_unlock(&bitmap->bitmap_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Correct bitmap pages to reflect the true allocation
+
+ SYNOPSIS
+ _ma_bitmap_release_unused()
+ info Maria handle
+ blocks Bitmap blocks
+
+ IMPLEMENTATION
+ If block->used & BLOCKUSED_TAIL is set:
+ If block->used & BLOCKUSED_USED is set, then the bits for the
+ corresponding page is set according to block->empty_space
+ If block->used & BLOCKUSED_USED is not set, then the bits for
+ the corresponding page is set to org_bitmap_value;
+
+ If block->used & BLOCKUSED_TAIL is not set:
+ if block->used is not set, the bits for the corresponding page are
+ cleared
+
+ For the first block (head block) the logic is same as for a tail block
+
+ Note that we may have 'filler blocks' that are used to split a block
+ in half; These can be recognized by that they have page_count == 0.
+
+ RETURN
+ 0 ok
+ 1 error (Couldn't write or read bitmap page)
+*/
+
+my_bool _ma_bitmap_release_unused(MARIA_HA *info, MARIA_BITMAP_BLOCKS *blocks)
+{
+ MARIA_BITMAP_BLOCK *block= blocks->block, *end= block + blocks->count;
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ uint bits, current_bitmap_value;
+ DBUG_ENTER("_ma_bitmap_release_unused");
+
+ /*
+ We can skip FULL_HEAD_PAGE (4) as the page was marked as 'full'
+ when we allocated space in the page
+ */
+ current_bitmap_value= FULL_HEAD_PAGE;
+
+ pthread_mutex_lock(&bitmap->bitmap_lock);
+
+ /* First handle head block */
+ if (block->used & BLOCKUSED_USED)
+ {
+ DBUG_PRINT("info", ("head page: %lu empty_space: %u",
+ (ulong) block->page, block->empty_space));
+ bits= _ma_free_size_to_head_pattern(bitmap, block->empty_space);
+ if (block->used & BLOCKUSED_USE_ORG_BITMAP)
+ current_bitmap_value= block->org_bitmap_value;
+ }
+ else
+ bits= block->org_bitmap_value;
+ if (bits != current_bitmap_value)
+ {
+ if (set_page_bits(info, bitmap, block->page, bits))
+ goto err;
+ }
+ else
+ {
+ DBUG_ASSERT(current_bitmap_value ==
+ _ma_bitmap_get_page_bits(info, bitmap, block->page));
+ }
+
+ /* Handle all full pages and tail pages (for head page and blob) */
+ for (block++; block < end; block++)
+ {
+ uint page_count;
+ if (!block->page_count)
+ continue; /* Skip 'filler blocks' */
+
+ page_count= block->page_count;
+ if (block->used & BLOCKUSED_TAIL)
+ {
+ current_bitmap_value= FULL_TAIL_PAGE;
+ /* The bitmap page is only one page */
+ page_count= 1;
+ if (block->used & BLOCKUSED_USED)
+ {
+ DBUG_PRINT("info", ("tail page: %lu empty_space: %u",
+ (ulong) block->page, block->empty_space));
+ bits= free_size_to_tail_pattern(bitmap, block->empty_space);
+ if (block->used & BLOCKUSED_USE_ORG_BITMAP)
+ current_bitmap_value= block->org_bitmap_value;
+ }
+ else
+ bits= block->org_bitmap_value;
+
+ /*
+ The page has all bits set; The following test is an optimization
+ to not set the bits to the same value as before.
+ */
+ if (bits != current_bitmap_value &&
+ set_page_bits(info, bitmap, block->page, bits))
+ goto err;
+ }
+ else if (!(block->used & BLOCKUSED_USED) &&
+ _ma_bitmap_reset_full_page_bits(info, bitmap,
+ block->page, page_count))
+ goto err;
+ }
+
+ /* This duplicates ma_bitmap_flushable(-1) except it already has mutex */
+ if (info->non_flushable_state)
+ {
+ DBUG_ASSERT(((int) (bitmap->non_flushable)) > 0);
+ info->non_flushable_state= 0;
+ if (--bitmap->non_flushable == 0)
+ {
+ _ma_bitmap_unpin_all(info->s);
+ if (unlikely(bitmap->flush_all_requested))
+ {
+ DBUG_PRINT("info", ("bitmap flushable waking up flusher"));
+ pthread_cond_broadcast(&bitmap->bitmap_cond);
+ }
+ }
+ }
+ DBUG_PRINT("info", ("bitmap->non_flushable: %u", bitmap->non_flushable));
+
+ pthread_mutex_unlock(&bitmap->bitmap_lock);
+ DBUG_RETURN(0);
+
+err:
+ pthread_mutex_unlock(&bitmap->bitmap_lock);
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Free full pages from bitmap and pagecache
+
+ SYNOPSIS
+ _ma_bitmap_free_full_pages()
+ info Maria handle
+ extents Extents (as stored on disk)
+ count Number of extents
+
+ IMPLEMENTATION
+ Mark all full pages (not tails) from extents as free, both in bitmap
+ and page cache.
+
+ RETURN
+ 0 ok
+ 1 error (Couldn't write or read bitmap page)
+*/
+
+my_bool _ma_bitmap_free_full_pages(MARIA_HA *info, const uchar *extents,
+ uint count)
+{
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ DBUG_ENTER("_ma_bitmap_free_full_pages");
+
+ pthread_mutex_lock(&bitmap->bitmap_lock);
+ for (; count--; extents+= ROW_EXTENT_SIZE)
+ {
+ pgcache_page_no_t page= uint5korr(extents);
+ uint page_count= (uint2korr(extents + ROW_EXTENT_PAGE_SIZE) &
+ ~START_EXTENT_BIT);
+ if (!(page_count & TAIL_BIT))
+ {
+ if (page == 0 && page_count == 0)
+ continue; /* Not used extent */
+ if (pagecache_delete_pages(info->s->pagecache, &info->dfile, page,
+ page_count, PAGECACHE_LOCK_WRITE, 1) ||
+ _ma_bitmap_reset_full_page_bits(info, bitmap, page, page_count))
+ {
+ pthread_mutex_unlock(&bitmap->bitmap_lock);
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ pthread_mutex_unlock(&bitmap->bitmap_lock);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Mark in the bitmap how much free space there is on a page
+
+ SYNOPSIS
+ _ma_bitmap_set()
+ info Maria handler
+ page Adress to page
+ head 1 if page is a head page, 0 if tail page
+ empty_space How much empty space there is on page
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+my_bool _ma_bitmap_set(MARIA_HA *info, pgcache_page_no_t page, my_bool head,
+ uint empty_space)
+{
+ MARIA_FILE_BITMAP *bitmap= &info->s->bitmap;
+ uint bits;
+ my_bool res;
+ DBUG_ENTER("_ma_bitmap_set");
+
+ pthread_mutex_lock(&info->s->bitmap.bitmap_lock);
+ bits= (head ?
+ _ma_free_size_to_head_pattern(bitmap, empty_space) :
+ free_size_to_tail_pattern(bitmap, empty_space));
+ res= set_page_bits(info, bitmap, page, bits);
+ pthread_mutex_unlock(&info->s->bitmap.bitmap_lock);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Check that bitmap pattern is correct for a page
+
+ NOTES
+ Used in maria_chk
+
+ SYNOPSIS
+ _ma_check_bitmap_data()
+ info Maria handler
+ page_type What kind of page this is
+ page Adress to page
+ empty_space Empty space on page
+ bitmap_pattern Store here the pattern that was in the bitmap for the
+ page. This is always updated.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+my_bool _ma_check_bitmap_data(MARIA_HA *info,
+ enum en_page_type page_type, pgcache_page_no_t page,
+ uint empty_space, uint *bitmap_pattern)
+{
+ uint bits;
+ switch (page_type) {
+ case UNALLOCATED_PAGE:
+ case MAX_PAGE_TYPE:
+ bits= 0;
+ break;
+ case HEAD_PAGE:
+ bits= _ma_free_size_to_head_pattern(&info->s->bitmap, empty_space);
+ break;
+ case TAIL_PAGE:
+ bits= free_size_to_tail_pattern(&info->s->bitmap, empty_space);
+ break;
+ case BLOB_PAGE:
+ bits= FULL_TAIL_PAGE;
+ break;
+ default:
+ bits= 0; /* to satisfy compiler */
+ DBUG_ASSERT(0);
+ }
+ return ((*bitmap_pattern= _ma_bitmap_get_page_bits(info, &info->s->bitmap,
+ page)) != bits);
+}
+
+
+/*
+ Check if the page type matches the one that we have in the bitmap
+
+ SYNOPSIS
+ _ma_check_if_right_bitmap_type()
+ info Maria handler
+ page_type What kind of page this is
+ page Adress to page
+ bitmap_pattern Store here the pattern that was in the bitmap for the
+ page. This is always updated.
+
+ NOTES
+ Used in maria_chk
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+my_bool _ma_check_if_right_bitmap_type(MARIA_HA *info,
+ enum en_page_type page_type,
+ pgcache_page_no_t page,
+ uint *bitmap_pattern)
+{
+ if ((*bitmap_pattern= _ma_bitmap_get_page_bits(info, &info->s->bitmap,
+ page)) > 7)
+ return 1; /* Couldn't read page */
+ switch (page_type) {
+ case HEAD_PAGE:
+ return *bitmap_pattern < 1 || *bitmap_pattern > 4;
+ case TAIL_PAGE:
+ return *bitmap_pattern < 5;
+ case BLOB_PAGE:
+ return *bitmap_pattern != 7;
+ default:
+ break;
+ }
+ DBUG_ASSERT(0);
+ return 1;
+}
+
+
+/**
+ @brief create the first bitmap page of a freshly created data file
+
+ @param share table's share
+
+ @return Operation status
+ @retval 0 OK
+ @retval !=0 Error
+*/
+
+int _ma_bitmap_create_first(MARIA_SHARE *share)
+{
+ uint block_size= share->bitmap.block_size;
+ File file= share->bitmap.file.file;
+ uchar marker[CRC_SIZE];
+
+ /*
+ Next write operation of the page will write correct CRC
+ if it is needed
+ */
+ int4store(marker, MARIA_NO_CRC_BITMAP_PAGE);
+
+ if (my_chsize(file, block_size - sizeof(marker),
+ 0, MYF(MY_WME)) ||
+ my_pwrite(file, marker, sizeof(marker),
+ block_size - sizeof(marker),
+ MYF(MY_NABP | MY_WME)))
+ return 1;
+ share->state.state.data_file_length= block_size;
+ _ma_bitmap_delete_all(share);
+ return 0;
+}
+
+
+/**
+ @brief Pagecache callback to get the TRANSLOG_ADDRESS to flush up to, when a
+ bitmap page needs to be flushed.
+
+ @param page Page's content
+ @param page_no Page's number (<offset>/<page length>)
+ @param data_ptr Callback data pointer (pointer to MARIA_SHARE)
+
+ @retval TRANSLOG_ADDRESS to flush up to.
+*/
+
+static my_bool
+flush_log_for_bitmap(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar *data_ptr __attribute__((unused)))
+{
+#ifndef DBUG_OFF
+ const MARIA_SHARE *share= (MARIA_SHARE*)data_ptr;
+#endif
+ DBUG_ENTER("flush_log_for_bitmap");
+ DBUG_ASSERT(share->now_transactional);
+ /*
+ WAL imposes that UNDOs reach disk before bitmap is flushed. We don't know
+ the LSN of the last UNDO about this bitmap page, so we flush whole log.
+ */
+ DBUG_RETURN(translog_flush(translog_get_horizon()));
+}
+
+
+/**
+ @brief Set callbacks for bitmap pages
+
+ @note
+ We don't use pagecache_file_init here, as we want to keep the
+ code readable
+*/
+
+void _ma_bitmap_set_pagecache_callbacks(PAGECACHE_FILE *file,
+ MARIA_SHARE *share)
+{
+ file->callback_data= (uchar*) share;
+ file->flush_log_callback= maria_flush_log_for_page_none;
+ file->write_fail= maria_page_write_failure;
+
+ if (share->temporary)
+ {
+ file->read_callback= &maria_page_crc_check_none;
+ file->write_callback= &maria_page_filler_set_none;
+ }
+ else
+ {
+ file->read_callback= &maria_page_crc_check_bitmap;
+ if (share->options & HA_OPTION_PAGE_CHECKSUM)
+ file->write_callback= &maria_page_crc_set_normal;
+ else
+ file->write_callback= &maria_page_filler_set_bitmap;
+ if (share->now_transactional)
+ file->flush_log_callback= flush_log_for_bitmap;
+ }
+}
+
+
+/**
+ Extends data file with zeroes and creates new bitmap pages into page cache.
+
+ Writes all bitmap pages in [from, to].
+
+ Non-bitmap pages of zeroes are correct as they are marked empty in
+ bitmaps. Bitmap pages will not be zeroes: they will get their CRC fixed when
+ flushed. And if there is a crash before flush (so they are zeroes at
+ restart), a REDO will re-create them in page cache.
+*/
+
+static my_bool
+_ma_bitmap_create_missing_into_pagecache(MARIA_SHARE *share,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t from,
+ pgcache_page_no_t to,
+ uchar *zeroes)
+{
+ pgcache_page_no_t i;
+ /*
+ We do not use my_chsize() because there can be a race between when it
+ reads the physical size and when it writes (assume data_file_length is 10,
+ physical length is 8 and two data pages are in cache, and here we do a
+ my_chsize: my_chsize sees physical length is 8, then the two data pages go
+ to disk then my_chsize writes from page 8 and so overwrites the two data
+ pages, wrongly).
+ We instead rely on the filesystem filling gaps with zeroes.
+ */
+ for (i= from; i <= to; i+= bitmap->pages_covered)
+ {
+ /**
+ No need to keep them pinned, they are new so flushable.
+ @todo but we may want to keep them pinned, as an optimization: if they
+ are not pinned they may go to disk before the data pages go (so, the
+ physical pages would be in non-ascending "sparse" order on disk), or the
+ filesystem may fill gaps with zeroes physically which is a waste of
+ time.
+ */
+ if (pagecache_write(share->pagecache,
+ &bitmap->file, i, 0,
+ zeroes, PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY, 0, LSN_IMPOSSIBLE))
+ goto err;
+ }
+ /*
+ Data pages after data_file_length are full of zeroes but that is allowed
+ as they are marked empty in the bitmap.
+ */
+ return FALSE;
+err:
+ return TRUE;
+}
+
+
+/**
+ Creates missing bitmaps when we extend the data file.
+
+ At run-time, when we need a new bitmap page we come here; and only one bitmap
+ page at a time is created.
+
+ In some recovery cases we insert at a large offset in the data file, way
+ beyond state.data_file_length, so can need to create more than one bitmap
+ page in one go. Known case is:
+ Start a transaction in Maria;
+ delete last row of very large table (with delete_row)
+ do a bulk insert
+ crash
+ Then UNDO_BULK_INSERT will truncate table files, and
+ UNDO_ROW_DELETE will want to put the row back to its original position,
+ extending the data file a lot: bitmap page*s* in the hole must be created,
+ or he table would look corrupted.
+
+ We need to log REDOs for bitmap creation, consider: we apply a REDO for a
+ data page, which creates the first data page covered by a new bitmap
+ not yet created. If the data page is flushed but the bitmap page is not and
+ there is a crash, re-execution of the REDO will complain about the zeroed
+ bitmap page (see it as corruption). Thus a REDO is needed to re-create the
+ bitmap.
+
+ @param info Maria handler
+ @param bitmap Bitmap handler
+ @param page Last bitmap page to create
+
+ @note When this function is called this must be true:
+ ((page + 1) * bitmap->block_size > info->s->state.state.data_file_length)
+
+*/
+
+static my_bool _ma_bitmap_create_missing(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page)
+{
+ MARIA_SHARE *share= info->s;
+ uint block_size= bitmap->block_size;
+ pgcache_page_no_t from, to;
+ my_off_t data_file_length= share->state.state.data_file_length;
+ DBUG_ENTER("_ma_bitmap_create_missing");
+
+ /* First (in offset order) bitmap page to create */
+ if (data_file_length < block_size)
+ goto err; /* corrupted, should have first bitmap page */
+
+ from= (data_file_length / block_size - 1) / bitmap->pages_covered + 1;
+ from*= bitmap->pages_covered;
+ /*
+ page>=from because:
+ (page + 1) * bs > dfl, and page == k * pc so:
+ (k * pc + 1) * bs > dfl; k * pc + 1 > dfl / bs; k * pc > dfl / bs - 1
+ k > (dfl / bs - 1) / pc; k >= (dfl / bs - 1) / pc + 1
+ k * pc >= ((dfl / bs - 1) / pc + 1) * pc == from.
+ */
+ DBUG_ASSERT(page >= from);
+
+ if (share->now_transactional)
+ {
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ page_store(log_data + FILEID_STORE_SIZE, from);
+ page_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, page);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ /*
+ We don't use info->trn so that this REDO is always executed even though
+ the UNDO does not reach disk due to crash. This is also consistent with
+ the fact that the new bitmap pages are not pinned.
+ */
+ if (translog_write_record(&lsn, LOGREC_REDO_BITMAP_NEW_PAGE,
+ &dummy_transaction_object, info,
+ (translog_size_t)sizeof(log_data),
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data, NULL))
+ goto err;
+ /*
+ No need to flush the log: the bitmap pages we are going to create will
+ flush it when they go to disk.
+ */
+ }
+
+ /*
+ Last bitmap page. It has special creation: will go to the page cache
+ only later as we are going to modify it very soon.
+ */
+ bzero(bitmap->map, bitmap->block_size);
+ bitmap->used_size= 0;
+#ifndef DBUG_OFF
+ memcpy(bitmap->map + bitmap->block_size, bitmap->map, bitmap->block_size);
+#endif
+
+ /* Last bitmap page to create before 'page' */
+ DBUG_ASSERT(page >= bitmap->pages_covered);
+ to= page - bitmap->pages_covered;
+ /*
+ In run-time situations, from>=to is always false, i.e. we always create
+ one bitmap at a time ('page').
+ */
+ if ((from <= to) &&
+ _ma_bitmap_create_missing_into_pagecache(share, bitmap, from, to,
+ bitmap->map))
+ goto err;
+
+ share->state.state.data_file_length= (page + 1) * bitmap->block_size;
+
+ DBUG_RETURN(FALSE);
+err:
+ DBUG_RETURN(TRUE);
+}
+
+
+my_bool _ma_apply_redo_bitmap_new_page(MARIA_HA *info,
+ LSN lsn __attribute__ ((unused)),
+ const uchar *header)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_FILE_BITMAP *bitmap= &share->bitmap;
+ my_bool error;
+ pgcache_page_no_t from, to, min_from;
+ DBUG_ENTER("_ma_apply_redo_bitmap_new_page");
+
+ from= page_korr(header);
+ to= page_korr(header + PAGE_STORE_SIZE);
+ DBUG_PRINT("info", ("from: %lu to: %lu", (ulong)from, (ulong)to));
+ if ((from > to) ||
+ (from % bitmap->pages_covered) != 0 ||
+ (to % bitmap->pages_covered) != 0)
+ {
+ error= TRUE; /* corrupted log record */
+ goto err;
+ }
+
+ min_from= (share->state.state.data_file_length / bitmap->block_size - 1) /
+ bitmap->pages_covered + 1;
+ min_from*= bitmap->pages_covered;
+ if (from < min_from)
+ {
+ DBUG_PRINT("info", ("overwrite bitmap pages from %lu", (ulong)min_from));
+ /*
+ We have to overwrite. It could be that there was a bitmap page in
+ memory, covering a data page which went to disk, then crash: the
+ bitmap page is now full of zeros and is ==min_from, we have to overwrite
+ it with correct checksum.
+ */
+ }
+ share->state.changed|= STATE_CHANGED;
+ bzero(info->buff, bitmap->block_size);
+ if (!(error=
+ _ma_bitmap_create_missing_into_pagecache(share, bitmap, from, to,
+ info->buff)))
+ share->state.state.data_file_length= (to + 1) * bitmap->block_size;
+
+err:
+ DBUG_RETURN(error);
+}
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
new file mode 100644
index 00000000000..6d66bb3389a
--- /dev/null
+++ b/storage/maria/ma_blockrec.c
@@ -0,0 +1,7173 @@
+/* Copyright (C) 2007-2008 Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Storage of records in block
+
+ Some clarifications about the abbrev used:
+
+ NULL fields -> Fields that may have contain a NULL value.
+ Not null fields -> Fields that may not contain a NULL value.
+ Critical fields -> Fields that can't be null and can't be dropped without
+ causing a table reorganization.
+
+
+ Maria will have a LSN at start of each page (excluding the bitmap pages)
+
+ The different page types that are in a data file are:
+
+ Bitmap pages Map of free pages in the next extent (8192 page size
+ gives us 256M of mapped pages / bitmap)
+ Head page Start of rows are stored on this page.
+ A rowid always points to a head page
+ Blob page This page is totally filled with data from one blob or by
+ a set of long VARCHAR/CHAR fields
+ Tail page This contains the last part from different rows, blobs
+ or varchar fields.
+
+ The data file starts with a bitmap page, followed by as many data
+ pages as the bitmap can cover. After this there is a new bitmap page
+ and more data pages etc.
+
+ For information about the bitmap page, see ma_bitmap.c
+
+ Structure of data and tail page:
+
+ The page has a row directory at end of page to allow us to do deletes
+ without having to reorganize the page. It also allows us to later store
+ some more bytes after each row to allow them to grow without having to move
+ around other rows.
+
+ Page header:
+
+ LSN 7 bytes Log position for last page change
+ PAGE_TYPE 1 uchar 1 for head / 2 for tail / 3 for blob
+ DIR_COUNT 1 uchar Number of row/tail entries on page
+ FREE_DIR_LINK 1 uchar Pointer to first free director entry or 255 if no
+ empty space 2 bytes Empty space on page
+
+ The most significant bit in PAGE_TYPE is set to 1 if the data on the page
+ can be compacted to get more space. (PAGE_CAN_BE_COMPACTED)
+
+ Row data
+
+ Row directory of NO entries, that consist of the following for each row
+ (in reverse order; i.e., first record is stored last):
+
+ Position 2 bytes Position of row on page
+ Length 2 bytes Length of entry
+
+ For Position and Length, the 1 most significant bit of the position and
+ the 1 most significant bit of the length could be used for some states of
+ the row (in other words, we should try to keep these reserved)
+
+ Position is 0 if the entry is not used. In this case length[0] points
+ to a previous free entry (255 if no previous entry) and length[1]
+ to the next free entry (or 255 if last free entry). This works because
+ the directory entry 255 can never be marked free (if the first directory
+ entry is freed, the directory is shrinked).
+
+ checksum 4 bytes Reserved for full page read testing and live backup.
+
+ ----------------
+
+ Structure of blob pages:
+
+ LSN 7 bytes Log position for last page change
+ PAGE_TYPE 1 uchar 3
+
+ data
+
+ -----------------
+
+ Row data structure:
+
+ Flag 1 uchar Marker of which header field exists
+ TRANSID 6 bytes TRANSID of changing transaction
+ (optional, added on insert and first
+ update/delete)
+ VER_PTR 7 bytes Pointer to older version in log
+ (undo record)
+ (optional, added after first
+ update/delete)
+ DELETE_TRANSID 6 bytes (optional). TRANSID of original row.
+ Added on delete.
+ Nulls_extended 1 uchar To allow us to add new DEFAULT NULL
+ fields (optional, added after first
+ change of row after alter table)
+ Number of ROW_EXTENT's 1-3 uchar Length encoded, optional
+ This is the number of extents the
+ row is split into
+ First row_extent 7 uchar Pointer to first row extent (optional)
+
+ Total length of length array 1-3 uchar Only used if we have
+ char/varchar/blob fields.
+ Row checksum 1 uchar Only if table created with checksums
+ Null_bits .. One bit for each NULL field (a field that may
+ have the value NULL)
+ Empty_bits .. One bit for each field that may be 'empty'.
+ (Both for null and not null fields).
+ This bit is 1 if the value for the field is
+ 0 or empty string.
+
+ field_offsets 2 byte/offset
+ For each 32'th field, there is one offset
+ that points to where the field information
+ starts in the block. This is to provide
+ fast access to later field in the row
+ when we only need to return a small
+ set of fields.
+ TODO: Implement this.
+
+ Things marked above as 'optional' will only be present if the
+ corresponding bit is set in 'Flag' field. Flag gives us a way to
+ get more space on a page when doing page compaction as we don't need
+ to store TRANSID that have committed before the smallest running
+ transaction we have in memory.
+
+ Data in the following order:
+ (Field order is precalculated when table is created)
+
+ Critical fixed length, not null, fields. (Note, these can't be dropped)
+ Fixed length, null fields
+
+ Length array, 1-4 uchar per field for all CHAR/VARCHAR/BLOB fields.
+ Number of bytes used in length array per entry is depending on max length
+ for field.
+
+ ROW_EXTENT's
+ CHAR data (space stripped)
+ VARCHAR data
+ BLOB data
+
+ Fields marked in null_bits or empty_bits are not stored in data part or
+ length array.
+
+ If row doesn't fit into the given block, then the first EXTENT will be
+ stored last on the row. This is done so that we don't break any field
+ data in the middle.
+
+ We first try to store the full row into one block. If that's not possible
+ we move out each big blob into their own extents. If this is not enough we
+ move out a concatenation of all varchars to their own extent.
+
+ Each blob and the concatenated char/varchar fields are stored the following
+ way:
+ - Store the parts in as many full-contiguous pages as possible.
+ - The last part, that doesn't fill a full page, is stored in tail page.
+
+ When doing an insert of a new row, we don't have to have
+ VER_PTR in the row. This will make rows that are not changed stored
+ efficiently. On update and delete we would add TRANSID (if it was an old
+ committed row) and VER_PTR to
+ the row. On row page compaction we can easily detect rows where
+ TRANSID was committed before the longest running transaction
+ started and we can then delete TRANSID and VER_PTR from the row to
+ gain more space.
+
+ If a row is deleted in Maria, we change TRANSID to the deleting
+ transaction's id, change VER_PTR to point to the undo record for the delete,
+ and add DELETE_TRANSID (the id of the transaction which last
+ inserted/updated the row before its deletion). DELETE_TRANSID allows an old
+ transaction to avoid reading the log to know if it can see the last version
+ before delete (in other words it reduces the probability of having to follow
+ VER_PTR). TODO: depending on a compilation option, evaluate the performance
+ impact of not storing DELETE_TRANSID (which would make the row smaller).
+
+ Description of the different parts:
+
+ Flag is coded as:
+
+ Description bit
+ TRANS_ID_exists 0
+ VER_PTR_exists 1
+ Row is deleted 2 (Means that DELETE_TRANSID exists)
+ Nulls_extended_exists 3
+ Row is split 7 This means that 'Number_of_row_extents' exists
+
+ Nulls_extended is the number of new DEFAULT NULL fields in the row
+ compared to the number of DEFAULT NULL fields when the first version
+ of the table was created. If Nulls_extended doesn't exist in the row,
+ we know it's 0 as this must be one of the original rows from when the
+ table was created first time. This coding allows us to add 255*8 =
+ 2048 new fields without requiring a full alter table.
+
+ Empty_bits is used to allow us to store 0, 0.0, empty string, empty
+ varstring and empty blob efficiently. (This is very good for data
+ warehousing where NULL's are often regarded as evil). Having this
+ bitmap also allows us to drop information of a field during a future
+ delete if field was deleted with ALTER TABLE DROP COLUMN. To be able
+ to handle DROP COLUMN, we must store in the index header the fields
+ that has been dropped. When unpacking a row we will ignore dropped
+ fields. When storing a row, we will mark a dropped field either with a
+ null in the null bit map or in the empty_bits and not store any data
+ for it.
+ TODO: Add code for handling dropped fields.
+
+
+ A ROW EXTENT is range of pages. One ROW_EXTENT is coded as:
+
+ START_PAGE 5 bytes
+ PAGE_COUNT 2 bytes. Bit 16 is set if this is a tail page.
+ Bit 15 is to set if this is start of a new
+ blob extent.
+
+ With 8K pages, we can cover 256M in one extent. This coding gives us a
+ maximum file size of 2^40*8192 = 8192 tera
+
+ As an example of ROW_EXTENT handling, assume a row with one integer
+ field (value 5), two big VARCHAR fields (size 250 and 8192*3), and 2
+ big BLOB fields that we have updated.
+
+ The record format for storing this into an empty file would be:
+
+ Page 1:
+
+ 00 00 00 00 00 00 00 LSN
+ 01 Only one row in page
+ FF No free dir entry
+ xx xx Empty space on page
+
+ 10 Flag: row split, VER_PTR exists
+ 01 00 00 00 00 00 TRANSID 1
+ 00 00 00 00 00 01 00 VER_PTR to first block in LOG file 1
+ 5 Number of row extents
+ 02 00 00 00 00 03 00 VARCHAR's are stored in full pages 2,3,4
+ 0 No null fields
+ 0 No empty fields
+ 05 00 00 00 00 00 80 Tail page for VARCHAR, rowid 0
+ 06 00 00 00 00 80 00 First blob, stored at page 6-133
+ 05 00 00 00 00 01 80 Tail of first blob (896 bytes) at page 5
+ 86 00 00 00 00 80 00 Second blob, stored at page 134-262
+ 05 00 00 00 00 02 80 Tail of second blob (896 bytes) at page 5
+ 05 00 5 integer
+ FA Length of first varchar field (size 250)
+ 00 60 Length of second varchar field (size 8192*3)
+ 00 60 10 First medium BLOB, 1M
+ 01 00 10 00 Second BLOB, 1M
+ xx xx xx xx xx xx Varchars are stored here until end of page
+
+ ..... until end of page
+
+ 09 00 F4 1F Start position 9, length 8180
+ xx xx xx xx Checksum
+
+ A data page is allowed to have a wrong CRC and header as long as it is
+ marked empty in the bitmap and its directory's count is 0.
+*/
+
+#include "maria_def.h"
+#include "ma_blockrec.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+#include "ma_recovery_util.h"
+#include <lf.h>
+
+/*
+ Struct for having a cursor over a set of extent.
+ This is used to loop over all extents for a row when reading
+ the row data. It's also used to store the tail positions for
+ a read row to be used by a later update/delete command.
+*/
+
+typedef struct st_maria_extent_cursor
+{
+ /*
+ Pointer to packed uchar array of extents for the row.
+ Format is described above in the header
+ */
+ uchar *extent;
+ /* Where data starts on page; Only for debugging */
+ uchar *data_start;
+ /* Position to all tails in the row. Updated when reading a row */
+ MARIA_RECORD_POS *tail_positions;
+ /* Current page */
+ pgcache_page_no_t page;
+ /* How many pages in the page region */
+ uint page_count;
+ /* What kind of lock to use for tail pages */
+ enum pagecache_page_lock lock_for_tail_pages;
+ /* Total number of extents (i.e., entries in the 'extent' slot) */
+ uint extent_count;
+ /* <> 0 if current extent is a tail page; Set while using cursor */
+ uint tail;
+ /* Position for tail on tail page */
+ uint tail_row_nr;
+ /*
+ == 1 if we are working on the first extent (i.e., the one that is stored in
+ the row header, not an extent that is stored as part of the row data).
+ */
+ my_bool first_extent;
+} MARIA_EXTENT_CURSOR;
+
+
+/**
+ @brief Structure for passing down info to write_hook_for_clr_end().
+ This hooks needs to know the variation of the live checksum caused by the
+ current operation to update state.checksum under log's mutex,
+ needs to know the transaction's previous undo_lsn to set
+ trn->undo_lsn under log mutex, and needs to know the type of UNDO being
+ undone now to modify state.records under log mutex.
+*/
+
+/** S:share,D:checksum_delta,E:expression,P:pointer_into_record,L:length */
+#define store_checksum_in_rec(S,D,E,P,L) do \
+ { \
+ D= 0; \
+ if ((S)->calc_checksum != NULL) \
+ { \
+ D= (E); \
+ ha_checksum_store(P, D); \
+ L+= HA_CHECKSUM_STORE_SIZE; \
+ } \
+ } while (0)
+
+static my_bool delete_tails(MARIA_HA *info, MARIA_RECORD_POS *tails);
+static my_bool delete_head_or_tail(MARIA_HA *info,
+ pgcache_page_no_t page, uint record_number,
+ my_bool head, my_bool from_update);
+#ifndef DBUG_OFF
+static void _ma_print_directory(uchar *buff, uint block_size);
+#endif
+static uchar *store_page_range(uchar *to, MARIA_BITMAP_BLOCK *block,
+ uint block_size, ulong length,
+ uint *tot_ranges);
+static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record,
+ LEX_CUSTRING *log_parts,
+ uint *log_parts_count);
+static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
+ const uchar *newrec,
+ LEX_CUSTRING *log_parts,
+ uint *log_parts_count);
+
+/****************************************************************************
+ Initialization
+****************************************************************************/
+
+/*
+ Initialize data needed for block structures
+*/
+
+
+/* Size of the different header elements for a row */
+
+static uchar header_sizes[]=
+{
+ TRANSID_SIZE,
+ VERPTR_SIZE,
+ TRANSID_SIZE, /* Delete transid */
+ 1 /* Null extends */
+};
+
+/*
+ Calculate array of all used headers
+
+ Used to speed up:
+
+ size= 1;
+ if (flag & 1)
+ size+= TRANSID_SIZE;
+ if (flag & 2)
+ size+= VERPTR_SIZE;
+ if (flag & 4)
+ size+= TRANSID_SIZE
+ if (flag & 8)
+ size+= 1;
+
+ NOTES
+ This is called only once at startup of Maria
+*/
+
+static uchar total_header_size[1 << array_elements(header_sizes)];
+#define PRECALC_HEADER_BITMASK (array_elements(total_header_size) -1)
+
+void _ma_init_block_record_data(void)
+{
+ uint i;
+ bzero(total_header_size, sizeof(total_header_size));
+ total_header_size[0]= FLAG_SIZE; /* Flag uchar */
+ for (i= 1; i < array_elements(total_header_size); i++)
+ {
+ uint size= FLAG_SIZE, j, bit;
+ for (j= 0; (bit= (1 << j)) <= i; j++)
+ {
+ if (i & bit)
+ size+= header_sizes[j];
+ }
+ total_header_size[i]= size;
+ }
+}
+
+
+my_bool _ma_once_init_block_record(MARIA_SHARE *share, File data_file)
+{
+
+ share->base.max_data_file_length=
+ (((ulonglong) 1 << ((share->base.rec_reflength-1)*8))-1) *
+ share->block_size;
+#if SIZEOF_OFF_T == 4
+ set_if_smaller(share->base.max_data_file_length, INT_MAX32);
+#endif
+ return _ma_bitmap_init(share, data_file);
+}
+
+
+my_bool _ma_once_end_block_record(MARIA_SHARE *share)
+{
+ int res= _ma_bitmap_end(share);
+ if (share->bitmap.file.file >= 0)
+ {
+ if (flush_pagecache_blocks(share->pagecache, &share->bitmap.file,
+ share->temporary ? FLUSH_IGNORE_CHANGED :
+ FLUSH_RELEASE))
+ res= 1;
+ /*
+ File must be synced as it is going out of the maria_open_list and so
+ becoming unknown to Checkpoint.
+ */
+ if (share->now_transactional &&
+ my_sync(share->bitmap.file.file, MYF(MY_WME)))
+ res= 1;
+ if (my_close(share->bitmap.file.file, MYF(MY_WME)))
+ res= 1;
+ /*
+ Trivial assignment to guard against multiple invocations
+ (May happen if file are closed but we want to keep the maria object
+ around a bit longer)
+ */
+ share->bitmap.file.file= -1;
+ }
+ if (share->id != 0)
+ {
+ /*
+ We de-assign the id even though index has not been flushed, this is ok
+ as close_lock serializes us with a Checkpoint looking at our share.
+ */
+ translog_deassign_id_from_share(share);
+ }
+ return res;
+}
+
+
+/* Init info->cur_row structure */
+
+my_bool _ma_init_block_record(MARIA_HA *info)
+{
+ MARIA_ROW *row= &info->cur_row, *new_row= &info->new_row;
+ MARIA_SHARE *share= info->s;
+ uint default_extents;
+ DBUG_ENTER("_ma_init_block_record");
+
+ if (!my_multi_malloc(MY_WME,
+ &row->empty_bits, share->base.pack_bytes,
+ &row->field_lengths,
+ share->base.max_field_lengths + 2,
+ &row->blob_lengths, sizeof(ulong) * share->base.blobs,
+ &row->null_field_lengths, (sizeof(uint) *
+ (share->base.fields -
+ share->base.blobs +
+ EXTRA_LENGTH_FIELDS)),
+ &row->tail_positions, (sizeof(MARIA_RECORD_POS) *
+ (share->base.blobs + 2)),
+ &new_row->empty_bits, share->base.pack_bytes,
+ &new_row->field_lengths,
+ share->base.max_field_lengths + 2,
+ &new_row->blob_lengths,
+ sizeof(ulong) * share->base.blobs,
+ &new_row->null_field_lengths, (sizeof(uint) *
+ (share->base.fields -
+ share->base.blobs +
+ EXTRA_LENGTH_FIELDS)),
+ &info->log_row_parts,
+ sizeof(*info->log_row_parts) *
+ (TRANSLOG_INTERNAL_PARTS + 3 +
+ share->base.fields + 3),
+ &info->update_field_data,
+ (share->base.fields * 4 +
+ share->base.max_field_lengths + 1 + 4),
+ NullS, 0))
+ DBUG_RETURN(1);
+ /* Skip over bytes used to store length of field length for logging */
+ row->field_lengths+= 2;
+ new_row->field_lengths+= 2;
+
+ /* Reserve some initial space to avoid mallocs during execution */
+ default_extents= (ELEMENTS_RESERVED_FOR_MAIN_PART + 1 +
+ (AVERAGE_BLOB_SIZE /
+ FULL_PAGE_SIZE(share->block_size) /
+ BLOB_SEGMENT_MIN_SIZE));
+
+ if (my_init_dynamic_array(&info->bitmap_blocks,
+ sizeof(MARIA_BITMAP_BLOCK), default_extents,
+ 64))
+ goto err;
+ info->cur_row.extents_buffer_length= default_extents * ROW_EXTENT_SIZE;
+ if (!(info->cur_row.extents= my_malloc(info->cur_row.extents_buffer_length,
+ MYF(MY_WME))))
+ goto err;
+
+ info->row_base_length= share->base_length;
+ info->row_flag= share->base.default_row_flag;
+
+ /*
+ We need to reserve 'EXTRA_LENGTH_FIELDS' number of parts in
+ null_field_lengths to allow splitting of rows in 'find_where_to_split_row'
+ */
+ row->null_field_lengths+= EXTRA_LENGTH_FIELDS;
+ new_row->null_field_lengths+= EXTRA_LENGTH_FIELDS;
+
+ DBUG_RETURN(0);
+
+err:
+ _ma_end_block_record(info);
+ DBUG_RETURN(1);
+}
+
+
+void _ma_end_block_record(MARIA_HA *info)
+{
+ DBUG_ENTER("_ma_end_block_record");
+ my_free((uchar*) info->cur_row.empty_bits, MYF(MY_ALLOW_ZERO_PTR));
+ delete_dynamic(&info->bitmap_blocks);
+ my_free((uchar*) info->cur_row.extents, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(info->blob_buff, MYF(MY_ALLOW_ZERO_PTR));
+ /*
+ The data file is closed, when needed, in ma_once_end_block_record().
+ The following protects us from doing an extra, not allowed, close
+ in maria_close()
+ */
+ info->dfile.file= -1;
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+ Helper functions
+****************************************************************************/
+
+/*
+ Return the next unused postion on the page after a directory entry.
+
+ SYNOPSIS
+ start_of_next_entry()
+ dir Directory entry to be used. This can not be the
+ the last entry on the page!
+
+ RETURN
+ # Position in page where next entry starts.
+ Everything between the '*dir' and this are free to be used.
+*/
+
+static inline uint start_of_next_entry(uchar *dir)
+{
+ uchar *prev;
+ /*
+ Find previous used entry. (There is always a previous entry as
+ the directory never starts with a deleted entry)
+ */
+ for (prev= dir - DIR_ENTRY_SIZE ;
+ prev[0] == 0 && prev[1] == 0 ;
+ prev-= DIR_ENTRY_SIZE)
+ {}
+ return (uint) uint2korr(prev);
+}
+
+
+/*
+ Return the offset where the previous entry ends (before on page)
+
+ SYNOPSIS
+ end_of_previous_entry()
+ dir Address for current directory entry
+ end Address to last directory entry
+
+ RETURN
+ # Position where previous entry ends (smallest address on page)
+ Everything between # and current entry are free to be used.
+*/
+
+
+static inline uint end_of_previous_entry(uchar *dir, uchar *end)
+{
+ uchar *pos;
+ for (pos= dir + DIR_ENTRY_SIZE ; pos < end ; pos+= DIR_ENTRY_SIZE)
+ {
+ uint offset;
+ if ((offset= uint2korr(pos)))
+ return offset + uint2korr(pos+2);
+ }
+ return PAGE_HEADER_SIZE;
+}
+
+
+#ifndef DBUG_OFF
+
+static void _ma_print_directory(uchar *buff, uint block_size)
+{
+ uint max_entry= (uint) ((uchar *) buff)[DIR_COUNT_OFFSET], row= 0;
+ uint end_of_prev_row= PAGE_HEADER_SIZE;
+ uchar *dir, *end;
+
+ dir= dir_entry_pos(buff, block_size, max_entry-1);
+ end= dir_entry_pos(buff, block_size, 0);
+
+ DBUG_LOCK_FILE;
+ fprintf(DBUG_FILE,"Directory dump (pos:length):\n");
+
+ for (row= 1; dir <= end ; end-= DIR_ENTRY_SIZE, row++)
+ {
+ uint offset= uint2korr(end);
+ uint length= uint2korr(end+2);
+ fprintf(DBUG_FILE, " %4u:%4u", offset, offset ? length : 0);
+ if (!(row % (80/12)))
+ fputc('\n', DBUG_FILE);
+ if (offset)
+ {
+ DBUG_ASSERT(offset >= end_of_prev_row);
+ end_of_prev_row= offset + length;
+ }
+ }
+ fputc('\n', DBUG_FILE);
+ fflush(DBUG_FILE);
+ DBUG_UNLOCK_FILE;
+}
+
+
+static void check_directory(uchar *buff, uint block_size, uint min_row_length)
+{
+ uchar *dir, *end;
+ uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
+ uint start_of_dir, deleted;
+ uchar free_entry, prev_free_entry;
+ uint end_of_prev_row= PAGE_HEADER_SIZE;
+
+ dir= dir_entry_pos(buff, block_size, max_entry-1);
+ start_of_dir= (uint) (dir - buff);
+ end= dir_entry_pos(buff, block_size, 0);
+ deleted= 0;
+
+ /* Ensure that all rows are in increasing order and no overlaps */
+ for (; dir <= end ; end-= DIR_ENTRY_SIZE)
+ {
+ uint offset= uint2korr(end);
+ uint length= uint2korr(end+2);
+ if (offset)
+ {
+ DBUG_ASSERT(offset >= end_of_prev_row);
+ DBUG_ASSERT(!length || length >= min_row_length);
+ end_of_prev_row= offset + length;
+ }
+ else
+ deleted++;
+ }
+ DBUG_ASSERT(end_of_prev_row <= start_of_dir);
+
+ /* check free links */
+ free_entry= buff[DIR_FREE_OFFSET];
+ prev_free_entry= END_OF_DIR_FREE_LIST;
+ while (free_entry != END_OF_DIR_FREE_LIST)
+ {
+ uchar *dir= dir_entry_pos(buff, block_size, free_entry);
+ DBUG_ASSERT(dir[0] == 0 && dir[1] == 0);
+ DBUG_ASSERT(dir[2] == prev_free_entry);
+ prev_free_entry= free_entry;
+ free_entry= dir[3];
+ deleted--;
+ }
+ DBUG_ASSERT(deleted == 0);
+}
+#else
+#define check_directory(A,B,C)
+#endif /* DBUG_OFF */
+
+
+/**
+ @brief Calculate if there is enough entries on the page
+*/
+
+my_bool enough_free_entries(uchar *buff, uint block_size, uint wanted_entries)
+{
+ uint entries= (uint) buff[DIR_COUNT_OFFSET];
+ uint needed_free_entries, free_entry;
+
+ if (entries + wanted_entries <= MAX_ROWS_PER_PAGE)
+ return 1;
+
+ /* Check if enough free entries in free list */
+ needed_free_entries= entries + wanted_entries - MAX_ROWS_PER_PAGE;
+
+ free_entry= (uint) buff[DIR_FREE_OFFSET];
+ while (free_entry != END_OF_DIR_FREE_LIST)
+ {
+ uchar *dir;
+ if (!--needed_free_entries)
+ return 1;
+ dir= dir_entry_pos(buff, block_size, free_entry);
+ free_entry= dir[3];
+ }
+ return 0; /* Not enough entries */
+}
+
+
+/**
+ @brief Extend a record area to fit a given size block
+
+ @fn extend_area_on_page()
+ @param info Handler if head page and 0 if tail page
+ @param buff Page buffer
+ @param dir Pointer to dir entry in buffer
+ @param rownr Row number we working on
+ @param block_size Block size of buffer
+ @param request_length How much data we want to put at [dir]
+ @param empty_space Total empty space in buffer
+ This is updated with length after dir
+ is allocated and current block freed
+
+ @implementation
+ The logic is as follows (same as in _ma_update_block_record())
+ - If new data fits in old block, use old block.
+ - Extend block with empty space before block. If enough, use it.
+ - Extend block with empty space after block. If enough, use it.
+ - Use _ma_compact_block_page() to get all empty space at dir.
+
+ @note
+ The given directory entry is set to rec length.
+ empty_space doesn't include the new directory entry
+
+
+ @return
+ @retval 0 ok
+ @retval ret_offset Pointer to store offset to found area
+ @retval ret_length Pointer to store length of found area
+ @retval [dir] rec_offset is store here too
+
+ @retval 1 error (wrong info in block)
+*/
+
+static my_bool extend_area_on_page(MARIA_HA *info,
+ uchar *buff, uchar *dir,
+ uint rownr, uint block_size,
+ uint request_length,
+ uint *empty_space, uint *ret_offset,
+ uint *ret_length)
+{
+ uint rec_offset, length;
+ uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
+ DBUG_ENTER("extend_area_on_page");
+
+ rec_offset= uint2korr(dir);
+ if (rec_offset)
+ {
+ /* Extending old row; Mark current space as 'free' */
+ length= uint2korr(dir + 2);
+ DBUG_PRINT("info", ("rec_offset: %u length: %u request_length: %u "
+ "empty_space: %u",
+ rec_offset, length, request_length, *empty_space));
+
+ *empty_space+= length;
+ }
+ else
+ {
+ /* Reusing free directory entry; Free it from the directory list */
+ if (dir[2] == END_OF_DIR_FREE_LIST)
+ buff[DIR_FREE_OFFSET]= dir[3];
+ else
+ {
+ uchar *prev_dir= dir_entry_pos(buff, block_size, (uint) dir[2]);
+ DBUG_ASSERT(uint2korr(prev_dir) == 0 && prev_dir[3] == (uchar) rownr);
+ prev_dir[3]= dir[3];
+ }
+ if (dir[3] != END_OF_DIR_FREE_LIST)
+ {
+ uchar *next_dir= dir_entry_pos(buff, block_size, (uint) dir[3]);
+ DBUG_ASSERT(uint2korr(next_dir) == 0 && next_dir[2] == (uchar) rownr);
+ next_dir[2]= dir[2];
+ }
+ rec_offset= start_of_next_entry(dir);
+ length= 0;
+ }
+ if (length < request_length)
+ {
+ uint old_rec_offset;
+ /*
+ New data did not fit in old position.
+ Find first possible position where to put new data.
+ */
+ old_rec_offset= rec_offset;
+ rec_offset= end_of_previous_entry(dir, buff + block_size -
+ PAGE_SUFFIX_SIZE);
+ length+= (uint) (old_rec_offset - rec_offset);
+ DBUG_ASSERT(old_rec_offset);
+ /*
+ 'length' is 0 if we are doing an insert into a not allocated block.
+ This can only happen during "REDO of INSERT" or "UNDO of DELETE."
+ */
+ if (length < request_length)
+ {
+ /*
+ Did not fit in current block + empty space. Extend with
+ empty space after block.
+ */
+ if (rownr == max_entry - 1)
+ {
+ /* Last entry; Everything is free between this and directory */
+ length= ((block_size - PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE * max_entry) -
+ rec_offset);
+ }
+ else
+ length= start_of_next_entry(dir) - rec_offset;
+ DBUG_ASSERT((int) length >= 0);
+ if (length < request_length)
+ {
+ /* Not enough continuous space, compact page to get more */
+ int2store(dir, rec_offset);
+ /* Reset length, as this may be a deleted block */
+ int2store(dir+2, 0);
+ _ma_compact_block_page(buff, block_size, rownr, 1,
+ info ? info->trn->min_read_from: 0,
+ info ? info->s->base.min_block_length : 0);
+ rec_offset= uint2korr(dir);
+ length= uint2korr(dir+2);
+ if (length < request_length)
+ {
+ DBUG_PRINT("error", ("Not enough space: "
+ "length: %u request_length: %u",
+ length, request_length));
+ my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */
+ DBUG_RETURN(1); /* Error in block */
+ }
+ *empty_space= length; /* All space is here */
+ }
+ }
+ }
+ int2store(dir, rec_offset);
+ int2store(dir + 2, length);
+ *ret_offset= rec_offset;
+ *ret_length= length;
+ check_directory(buff, block_size, info ? info->s->base.min_block_length : 0);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Copy not changed fields from 'from' to 'to'
+
+ @notes
+ Assumption is that most fields are not changed!
+ (Which is why we don't test if all bits are set for some bytes in bitmap)
+*/
+
+void copy_not_changed_fields(MARIA_HA *info, MY_BITMAP *changed_fields,
+ uchar *to, uchar *from)
+{
+ MARIA_COLUMNDEF *column, *end_column;
+ uchar *bitmap= (uchar*) changed_fields->bitmap;
+ MARIA_SHARE *share= info->s;
+ uint bit= 1;
+
+ for (column= share->columndef, end_column= column+ share->base.fields;
+ column < end_column; column++)
+ {
+ if (!(*bitmap & bit))
+ {
+ uint field_length= column->length;
+ if (column->type == FIELD_VARCHAR)
+ {
+ if (column->fill_length == 1)
+ field_length= (uint) from[column->offset] + 1;
+ else
+ field_length= uint2korr(from + column->offset) + 2;
+ }
+ memcpy(to + column->offset, from + column->offset, field_length);
+ }
+ if ((bit= (bit << 1)) == 256)
+ {
+ bitmap++;
+ bit= 1;
+ }
+ }
+}
+
+#ifdef NOT_YET_NEEDED
+/* Calculate empty space on a page */
+
+static uint empty_space_on_page(uchar *buff, uint block_size)
+{
+ enum en_page_type;
+ page_type= (enum en_page_type) (buff[PAGE_TYPE_OFFSET] &
+ ~(uchar) PAGE_CAN_BE_COMPACTED);
+ if (page_type == UNALLOCATED_PAGE)
+ return block_size;
+ if ((uint) page_type <= TAIL_PAGE)
+ return uint2korr(buff+EMPTY_SPACE_OFFSET);
+ return 0; /* Blob page */
+}
+#endif
+
+
+/*
+ @brief Ensure we have space for new directory entries
+
+ @fn make_space_for_directory()
+ @param buff Page buffer
+ @param block_size Block size for pages
+ @param max_entry Number of current entries in directory
+ @param count Number of new entries to be added to directory
+ @param first_dir First directory entry on page
+ @param empty_space Total empty space in buffer. It's updated
+ to reflect the new empty space
+ @param first_pos Store position to last data byte on page here
+
+ @note
+ This function is inline as the argument passing is the biggest
+ part of the function
+
+ @return
+ @retval 0 ok
+ @retval 1 error (No data on page, fatal error)
+*/
+
+static inline my_bool
+make_space_for_directory(MARIA_HA *info,
+ uchar *buff, uint block_size, uint max_entry,
+ uint count, uchar *first_dir, uint *empty_space,
+ uint *first_pos)
+{
+ uint length_needed= DIR_ENTRY_SIZE * count;
+
+ /*
+ The following is not true only in the case and UNDO is used to reinsert
+ a row on a previously not used page
+ */
+ if (likely(max_entry))
+ {
+ /* Check if there is place for the directory entry on the page */
+ *first_pos= uint2korr(first_dir) + uint2korr(first_dir + 2);
+
+ if ((uint) (first_dir - buff) < *first_pos + length_needed)
+ {
+ /* Create place for directory */
+ _ma_compact_block_page(buff, block_size, max_entry - 1, 0,
+ info ? info->trn->min_read_from : 0,
+ info ? info->s->base.min_block_length : 0);
+ *first_pos= (uint2korr(first_dir) + uint2korr(first_dir + 2));
+ *empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
+ if (*empty_space < length_needed)
+ {
+ /*
+ We should always have space, as we only come here for
+ UNDO of DELETE (in which case we know the row was on the
+ page before) or if the bitmap told us there was space on page
+ */
+ DBUG_ASSERT(0);
+ return(1);
+ }
+ }
+ }
+ else
+ *first_pos= PAGE_HEADER_SIZE;
+
+ /* Reduce directory entry size from free space size */
+ (*empty_space)-= length_needed;
+ buff[DIR_COUNT_OFFSET]= (uchar) (max_entry + count);
+ return(0);
+}
+
+
+/*
+ Find free position in directory
+
+ SYNOPSIS
+ find_free_position()
+ info Handler if head page and 0 otherwise
+ buff Page
+ block_size Size of page
+ res_rownr Store index to free position here
+ res_length Store length of found segment here
+ empty_space Store length of empty space on disk here. This is
+ all empty space, including the found block.
+
+ NOTES
+ If there is a free directory entry (entry with position == 0),
+ then use it and change it to be the size of the empty block
+ after the previous entry. This guarantees that all row entries
+ are stored on disk in inverse directory order, which makes life easier for
+ '_ma_compact_block_page()' and to know if there is free space after any
+ block.
+
+ If there is no free entry (entry with position == 0), then we create
+ a new one. If there is not space for the directory entry (because
+ the last block overlapps with the directory), we compact the page.
+
+ We will update the offset and the length of the found dir entry to
+ match the position and empty space found.
+
+ buff[EMPTY_SPACE_OFFSET] is NOT updated but left up to the caller
+
+ See start of file for description of how free directory entires are linked
+
+ RETURN
+ 0 Error (directory full or last block goes over directory)
+ # Pointer to directory entry on page
+*/
+
+static uchar *find_free_position(MARIA_HA *info,
+ uchar *buff, uint block_size, uint *res_rownr,
+ uint *res_length, uint *empty_space)
+{
+ uint max_entry, free_entry;
+ uint length, first_pos;
+ uchar *dir, *first_dir;
+ DBUG_ENTER("find_free_position");
+
+ max_entry= (uint) buff[DIR_COUNT_OFFSET];
+ free_entry= (uint) buff[DIR_FREE_OFFSET];
+ *empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
+
+ DBUG_PRINT("info", ("max_entry: %u free_entry: %u", max_entry, free_entry));
+
+ first_dir= dir_entry_pos(buff, block_size, max_entry - 1);
+
+ /* Search after first free position */
+ if (free_entry != END_OF_DIR_FREE_LIST)
+ {
+ if (free_entry >= max_entry)
+ DBUG_RETURN(0); /* Consistency error */
+ dir= dir_entry_pos(buff, block_size, free_entry);
+ DBUG_ASSERT(uint2korr(dir) == 0 && dir[2] == END_OF_DIR_FREE_LIST);
+ /* Relink free list */
+ if ((buff[DIR_FREE_OFFSET]= dir[3]) != END_OF_DIR_FREE_LIST)
+ {
+ uchar *next_entry= dir_entry_pos(buff, block_size, (uint) dir[3]);
+ DBUG_ASSERT((uint) next_entry[2] == free_entry &&
+ uint2korr(next_entry) == 0);
+ next_entry[2]= END_OF_DIR_FREE_LIST; /* Backlink */
+ }
+
+ first_pos= end_of_previous_entry(dir, buff + block_size -
+ PAGE_SUFFIX_SIZE);
+ length= start_of_next_entry(dir) - first_pos;
+ int2store(dir, first_pos); /* Update dir entry */
+ int2store(dir + 2, 0);
+ *res_rownr= free_entry;
+ *res_length= length;
+
+ check_directory(buff, block_size,
+ info ? info->s->base.min_block_length : 0);
+ DBUG_RETURN(dir);
+ }
+ /* No free places in dir; create a new one */
+
+ /* Check if there is place for the directory entry */
+ if (max_entry == MAX_ROWS_PER_PAGE)
+ DBUG_RETURN(0);
+
+ if (make_space_for_directory(info, buff, block_size, max_entry, 1,
+ first_dir, empty_space, &first_pos))
+ DBUG_RETURN(0);
+
+ dir= first_dir - DIR_ENTRY_SIZE;
+ length= (uint) (dir - buff - first_pos);
+ DBUG_ASSERT(length <= *empty_space);
+ int2store(dir, first_pos);
+ int2store(dir + 2, 0); /* Max length of region */
+ *res_rownr= max_entry;
+ *res_length= length;
+
+ check_directory(buff, block_size, info ? info->s->base.min_block_length : 0);
+ DBUG_RETURN(dir);
+}
+
+
+/**
+ @brief Enlarge page directory to hold more entries
+
+ @fn extend_directory()
+ @param info Handler if head page and 0 otherwise
+ @param buff Page buffer
+ @param block_size Block size
+ @param max_entry Number of directory entries on page
+ @param new_entry Position for new entry
+ @param empty_space Total empty space in buffer. It's updated
+ to reflect the new empty space
+
+ @note
+ This is only called on UNDO when we want to expand the directory
+ to be able to re-insert row in a given position
+
+ The new directory entry will be set to cover the maximum possible space
+
+ @return
+ @retval 0 ok
+ @retval 1 error (No data on page, fatal error)
+*/
+
+static my_bool extend_directory(MARIA_HA *info, uchar *buff, uint block_size,
+ uint max_entry, uint new_entry,
+ uint *empty_space)
+{
+ uint length, first_pos;
+ uchar *dir, *first_dir;
+ DBUG_ENTER("extend_directory");
+
+ /*
+ Note that in if max_entry is 0, then first_dir will point to
+ an illegal directory entry. This is ok, as in this case we will
+ not access anything through first_dir.
+ */
+ first_dir= dir_entry_pos(buff, block_size, max_entry) + DIR_ENTRY_SIZE;
+
+ if (make_space_for_directory(info, buff, block_size, max_entry,
+ new_entry - max_entry + 1,
+ first_dir, empty_space, &first_pos))
+ DBUG_RETURN(1);
+
+ /* Set the new directory entry to cover the max possible length */
+ dir= first_dir - DIR_ENTRY_SIZE * (new_entry - max_entry + 1);
+ length= (uint) (dir - buff - first_pos);
+ int2store(dir, first_pos);
+ int2store(dir+2, length);
+ *empty_space-= length;
+
+ if (new_entry-- > max_entry)
+ {
+ /* Link all row entries between new_entry and max_entry into free list */
+ uint free_entry= (uint) buff[DIR_FREE_OFFSET];
+ uint prev_entry= END_OF_DIR_FREE_LIST;
+ buff[DIR_FREE_OFFSET]= new_entry;
+ do
+ {
+ dir+= DIR_ENTRY_SIZE;
+ dir[0]= dir[1]= 0;
+ dir[2]= (uchar) prev_entry;
+ dir[3]= (uchar) new_entry-1;
+ prev_entry= new_entry;
+ } while (new_entry-- > max_entry);
+ if ((dir[3]= free_entry) != END_OF_DIR_FREE_LIST)
+ {
+ /* Relink next entry to point to newly freed entry */
+ uchar *next_entry= dir_entry_pos(buff, block_size, (uint) dir[3]);
+ DBUG_ASSERT(uint2korr(next_entry) == 0 &&
+ next_entry[2] == END_OF_DIR_FREE_LIST);
+ next_entry[2]= max_entry;
+ }
+ }
+
+ check_directory(buff, block_size,
+ info ? min(info->s->base.min_block_length, length) : 0);
+ DBUG_RETURN(0);
+}
+
+
+/****************************************************************************
+ Updating records
+****************************************************************************/
+
+/*
+ Calculate length of all the different field parts
+
+ SYNOPSIS
+ calc_record_size()
+ info Maria handler
+ record Row to store
+ row Store statistics about row here
+
+ NOTES
+ The statistics is used to find out how much space a row will need
+ and also where we can split a row when we need to split it into several
+ extents.
+*/
+
+static void calc_record_size(MARIA_HA *info, const uchar *record,
+ MARIA_ROW *row)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *field_length_data;
+ MARIA_COLUMNDEF *column, *end_column;
+ uint *null_field_lengths= row->null_field_lengths;
+ ulong *blob_lengths= row->blob_lengths;
+ DBUG_ENTER("calc_record_size");
+
+ row->normal_length= row->char_length= row->varchar_length=
+ row->blob_length= row->extents_count= 0;
+
+ /* Create empty bitmap and calculate length of each varlength/char field */
+ bzero(row->empty_bits, share->base.pack_bytes);
+ field_length_data= row->field_lengths;
+ for (column= share->columndef + share->base.fixed_not_null_fields,
+ end_column= share->columndef + share->base.fields;
+ column < end_column; column++, null_field_lengths++)
+ {
+ if ((record[column->null_pos] & column->null_bit))
+ {
+ if (column->type != FIELD_BLOB)
+ *null_field_lengths= 0;
+ else
+ *blob_lengths++= 0;
+ continue;
+ }
+ switch (column->type) {
+ case FIELD_CHECK:
+ case FIELD_NORMAL: /* Fixed length field */
+ case FIELD_ZERO:
+ DBUG_ASSERT(column->empty_bit == 0);
+ /* fall through */
+ case FIELD_SKIP_PRESPACE: /* Not packed */
+ row->normal_length+= column->length;
+ *null_field_lengths= column->length;
+ break;
+ case FIELD_SKIP_ZERO: /* Fixed length field */
+ if (memcmp(record+ column->offset, maria_zero_string,
+ column->length) == 0)
+ {
+ row->empty_bits[column->empty_pos] |= column->empty_bit;
+ *null_field_lengths= 0;
+ }
+ else
+ {
+ row->normal_length+= column->length;
+ *null_field_lengths= column->length;
+ }
+ break;
+ case FIELD_SKIP_ENDSPACE: /* CHAR */
+ {
+ const uchar *pos, *end;
+ for (pos= record + column->offset, end= pos + column->length;
+ end > pos && end[-1] == ' '; end--)
+ ;
+ if (pos == end) /* If empty string */
+ {
+ row->empty_bits[column->empty_pos]|= column->empty_bit;
+ *null_field_lengths= 0;
+ }
+ else
+ {
+ uint length= (uint) (end - pos);
+ if (column->length <= 255)
+ *field_length_data++= (uchar) length;
+ else
+ {
+ int2store(field_length_data, length);
+ field_length_data+= 2;
+ }
+ row->char_length+= length;
+ *null_field_lengths= length;
+ }
+ break;
+ }
+ case FIELD_VARCHAR:
+ {
+ uint length, field_length_data_length;
+ const uchar *field_pos= record + column->offset;
+
+ /* 256 is correct as this includes the length uchar */
+ field_length_data[0]= field_pos[0];
+ if (column->length <= 256)
+ {
+ length= (uint) (uchar) *field_pos;
+ field_length_data_length= 1;
+ }
+ else
+ {
+ length= uint2korr(field_pos);
+ field_length_data[1]= field_pos[1];
+ field_length_data_length= 2;
+ }
+ *null_field_lengths= length;
+ if (!length)
+ {
+ row->empty_bits[column->empty_pos]|= column->empty_bit;
+ break;
+ }
+ row->varchar_length+= length;
+ *null_field_lengths= length;
+ field_length_data+= field_length_data_length;
+ break;
+ }
+ case FIELD_BLOB:
+ {
+ const uchar *field_pos= record + column->offset;
+ uint size_length= column->length - portable_sizeof_char_ptr;
+ ulong blob_length= _ma_calc_blob_length(size_length, field_pos);
+
+ *blob_lengths++= blob_length;
+ if (!blob_length)
+ row->empty_bits[column->empty_pos]|= column->empty_bit;
+ else
+ {
+ row->blob_length+= blob_length;
+ memcpy(field_length_data, field_pos, size_length);
+ field_length_data+= size_length;
+ }
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ row->field_lengths_length= (uint) (field_length_data - row->field_lengths);
+ /*
+ - info->row_base_length is base information we must have on a page in first
+ extent:
+ - flag byte (1) + is_nulls_extended (0 | 1) + null_bytes + pack_bytes +
+ table_checksum (0 | 1)
+ - row->min_length is minimum amount of data we must store on
+ a page. bitmap code will ensure we get at list this much +
+ total number of extents and one extent information
+ - fixed_not_null_fields_length is length of fixed length fields that can't
+ be compacted
+ - head_length is the amount of data for the head page
+ (ie, all fields except blobs)
+ */
+ row->min_length= (info->row_base_length +
+ (share->base.max_field_lengths ?
+ size_to_store_key_length(row->field_lengths_length) :
+ 0));
+ row->head_length= (row->min_length +
+ share->base.fixed_not_null_fields_length +
+ row->field_lengths_length +
+ row->normal_length +
+ row->char_length + row->varchar_length);
+ row->total_length= (row->head_length + row->blob_length);
+ if (row->total_length < share->base.min_block_length)
+ row->total_length= share->base.min_block_length;
+ DBUG_PRINT("exit", ("head_length: %lu total_length: %lu",
+ (ulong) row->head_length, (ulong) row->total_length));
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Compact page by removing all space between rows
+
+ Moves up all rows to start of page. Moves blocks that are directly after
+ each other with one memmove.
+
+ @note if rownr is the last row in the page, and extend_block is false,
+ caller has to make sure to update bitmap page afterwards to reflect freed
+ space.
+
+ @param buff Page to compact
+ @param block_size Size of page
+ @param rownr Put empty data after this row
+ @param extend_block If 1, extend the block at 'rownr' to cover the
+ whole block.
+ @param min_read_from If <> 0, remove all trid's that are less than this
+*/
+
+void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
+ my_bool extend_block, TrID min_read_from,
+ uint min_row_length)
+{
+ uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
+ uint page_pos, next_free_pos, start_of_found_block, diff, end_of_found_block;
+ uint freed_size= 0;
+ uchar *dir, *end;
+ DBUG_ENTER("_ma_compact_block_page");
+ DBUG_PRINT("enter", ("rownr: %u", rownr));
+ DBUG_ASSERT(max_entry > 0 &&
+ max_entry < (block_size - PAGE_HEADER_SIZE -
+ PAGE_SUFFIX_SIZE) / DIR_ENTRY_SIZE);
+
+ /* Move all entries before and including rownr up to start of page */
+ dir= dir_entry_pos(buff, block_size, rownr);
+ end= dir_entry_pos(buff, block_size, 0);
+ page_pos= next_free_pos= start_of_found_block= PAGE_HEADER_SIZE;
+ diff= 0;
+ for (; dir <= end ; end-= DIR_ENTRY_SIZE)
+ {
+ uint offset= uint2korr(end);
+
+ if (offset)
+ {
+ uint row_length= uint2korr(end + 2);
+ DBUG_ASSERT(offset >= page_pos);
+ DBUG_ASSERT(buff + offset + row_length <= dir);
+ DBUG_ASSERT(row_length >= min_row_length || row_length == 0);
+
+ /* Row length can be zero if row is to be deleted */
+ if (min_read_from && row_length && (buff[offset] & ROW_FLAG_TRANSID))
+ {
+ TrID transid= transid_korr(buff+offset+1);
+ if (transid < min_read_from)
+ {
+ /* Remove transid from row by moving the start point of the row up */
+ buff[offset + TRANSID_SIZE]= buff[offset] & ~ROW_FLAG_TRANSID;
+ offset+= TRANSID_SIZE;
+ freed_size+= TRANSID_SIZE;
+ row_length-= TRANSID_SIZE;
+ int2store(end+2, row_length);
+ }
+ }
+
+ if (offset != next_free_pos)
+ {
+ uint length= (next_free_pos - start_of_found_block);
+ /*
+ There was empty space before this and prev block
+ Check if we have to move previous block up to page start
+ */
+ if (page_pos != start_of_found_block)
+ {
+ /* move up previous block */
+ memmove(buff + page_pos, buff + start_of_found_block, length);
+ }
+ page_pos+= length;
+ /* next continuous block starts here */
+ start_of_found_block= offset;
+ diff= offset - page_pos;
+ }
+ int2store(end, offset - diff); /* correct current pos */
+ next_free_pos= offset + row_length;
+
+ if (unlikely(row_length < min_row_length) && row_length)
+ {
+ /*
+ This can only happen in the case we compacted transid and
+ the row become 'too short'
+
+ Move the current row down to it's right place and extend it
+ with 0.
+ */
+ uint row_diff= min_row_length - row_length;
+ uint length= (next_free_pos - start_of_found_block);
+
+ DBUG_ASSERT(page_pos != start_of_found_block);
+ bmove(buff + page_pos, buff + start_of_found_block, length);
+ bzero(buff+ page_pos + length, row_diff);
+ page_pos+= min_row_length;
+ int2store(end+2, min_row_length);
+ freed_size-= row_diff;
+ next_free_pos= start_of_found_block= page_pos;
+ diff= 0;
+ }
+ }
+ }
+ if (page_pos != start_of_found_block)
+ {
+ uint length= (next_free_pos - start_of_found_block);
+ memmove(buff + page_pos, buff + start_of_found_block, length);
+ }
+ start_of_found_block= uint2korr(dir);
+
+ if (rownr != max_entry - 1)
+ {
+ /* Move all entries after rownr to end of page */
+ uint rownr_length;
+ next_free_pos= end_of_found_block= page_pos=
+ block_size - DIR_ENTRY_SIZE * max_entry - PAGE_SUFFIX_SIZE;
+ diff= 0;
+ /* End points to entry before 'rownr' */
+ for (dir= buff + end_of_found_block ; dir <= end ; dir+= DIR_ENTRY_SIZE)
+ {
+ uint offset= uint2korr(dir);
+ uint row_length;
+ uint row_end;
+ if (!offset)
+ continue;
+ row_length= uint2korr(dir + 2);
+ row_end= offset + row_length;
+ DBUG_ASSERT(offset >= start_of_found_block &&
+ row_end <= next_free_pos && row_length >= min_row_length);
+
+ if (min_read_from && (buff[offset] & ROW_FLAG_TRANSID))
+ {
+ TrID transid= transid_korr(buff + offset+1);
+ if (transid < min_read_from)
+ {
+ /* Remove transid from row */
+ buff[offset + TRANSID_SIZE]= buff[offset] & ~ROW_FLAG_TRANSID;
+ offset+= TRANSID_SIZE;
+ row_length-= TRANSID_SIZE;
+ int2store(dir+2, row_length);
+ }
+ if (unlikely(row_length < min_row_length))
+ {
+ /*
+ This can only happen in the case we compacted transid and
+ the row become 'too short'
+ */
+ uint row_diff= min_row_length - row_length;
+ if (next_free_pos < row_end + row_diff)
+ {
+ /*
+ Not enough space for extending next block with enough
+ end 0's. Move current data down to get place for them
+ */
+ uint move_down= row_diff - (next_free_pos - row_end);
+ bmove(buff + offset - move_down, buff + offset, row_length);
+ offset-= move_down;
+ }
+ /*
+ Extend the next block with 0, which will be part of current
+ row when the blocks are joined together later
+ */
+ bzero(buff + next_free_pos - row_diff, row_diff);
+ next_free_pos-= row_diff;
+ int2store(dir+2, min_row_length);
+ }
+ row_end= offset + row_length;
+ }
+
+ if (row_end != next_free_pos)
+ {
+ uint length= (end_of_found_block - next_free_pos);
+ if (page_pos != end_of_found_block)
+ {
+ /* move next block down */
+ memmove(buff + page_pos - length, buff + next_free_pos, length);
+ }
+ page_pos-= length;
+ /* next continuous block starts here */
+ end_of_found_block= row_end;
+ diff= page_pos - row_end;
+ }
+ int2store(dir, offset + diff); /* correct current pos */
+ next_free_pos= offset;
+ }
+
+ if (page_pos != end_of_found_block)
+ {
+ uint length= (end_of_found_block - next_free_pos);
+ memmove(buff + page_pos - length, buff + next_free_pos, length);
+ next_free_pos= page_pos- length;
+ }
+ /* Extend rownr block to cover hole */
+ rownr_length= next_free_pos - start_of_found_block;
+ int2store(dir+2, rownr_length);
+ DBUG_ASSERT(rownr_length >= min_row_length);
+ }
+ else
+ {
+ if (extend_block)
+ {
+ /* Extend last block to cover whole page */
+ uint length= ((uint) (dir - buff) - start_of_found_block);
+ int2store(dir+2, length);
+ DBUG_ASSERT(length >= min_row_length);
+ }
+ else
+ {
+ /* Add length gained from freed transaction id's to this page */
+ uint length= uint2korr(buff+ EMPTY_SPACE_OFFSET) + freed_size;
+ int2store(buff + EMPTY_SPACE_OFFSET, length);
+ }
+ buff[PAGE_TYPE_OFFSET]&= ~(uchar) PAGE_CAN_BE_COMPACTED;
+ }
+ check_directory(buff, block_size, min_row_length);
+ DBUG_EXECUTE("directory", _ma_print_directory(buff, block_size););
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Create an empty tail or head page
+
+ SYNOPSIS
+ make_empty_page()
+ buff Page buffer
+ block_size Block size
+ page_type HEAD_PAGE or TAIL_PAGE
+ create_dir_entry TRUE of we should create a directory entry
+
+ NOTES
+ EMPTY_SPACE is not updated
+*/
+
+static void make_empty_page(MARIA_HA *info, uchar *buff, uint page_type,
+ my_bool create_dir_entry)
+{
+ uint block_size= info->s->block_size;
+ DBUG_ENTER("make_empty_page");
+
+ bzero(buff, PAGE_HEADER_SIZE);
+
+#if !defined(DONT_ZERO_PAGE_BLOCKS) || defined(HAVE_purify)
+ /*
+ We zero the rest of the block to avoid getting old memory information
+ to disk and to allow the file to be compressed better if archived.
+ The code does not assume the block is zeroed.
+ */
+ if (page_type != BLOB_PAGE)
+ bzero(buff+ PAGE_HEADER_SIZE, block_size - PAGE_HEADER_SIZE);
+#endif
+ buff[PAGE_TYPE_OFFSET]= (uchar) page_type;
+ buff[DIR_COUNT_OFFSET]= (int) create_dir_entry;
+ buff[DIR_FREE_OFFSET]= END_OF_DIR_FREE_LIST;
+ if (create_dir_entry)
+ {
+ /* Create directory entry to point to start of page with size 0 */
+ buff+= block_size - PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE;
+ int2store(buff, PAGE_HEADER_SIZE);
+ int2store(buff+2, 0);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Read or initialize new head or tail page
+
+ SYNOPSIS
+ get_head_or_tail_page()
+ info Maria handler
+ block Block to read
+ buff Suggest this buffer to key cache
+ length Minimum space needed
+ page_type HEAD_PAGE || TAIL_PAGE
+ res Store result position here
+
+ NOTES
+ We don't decremented buff[EMPTY_SPACE_OFFSET] with the allocated data
+ as we don't know how much data the caller will actually use.
+
+ res->empty_space is set to length of empty space
+
+ RETURN
+ 0 ok All slots in 'res' are updated
+ 1 error my_errno is set
+*/
+
+struct st_row_pos_info
+{
+ uchar *buff; /* page buffer */
+ uchar *data; /* Place for data */
+ uchar *dir; /* Directory */
+ uint length; /* Length for data */
+ uint rownr; /* Offset in directory */
+ uint empty_space; /* Space left on page */
+};
+
+
+static my_bool get_head_or_tail_page(MARIA_HA *info,
+ MARIA_BITMAP_BLOCK *block,
+ uchar *buff, uint length, uint page_type,
+ enum pagecache_page_lock lock,
+ struct st_row_pos_info *res)
+{
+ uint block_size;
+ MARIA_PINNED_PAGE page_link;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("get_head_or_tail_page");
+ DBUG_PRINT("enter", ("length: %u", length));
+
+ block_size= share->block_size;
+ if (block->org_bitmap_value == 0) /* Empty block */
+ {
+ /* New page */
+ make_empty_page(info, buff, page_type, 1);
+ res->buff= buff;
+ res->empty_space= res->length= (block_size - PAGE_OVERHEAD_SIZE);
+ res->data= (buff + PAGE_HEADER_SIZE);
+ res->dir= res->data + res->length;
+ res->rownr= 0;
+ DBUG_ASSERT(length <= res->length);
+ }
+ else
+ {
+ uchar *dir;
+ /* Read old page */
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ res->buff= pagecache_read(share->pagecache, &info->dfile,
+ block->page, 0, 0, share->page_type,
+ lock, &page_link.link);
+ page_link.changed= res->buff != 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ if (!page_link.changed)
+ goto crashed;
+
+ DBUG_ASSERT((res->buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type);
+ if (!(dir= find_free_position(page_type == HEAD_PAGE ? info : 0,
+ res->buff, block_size, &res->rownr,
+ &res->length, &res->empty_space)))
+ goto crashed;
+
+ if (res->length < length)
+ {
+ if (res->empty_space + res->length >= length)
+ {
+ _ma_compact_block_page(res->buff, block_size, res->rownr, 1,
+ (page_type == HEAD_PAGE ?
+ info->trn->min_read_from : 0),
+ (page_type == HEAD_PAGE ?
+ share->base.min_block_length :
+ 0));
+ /* All empty space are now after current position */
+ dir= dir_entry_pos(res->buff, block_size, res->rownr);
+ res->length= res->empty_space= uint2korr(dir+2);
+ }
+ if (res->length < length)
+ {
+ DBUG_PRINT("error", ("length: %u res->length: %u empty_space: %u",
+ length, res->length, res->empty_space));
+ goto crashed; /* Wrong bitmap information */
+ }
+ }
+ res->dir= dir;
+ res->data= res->buff + uint2korr(dir);
+ }
+ DBUG_RETURN(0);
+
+crashed:
+ my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */
+ DBUG_RETURN(1);
+}
+
+
+/*
+ @brief Create room for a head or tail row on a given page at given position
+
+ @fn get_rowpos_in_head_or_tail_page()
+ @param info Maria handler
+ @param block Block to read
+ @param buff Suggest this buffer to key cache
+ @param length Minimum space needed
+ @param page_type HEAD_PAGE || TAIL_PAGE
+ @param rownr Rownr to use
+ @param res Store result position here
+
+ @note
+ This is essential same as get_head_or_tail_page, with the difference
+ that the caller species at what position the row should be put.
+ This is used when restoring a row to it's original position as
+ part of UNDO DELETE or UNDO UPDATE
+
+ @return
+ @retval 0 ok All slots in 'res' are updated
+ @retval 1 error my_errno is set
+*/
+
+static my_bool get_rowpos_in_head_or_tail_page(MARIA_HA *info,
+ MARIA_BITMAP_BLOCK *block,
+ uchar *buff, uint length,
+ uint page_type,
+ enum pagecache_page_lock lock,
+ uint rownr,
+ struct st_row_pos_info *res)
+{
+ MARIA_PINNED_PAGE page_link;
+ MARIA_SHARE *share= info->s;
+ uchar *dir;
+ uint block_size= share->block_size;
+ uint max_entry, max_length, rec_offset;
+ DBUG_ENTER("get_rowpos_in_head_or_tail_page");
+
+ if (block->org_bitmap_value == 0) /* Empty block */
+ {
+ /* New page */
+ make_empty_page(info, buff, page_type, 0);
+ res->empty_space= block_size - PAGE_HEADER_SIZE - PAGE_SUFFIX_SIZE;
+ }
+ else
+ {
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ buff= pagecache_read(share->pagecache, &info->dfile,
+ block->page, 0, 0, share->page_type,
+ lock, &page_link.link);
+ page_link.changed= buff != 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ if (!page_link.changed) /* Read error */
+ goto err;
+ DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) ==
+ (uchar) page_type);
+ if ((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) != (uchar) page_type)
+ goto err;
+ res->empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
+ }
+
+ max_entry= (uint) buff[DIR_COUNT_OFFSET];
+ if (max_entry <= rownr)
+ {
+ if (extend_directory(page_type == HEAD_PAGE ? info : 0, buff, block_size,
+ max_entry, rownr, &res->empty_space))
+ goto err;
+ }
+
+ dir= dir_entry_pos(buff, block_size, rownr);
+#ifdef SANITY_CHECKS
+ /* Tail's should always be unused */
+ if (page_type == TAIL_PAGE && max_entry > rownr &&
+ (dir[0] != 0 || dir[1] != 0))
+ {
+ DBUG_ASSERT(0);
+ goto err;
+ }
+#endif
+
+ if (extend_area_on_page(page_type == HEAD_PAGE ? info : 0, buff, dir,
+ rownr, block_size, length,
+ &res->empty_space, &rec_offset, &max_length))
+ goto err;
+
+ res->buff= buff;
+ res->rownr= rownr;
+ res->dir= dir;
+ res->data= buff + rec_offset;
+ res->length= length;
+ DBUG_RETURN(0);
+
+err:
+ my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Write tail for head data or blob
+
+ SYNOPSIS
+ write_tail()
+ info Maria handler
+ block Block to tail page
+ row_part Data to write to page
+ length Length of data
+
+ NOTES
+ block->page_count is updated to the directory offset for the tail
+ so that we can store the position in the row extent information
+
+ RETURN
+ 0 ok
+ block->page_count is set to point (dir entry + TAIL_BIT)
+
+ 1 error; In this case my_errno is set to the error
+*/
+
+static my_bool write_tail(MARIA_HA *info,
+ MARIA_BITMAP_BLOCK *block,
+ uchar *row_part, uint org_length)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_PINNED_PAGE page_link;
+ uint block_size= share->block_size, empty_space, length= org_length;
+ struct st_row_pos_info row_pos;
+ my_off_t position;
+ my_bool res, block_is_read;
+ DBUG_ENTER("write_tail");
+ DBUG_PRINT("enter", ("page: %lu length: %u",
+ (ulong) block->page, length));
+
+ info->keyread_buff_used= 1;
+ /*
+ Don't allocate smaller block than MIN_TAIL_SIZE (we want to give rows
+ some place to grow in the future)
+ */
+ if (length < MIN_TAIL_SIZE)
+ length= MIN_TAIL_SIZE;
+
+ if (block->page_count == TAIL_PAGE_COUNT_MARKER)
+ {
+ /*
+ Create new tail
+ page will be pinned & locked by get_head_or_tail_page
+ */
+ if (get_head_or_tail_page(info, block, info->keyread_buff, length,
+ TAIL_PAGE, PAGECACHE_LOCK_WRITE,
+ &row_pos))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ /* Write tail on predefined row position */
+ if (get_rowpos_in_head_or_tail_page(info, block, info->keyread_buff,
+ length, TAIL_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ block->page_count & ~TAIL_BIT,
+ &row_pos))
+ DBUG_RETURN(1);
+ }
+ DBUG_PRINT("info", ("tailid: %lu (%lu:%u)",
+ (ulong) ma_recordpos(block->page, row_pos.rownr),
+ (ulong) block->page, row_pos.rownr));
+
+ block_is_read= block->org_bitmap_value != 0;
+
+ memcpy(row_pos.data, row_part, org_length);
+
+ if (share->now_transactional)
+ {
+ /* Log changes in tail block */
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ LSN lsn;
+
+ /*
+ Log REDO changes of tail page
+ Note that we have to log length, not org_length, to be sure that
+ REDO, which doesn't use write_tail, also creates a block of at least
+ MIN_TAIL_SIZE
+ */
+ page_store(log_data + FILEID_STORE_SIZE, block->page);
+ dirpos_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE,
+ row_pos.rownr);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= row_pos.data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= length;
+ if (translog_write_record(&lsn,
+ (block_is_read ? LOGREC_REDO_INSERT_ROW_TAIL :
+ LOGREC_REDO_NEW_ROW_TAIL),
+ info->trn, info,
+ (translog_size_t) (sizeof(log_data) + length),
+ TRANSLOG_INTERNAL_PARTS + 2, log_array,
+ log_data, NULL))
+ DBUG_RETURN(1);
+ }
+
+ int2store(row_pos.dir + 2, length);
+ empty_space= row_pos.empty_space - length;
+ int2store(row_pos.buff + EMPTY_SPACE_OFFSET, empty_space);
+ block->page_count= row_pos.rownr + TAIL_BIT;
+ /*
+ If there is less directory entries free than number of possible tails
+ we can write for a row, we mark the page full to ensure that we don't
+ during _ma_bitmap_find_place() allocate more entries on the tail page
+ than it can hold
+ */
+ block->empty_space= (enough_free_entries(row_pos.buff, share->block_size,
+ 1 + share->base.blobs) ?
+ empty_space : 0);
+ block->used= BLOCKUSED_USED | BLOCKUSED_TAIL;
+
+ /* Increase data file size, if extended */
+ position= (my_off_t) block->page * block_size;
+ if (share->state.state.data_file_length <= position)
+ {
+ /*
+ We are modifying a state member before writing the UNDO; this is a WAL
+ violation. But for data_file_length this is ok, as long as we change
+ data_file_length after writing any log record (FILE_ID/REDO/UNDO) (see
+ collect_tables()).
+ */
+ _ma_set_share_data_file_length(share, position + block_size);
+ }
+
+ if (block_is_read)
+ {
+ /* Current page link is last element in pinned_pages */
+ MARIA_PINNED_PAGE *page_link;
+ page_link= dynamic_element(&info->pinned_pages,
+ info->pinned_pages.elements-1,
+ MARIA_PINNED_PAGE*);
+ pagecache_unlock_by_link(share->pagecache, page_link->link,
+ PAGECACHE_LOCK_WRITE_TO_READ,
+ PAGECACHE_PIN_LEFT_PINNED, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 1, FALSE);
+ DBUG_ASSERT(page_link->changed);
+ page_link->unlock= PAGECACHE_LOCK_READ_UNLOCK;
+ res= 0;
+ }
+ else if (!(res= pagecache_write(share->pagecache,
+ &info->dfile, block->page, 0,
+ row_pos.buff,share->page_type,
+ PAGECACHE_LOCK_READ,
+ PAGECACHE_PIN,
+ PAGECACHE_WRITE_DELAY, &page_link.link,
+ LSN_IMPOSSIBLE)))
+ {
+ page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ }
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Write full pages
+
+ SYNOPSIS
+ write_full_pages()
+ info Maria handler
+ lsn LSN for the undo record
+ block Where to write data
+ data Data to write
+ length Length of data
+
+ NOTES
+ Logging of the changes to the full pages are done in the caller
+ write_block_record().
+
+ RETURN
+ 0 ok
+ 1 error on write
+*/
+
+static my_bool write_full_pages(MARIA_HA *info,
+ LSN lsn,
+ MARIA_BITMAP_BLOCK *block,
+ uchar *data, ulong length)
+{
+ pgcache_page_no_t page;
+ MARIA_SHARE *share= info->s;
+ uint block_size= share->block_size;
+ uint data_size= FULL_PAGE_SIZE(block_size);
+ uchar *buff= info->keyread_buff;
+ uint page_count, sub_blocks;
+ my_off_t position;
+ DBUG_ENTER("write_full_pages");
+ DBUG_PRINT("enter", ("length: %lu page: %lu page_count: %lu",
+ (ulong) length, (ulong) block->page,
+ (ulong) block->page_count));
+ DBUG_ASSERT((block->page_count & TAIL_BIT) == 0);
+
+ info->keyread_buff_used= 1;
+ page= block->page;
+ page_count= block->page_count;
+ sub_blocks= block->sub_blocks;
+
+ position= (my_off_t) (page + page_count) * block_size;
+ if (share->state.state.data_file_length < position)
+ _ma_set_share_data_file_length(share, position);
+
+ /* Increase data file size, if extended */
+
+ for (; length; data+= data_size)
+ {
+ uint copy_length;
+ if (!page_count--)
+ {
+ if (!--sub_blocks)
+ {
+ DBUG_ASSERT(0); /* Wrong in bitmap or UNDO */
+ my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */
+ DBUG_RETURN(1);
+ }
+
+ block++;
+ page= block->page;
+ page_count= block->page_count - 1;
+ DBUG_PRINT("info", ("page: %lu page_count: %lu",
+ (ulong) block->page, (ulong) block->page_count));
+
+ position= (page + page_count + 1) * block_size;
+ if (share->state.state.data_file_length < position)
+ _ma_set_share_data_file_length(share, position);
+ }
+ lsn_store(buff, lsn);
+ buff[PAGE_TYPE_OFFSET]= (uchar) BLOB_PAGE;
+ copy_length= min(data_size, length);
+ memcpy(buff + LSN_SIZE + PAGE_TYPE_SIZE, data, copy_length);
+ length-= copy_length;
+
+ /*
+ Zero out old information from the block. This removes possible
+ sensitive information from the block and also makes the file
+ easier to compress and easier to compare after recovery.
+ */
+ if (copy_length != data_size)
+ bzero(buff + block_size - PAGE_SUFFIX_SIZE - (data_size - copy_length),
+ (data_size - copy_length) + PAGE_SUFFIX_SIZE);
+
+ if (pagecache_write(share->pagecache,
+ &info->dfile, page, 0,
+ buff, share->page_type,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, info->trn->rec_lsn))
+ DBUG_RETURN(1);
+ page++;
+ DBUG_ASSERT(block->used & BLOCKUSED_USED);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Store ranges of full pages in compact format for logging
+
+ SYNOPSIS
+ store_page_range()
+ to Store data here
+ block Where pages are to be written
+ block_size block size
+ length Length of data to be written
+ Normally this is full pages, except for the last
+ tail block that may only partly fit the last page.
+ tot_ranges Add here the number of ranges used
+
+ NOTES
+ The format of one entry is:
+
+ Ranges SUB_RANGE_SIZE
+ Empty bytes at end of last byte BLOCK_FILLER_SIZE
+ For each range
+ Page number PAGE_STORE_SIZE
+ Number of pages PAGERANGE_STORE_SIZE
+
+ RETURN
+ # end position for 'to'
+*/
+
+static uchar *store_page_range(uchar *to, MARIA_BITMAP_BLOCK *block,
+ uint block_size, ulong length,
+ uint *tot_ranges)
+{
+ uint data_size= FULL_PAGE_SIZE(block_size);
+ ulong pages_left= (length + data_size -1) / data_size;
+ uint page_count, ranges, empty_space;
+ uchar *to_start;
+ DBUG_ENTER("store_page_range");
+
+ to_start= to;
+ to+= SUB_RANGE_SIZE;
+
+ /* Store number of unused bytes at last page */
+ empty_space= (uint) (pages_left * data_size - length);
+ int2store(to, empty_space);
+ to+= BLOCK_FILLER_SIZE;
+
+ ranges= 0;
+ do
+ {
+ pgcache_page_no_t page;
+ page= block->page;
+ page_count= block->page_count;
+ block++;
+ if (page_count > pages_left)
+ page_count= pages_left;
+
+ page_store(to, page);
+ to+= PAGE_STORE_SIZE;
+ pagerange_store(to, page_count);
+ to+= PAGERANGE_STORE_SIZE;
+ ranges++;
+ } while ((pages_left-= page_count));
+ /* Store number of ranges for this block */
+ int2store(to_start, ranges);
+ (*tot_ranges)+= ranges;
+
+ DBUG_RETURN(to);
+}
+
+
+/*
+ Store packed extent data
+
+ SYNOPSIS
+ store_extent_info()
+ to Store first packed data here
+ row_extents_second_part Store rest here
+ first_block First block to store
+ count Number of blocks
+
+ NOTES
+ We don't have to store the position for the head block
+
+ We have to set the START_EXTENT_BIT for every extent where the
+ blob will be stored on a page of it's own. We need this in the
+ UNDO phase to generate MARIA_BITMAP_BLOCK's for undo-delete and
+ undo-update.
+*/
+
+static void store_extent_info(uchar *to,
+ uchar *row_extents_second_part,
+ MARIA_BITMAP_BLOCK *first_block,
+ uint count)
+{
+ MARIA_BITMAP_BLOCK *block, *end_block;
+ uint copy_length;
+ my_bool first_found= 0;
+
+ for (block= first_block, end_block= first_block+count ;
+ block < end_block; block++)
+ {
+ /* The following is only false for marker blocks */
+ if (likely(block->used & BLOCKUSED_USED))
+ {
+ uint page_count= block->page_count;
+ DBUG_ASSERT(page_count != 0);
+ page_store(to, block->page);
+ if (block->sub_blocks)
+ {
+ /*
+ Set a bit so that we later know that this was the first block
+ for a blob
+ */
+ page_count|= START_EXTENT_BIT;
+ }
+ pagerange_store(to + PAGE_STORE_SIZE, page_count);
+ to+= ROW_EXTENT_SIZE;
+ if (!first_found)
+ {
+ first_found= 1;
+ to= row_extents_second_part;
+ }
+ }
+ }
+ copy_length= (count - 1) * ROW_EXTENT_SIZE;
+ /*
+ In some unlikely cases we have allocated to many blocks. Clear this
+ data.
+ */
+ bzero(to, (size_t) (row_extents_second_part + copy_length - to));
+}
+
+
+/**
+ @brief
+ Convert extent info read from file to MARIA_BITMAP_BLOCKS suitable
+ for write_block_record
+
+ @note
+ In case of blobs, this function marks all the blob pages in the bitmap
+ as full pages. The bitmap bits for other pages will be marked
+ when write_block_record() calls _ma_bitmap_release_unused().
+
+ This function will be removed in Maria 2.0 when we instead of delete rows
+ mark them as deleted and only remove them after commit.
+
+ @return
+ @retval 0 ok
+ @retval 1 Error (out of memory or disk error changing bitmap)
+*/
+
+static my_bool extent_to_bitmap_blocks(MARIA_HA *info,
+ MARIA_BITMAP_BLOCKS *blocks,
+ pgcache_page_no_t head_page,
+ uint extent_count,
+ const uchar *extent_info)
+{
+ MARIA_BITMAP_BLOCK *block, *start_block;
+ MARIA_SHARE *share= info->s;
+ uint i;
+ DBUG_ENTER("extent_to_bitmap_blocks");
+
+ if (allocate_dynamic(&info->bitmap_blocks, extent_count + 2))
+ DBUG_RETURN(1);
+ block= blocks->block= dynamic_element(&info->bitmap_blocks, 0,
+ MARIA_BITMAP_BLOCK*);
+ blocks->count= extent_count + 1;
+ blocks->tail_page_skipped= blocks->page_skipped= 0;
+ block->page= head_page;
+ block->page_count= 1;
+ block->used= BLOCKUSED_USED | BLOCKUSED_USE_ORG_BITMAP;
+ /* Impossible value, will force storage of real value */
+ block->org_bitmap_value= 255;
+
+ start_block= block++;
+ for (i=0 ;
+ i++ < extent_count ;
+ block++, extent_info+= ROW_EXTENT_SIZE)
+ {
+ uint page_count= uint2korr(extent_info + ROW_EXTENT_PAGE_SIZE);
+ if (page_count & START_EXTENT_BIT)
+ {
+ page_count&= ~START_EXTENT_BIT;
+ start_block->sub_blocks= (uint) (block - start_block);
+ start_block= block;
+
+ }
+ block->page= page_korr(extent_info);
+ block->page_count= page_count;
+ block->sub_blocks= 0;
+
+ if (page_count & TAIL_BIT)
+ {
+ block->org_bitmap_value= _ma_bitmap_get_page_bits(info, &share->bitmap,
+ block->page);
+ block->used= (BLOCKUSED_TAIL | BLOCKUSED_USED |
+ BLOCKUSED_USE_ORG_BITMAP);
+ }
+ else
+ {
+ my_bool res;
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+ res= _ma_bitmap_set_full_page_bits(info, &share->bitmap,
+ block->page, block->page_count);
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ if (res)
+ DBUG_RETURN(1);
+ block->used= BLOCKUSED_USED;
+ }
+ }
+ start_block->sub_blocks= (uint) (block - start_block);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Free regions of pages with logging
+
+ NOTES
+ We are removing filler events and tail page events from
+ row->extents to get smaller log.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool free_full_pages(MARIA_HA *info, MARIA_ROW *row)
+{
+ uchar log_data[FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ LSN lsn;
+ size_t extents_length;
+ uchar *extents= row->extents;
+ DBUG_ENTER("free_full_pages");
+
+ if (info->s->now_transactional)
+ {
+ /* Compact events by removing filler and tail events */
+ uchar *new_block= 0;
+ uchar *end, *to, *compact_extent_info;
+ my_bool res;
+ uint extents_count;
+
+ if (!(compact_extent_info= my_alloca(row->extents_count *
+ ROW_EXTENT_SIZE)))
+ DBUG_RETURN(1);
+
+ to= compact_extent_info;
+ for (end= extents + row->extents_count * ROW_EXTENT_SIZE ;
+ extents < end ;
+ extents+= ROW_EXTENT_SIZE)
+ {
+ uint page_count= uint2korr(extents + ROW_EXTENT_PAGE_SIZE);
+ page_count&= ~START_EXTENT_BIT;
+ if (! (page_count & TAIL_BIT) && page_count != 0)
+ {
+ /* Found correct extent */
+ if (!new_block)
+ new_block= extents; /* First extent in range */
+ continue;
+ }
+ /* Found extent to remove, copy everything found so far */
+ if (new_block)
+ {
+ size_t length= (size_t) (extents - new_block);
+ memcpy(to, new_block, length);
+ to+= length;
+ new_block= 0;
+ }
+ }
+ if (new_block)
+ {
+ size_t length= (size_t) (extents - new_block);
+ memcpy(to, new_block, length);
+ to+= length;
+ }
+
+ if (!unlikely(extents_length= (uint) (to - compact_extent_info)))
+ {
+ /*
+ No ranges. This happens in the rear case when we have a allocated
+ place for a blob on a tail page but it did fit into the main page.
+ */
+ my_afree(compact_extent_info);
+ DBUG_RETURN(0);
+ }
+ extents_count= (uint) (extents_length / ROW_EXTENT_SIZE);
+ pagerange_store(log_data + FILEID_STORE_SIZE, extents_count);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= compact_extent_info;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= extents_length;
+ res= translog_write_record(&lsn, LOGREC_REDO_FREE_BLOCKS, info->trn,
+ info,
+ (translog_size_t) (sizeof(log_data) +
+ extents_length),
+ TRANSLOG_INTERNAL_PARTS + 2, log_array,
+ log_data, NULL);
+ my_afree(compact_extent_info);
+ if (res)
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(_ma_bitmap_free_full_pages(info, row->extents,
+ row->extents_count));
+}
+
+
+/*
+ Free one page range
+
+ NOTES
+ This is very similar to free_full_pages()
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool free_full_page_range(MARIA_HA *info, pgcache_page_no_t page,
+ uint count)
+{
+ my_bool res= 0;
+ uint delete_count;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("free_full_page_range");
+
+ delete_count= count;
+ if (share->state.state.data_file_length ==
+ (page + count) * share->block_size)
+ {
+ /*
+ Don't delete last page from pagecache as this will make the file
+ shorter than expected if the last operation extended the file
+ */
+ delete_count--;
+ }
+ if (delete_count &&
+ pagecache_delete_pages(share->pagecache, &info->dfile,
+ page, delete_count, PAGECACHE_LOCK_WRITE, 0))
+ res= 1;
+
+ if (share->now_transactional)
+ {
+ LSN lsn;
+ /** @todo unify log_data's shape with delete_head_or_tail() */
+ uchar log_data[FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE +
+ ROW_EXTENT_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ DBUG_ASSERT(info->trn->rec_lsn);
+ pagerange_store(log_data + FILEID_STORE_SIZE, 1);
+ page_store(log_data + FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE,
+ page);
+ int2store(log_data + FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE +
+ PAGE_STORE_SIZE, count);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+
+ if (translog_write_record(&lsn, LOGREC_REDO_FREE_BLOCKS,
+ info->trn, info,
+ (translog_size_t) sizeof(log_data),
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data, NULL))
+ res= 1;
+ }
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+ if (_ma_bitmap_reset_full_page_bits(info, &share->bitmap, page, count))
+ res= 1;
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Write a record to a (set of) pages
+
+ @fn write_block_record()
+ @param info Maria handler
+ @param old_record Original record in case of update; NULL in case of
+ insert
+ @param record Record we should write
+ @param row Statistics about record (calculated by
+ calc_record_size())
+ @param map_blocks On which pages the record should be stored
+ @param row_pos Position on head page where to put head part of
+ record
+ @param undo_lsn <> LSN_ERROR if we are executing an UNDO
+ @param old_record_checksum Checksum of old_record: ignored if table does
+ not have live checksum; otherwise if
+ old_record==NULL it must be 0.
+
+ @note
+ On return all pinned pages are released.
+
+ [page_buff + EMPTY_SPACE_OFFSET] is set to
+ row_pos->empty_space - head_length
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool write_block_record(MARIA_HA *info,
+ const uchar *old_record,
+ const uchar *record,
+ MARIA_ROW *row,
+ MARIA_BITMAP_BLOCKS *bitmap_blocks,
+ my_bool head_block_is_read,
+ struct st_row_pos_info *row_pos,
+ LSN undo_lsn,
+ ha_checksum old_record_checksum)
+{
+ uchar *data, *end_of_data, *tmp_data_used, *tmp_data;
+ uchar *row_extents_first_part, *row_extents_second_part;
+ uchar *field_length_data;
+ uchar *page_buff;
+ MARIA_BITMAP_BLOCK *block, *head_block;
+ MARIA_SHARE *share= info->s;
+ MARIA_COLUMNDEF *column, *end_column;
+ MARIA_PINNED_PAGE page_link;
+ uint block_size, flag, head_length;
+ ulong *blob_lengths;
+ my_bool row_extents_in_use, blob_full_pages_exists;
+ LSN lsn;
+ my_off_t position;
+ uint save_my_errno;
+ DBUG_ENTER("write_block_record");
+
+ LINT_INIT(row_extents_first_part);
+ LINT_INIT(row_extents_second_part);
+
+ head_block= bitmap_blocks->block;
+ block_size= share->block_size;
+
+ page_buff= row_pos->buff;
+ /* Position on head page where we should store the head part */
+ data= row_pos->data;
+ end_of_data= data + row_pos->length;
+
+ /* Write header */
+ flag= info->row_flag;
+ row_extents_in_use= 0;
+ if (unlikely(row->total_length > row_pos->length))
+ {
+ /* Need extent */
+ DBUG_ASSERT(bitmap_blocks->count > 1);
+ if (bitmap_blocks->count <= 1)
+ goto crashed; /* Wrong in bitmap */
+ flag|= ROW_FLAG_EXTENTS;
+ row_extents_in_use= 1;
+ }
+ /* For now we have only a minimum header */
+ *data++= (uchar) flag;
+ if (flag & ROW_FLAG_TRANSID)
+ {
+ transid_store(data, info->trn->trid);
+ data+= TRANSID_SIZE;
+ }
+
+ if (unlikely(flag & ROW_FLAG_NULLS_EXTENDED))
+ *data++= (uchar) (share->base.null_bytes -
+ share->base.original_null_bytes);
+ if (row_extents_in_use)
+ {
+ /* Store first extent in header */
+ store_key_length_inc(data, bitmap_blocks->count - 1);
+ row_extents_first_part= data;
+ data+= ROW_EXTENT_SIZE;
+ }
+ if (share->base.max_field_lengths)
+ store_key_length_inc(data, row->field_lengths_length);
+ if (share->calc_checksum)
+ {
+ *(data++)= (uchar) (row->checksum); /* store least significant byte */
+ DBUG_ASSERT(!((old_record_checksum != 0) && (old_record == NULL)));
+ }
+ memcpy(data, record, share->base.null_bytes);
+ data+= share->base.null_bytes;
+ memcpy(data, row->empty_bits, share->base.pack_bytes);
+ data+= share->base.pack_bytes;
+
+ DBUG_ASSERT(row_extents_in_use || undo_lsn != LSN_ERROR ||
+ (uint) (data - row_pos->data) == row->min_length);
+
+ /*
+ Allocate a buffer of rest of data (except blobs)
+
+ To avoid double copying of data, we copy as many columns that fits into
+ the page. The rest goes into info->packed_row.
+
+ Using an extra buffer, instead of doing continuous writes to different
+ pages, uses less code and we don't need to have to do a complex call
+ for every data segment we want to store.
+ */
+ if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
+ row->head_length))
+ DBUG_RETURN(1);
+
+ tmp_data_used= 0; /* Either 0 or last used uchar in 'data' */
+ tmp_data= data;
+
+ if (row_extents_in_use)
+ {
+ uint copy_length= (bitmap_blocks->count - 2) * ROW_EXTENT_SIZE;
+ if (!tmp_data_used && tmp_data + copy_length > end_of_data)
+ {
+ tmp_data_used= tmp_data;
+ tmp_data= info->rec_buff;
+ }
+ row_extents_second_part= tmp_data;
+ /*
+ We will copy the extents here when we have figured out the tail
+ positions.
+ */
+ tmp_data+= copy_length;
+ }
+
+ /* Copy fields that has fixed lengths (primary key etc) */
+ for (column= share->columndef,
+ end_column= column + share->base.fixed_not_null_fields;
+ column < end_column; column++)
+ {
+ if (!tmp_data_used && tmp_data + column->length > end_of_data)
+ {
+ tmp_data_used= tmp_data;
+ tmp_data= info->rec_buff;
+ }
+ memcpy(tmp_data, record + column->offset, column->length);
+ tmp_data+= column->length;
+ }
+
+ /* Copy length of data for variable length fields */
+ if (!tmp_data_used && tmp_data + row->field_lengths_length > end_of_data)
+ {
+ tmp_data_used= tmp_data;
+ tmp_data= info->rec_buff;
+ }
+ field_length_data= row->field_lengths;
+ memcpy(tmp_data, field_length_data, row->field_lengths_length);
+ tmp_data+= row->field_lengths_length;
+
+ DBUG_ASSERT(row_extents_in_use || undo_lsn != LSN_ERROR ||
+ (uint) (tmp_data - row_pos->data) == row->min_length +
+ share->base.fixed_not_null_fields_length +
+ row->field_lengths_length);
+
+ /* Copy variable length fields and fields with null/zero */
+ for (end_column= share->columndef + share->base.fields - share->base.blobs;
+ column < end_column ;
+ column++)
+ {
+ const uchar *field_pos;
+ ulong length;
+ if ((record[column->null_pos] & column->null_bit) ||
+ (row->empty_bits[column->empty_pos] & column->empty_bit))
+ continue;
+
+ field_pos= record + column->offset;
+ switch (column->type) {
+ case FIELD_NORMAL: /* Fixed length field */
+ case FIELD_SKIP_PRESPACE:
+ case FIELD_SKIP_ZERO: /* Fixed length field */
+ length= column->length;
+ break;
+ case FIELD_SKIP_ENDSPACE: /* CHAR */
+ /* Char that is space filled */
+ if (column->length <= 255)
+ length= (uint) (uchar) *field_length_data++;
+ else
+ {
+ length= uint2korr(field_length_data);
+ field_length_data+= 2;
+ }
+ break;
+ case FIELD_VARCHAR:
+ if (column->length <= 256)
+ {
+ length= (uint) (uchar) *field_length_data++;
+ field_pos++; /* Skip length uchar */
+ }
+ else
+ {
+ length= uint2korr(field_length_data);
+ field_length_data+= 2;
+ field_pos+= 2;
+ }
+ DBUG_ASSERT(length <= column->length);
+ break;
+ default: /* Wrong data */
+ DBUG_ASSERT(0);
+ length=0;
+ break;
+ }
+ if (!tmp_data_used && tmp_data + length > end_of_data)
+ {
+ /* Data didn't fit in page; Change to use tmp buffer */
+ tmp_data_used= tmp_data;
+ tmp_data= info->rec_buff;
+ }
+ memcpy((char*) tmp_data, field_pos, length);
+ tmp_data+= length;
+ }
+
+ block= head_block + head_block->sub_blocks; /* Point to first blob data */
+
+ end_column= column + share->base.blobs;
+ blob_lengths= row->blob_lengths;
+ if (!tmp_data_used)
+ {
+ /* Still room on page; Copy as many blobs we can into this page */
+ data= tmp_data;
+ for (; column < end_column &&
+ *blob_lengths <= (ulong)(end_of_data - data);
+ column++, blob_lengths++)
+ {
+ uchar *tmp_pos;
+ uint length;
+ if (!*blob_lengths) /* Null or "" */
+ continue;
+ length= column->length - portable_sizeof_char_ptr;
+ memcpy_fixed((uchar*) &tmp_pos, record + column->offset + length,
+ sizeof(char*));
+ memcpy(data, tmp_pos, *blob_lengths);
+ data+= *blob_lengths;
+ /* Skip over tail page that was to be used to store blob */
+ block++;
+ bitmap_blocks->tail_page_skipped= 1;
+ }
+ if (head_block->sub_blocks > 1)
+ {
+ /* We have allocated pages that where not used */
+ bitmap_blocks->page_skipped= 1;
+ }
+ }
+ else
+ data= tmp_data_used; /* Get last used on page */
+
+ /* Update page directory */
+ head_length= (uint) (data - row_pos->data);
+ DBUG_PRINT("info", ("Used head length on page: %u", head_length));
+ DBUG_ASSERT(data <= end_of_data);
+ if (head_length < share->base.min_block_length)
+ {
+ /* Extend row to be of size min_block_length */
+ uint diff_length= share->base.min_block_length - head_length;
+ bzero(data, diff_length);
+ data+= diff_length;
+ head_length= share->base.min_block_length;
+ }
+ int2store(row_pos->dir + 2, head_length);
+ /* update empty space at start of block */
+ row_pos->empty_space-= head_length;
+ int2store(page_buff + EMPTY_SPACE_OFFSET, row_pos->empty_space);
+ /* Mark in bitmaps how the current page was actually used */
+ head_block->empty_space= row_pos->empty_space;
+ if (page_buff[DIR_COUNT_OFFSET] == MAX_ROWS_PER_PAGE &&
+ page_buff[DIR_FREE_OFFSET] == END_OF_DIR_FREE_LIST)
+ head_block->empty_space= 0; /* Page is full */
+ head_block->used|= BLOCKUSED_USED;
+
+ check_directory(page_buff, share->block_size, share->base.min_block_length);
+
+ /*
+ Now we have to write tail pages, as we need to store the position
+ to them in the row extent header.
+
+ We first write out all blob tails, to be able to store them in
+ the current page or 'tmp_data'.
+
+ Then we write the tail of the non-blob fields (The position to the
+ tail page is stored either in row header, the extents in the head
+ page or in the first full page of the non-blob data. It's never in
+ the tail page of the non-blob data)
+ */
+
+ blob_full_pages_exists= 0;
+ if (row_extents_in_use)
+ {
+ if (column != end_column) /* If blob fields */
+ {
+ MARIA_COLUMNDEF *save_column= column;
+ MARIA_BITMAP_BLOCK *save_block= block;
+ MARIA_BITMAP_BLOCK *end_block;
+ ulong *save_blob_lengths= blob_lengths;
+
+ for (; column < end_column; column++, blob_lengths++)
+ {
+ uchar *blob_pos;
+ if (!*blob_lengths) /* Null or "" */
+ continue;
+ if (block[block->sub_blocks - 1].used & BLOCKUSED_TAIL)
+ {
+ uint length;
+ length= column->length - portable_sizeof_char_ptr;
+ memcpy_fixed((uchar *) &blob_pos, record + column->offset + length,
+ sizeof(char*));
+ length= *blob_lengths % FULL_PAGE_SIZE(block_size); /* tail size */
+ if (length != *blob_lengths)
+ blob_full_pages_exists= 1;
+ if (write_tail(info, block + block->sub_blocks-1,
+ blob_pos + *blob_lengths - length,
+ length))
+ goto disk_err;
+ }
+ else
+ blob_full_pages_exists= 1;
+
+ for (end_block= block + block->sub_blocks; block < end_block; block++)
+ {
+ /*
+ Set only a bit, to not cause bitmap code to believe a block is full
+ when there is still a lot of entries in it
+ */
+ block->used|= BLOCKUSED_USED;
+ }
+ }
+ column= save_column;
+ block= save_block;
+ blob_lengths= save_blob_lengths;
+ }
+
+ if (tmp_data_used) /* non blob data overflows */
+ {
+ MARIA_BITMAP_BLOCK *cur_block, *end_block, *last_head_block;
+ MARIA_BITMAP_BLOCK *head_tail_block= 0;
+ ulong length;
+ ulong data_length= (ulong) (tmp_data - info->rec_buff);
+
+#ifdef SANITY_CHECKS
+ DBUG_ASSERT(head_block->sub_blocks != 1);
+ if (head_block->sub_blocks == 1)
+ goto crashed; /* no reserved full or tails */
+#endif
+ /*
+ Find out where to write tail for non-blob fields.
+
+ Problem here is that the bitmap code may have allocated more
+ space than we need. We have to handle the following cases:
+
+ - Bitmap code allocated a tail page we don't need.
+ - The last full page allocated needs to be changed to a tail page
+ (Because we where able to put more data on the head page than
+ the bitmap allocation assumed)
+
+ The reserved pages in bitmap_blocks for the main page has one of
+ the following allocations:
+ - Full pages, with following blocks:
+ # * full pages
+ empty page ; To be used if we change last full to tail page. This
+ has 'count' = 0.
+ tail page (optional, if last full page was part full)
+ - One tail page
+ */
+
+ cur_block= head_block + 1;
+ end_block= head_block + head_block->sub_blocks;
+ /*
+ Loop until we have find a block bigger than we need or
+ we find the empty page block.
+ */
+ while (data_length >= (length= (cur_block->page_count *
+ FULL_PAGE_SIZE(block_size))) &&
+ cur_block->page_count)
+ {
+#ifdef SANITY_CHECKS
+ DBUG_ASSERT(!((cur_block == end_block) ||
+ (cur_block->used & BLOCKUSED_USED)));
+ if ((cur_block == end_block) || (cur_block->used & BLOCKUSED_USED))
+ goto crashed;
+#endif
+ data_length-= length;
+ (cur_block++)->used|= BLOCKUSED_USED;
+ }
+ last_head_block= cur_block;
+ if (data_length)
+ {
+ if (cur_block->page_count == 0)
+ {
+ /* Skip empty filler block */
+ cur_block++;
+ }
+#ifdef SANITY_CHECKS
+ DBUG_ASSERT(!(cur_block >= end_block));
+ if ((cur_block >= end_block))
+ goto crashed;
+#endif
+ if (cur_block->used & BLOCKUSED_TAIL)
+ {
+ DBUG_ASSERT(data_length < MAX_TAIL_SIZE(block_size));
+ /* tail written to full tail page */
+ cur_block->used|= BLOCKUSED_USED;
+ head_tail_block= cur_block;
+ }
+ else if (data_length > length - MAX_TAIL_SIZE(block_size))
+ {
+ /* tail written to full page */
+ cur_block->used|= BLOCKUSED_USED;
+ if ((cur_block != end_block - 1) &&
+ (end_block[-1].used & BLOCKUSED_TAIL))
+ bitmap_blocks->tail_page_skipped= 1;
+ }
+ else
+ {
+ /*
+ cur_block is a full block, followed by an empty and optional
+ tail block. Change cur_block to a tail block or split it
+ into full blocks and tail blocks.
+
+ TODO:
+ If there is enough space on the following tail block, use
+ this instead of creating a new tail block.
+ */
+ DBUG_ASSERT(cur_block[1].page_count == 0);
+ if (cur_block->page_count == 1)
+ {
+ /* convert full block to tail block */
+ cur_block->used|= BLOCKUSED_USED | BLOCKUSED_TAIL;
+ head_tail_block= cur_block;
+ }
+ else
+ {
+ DBUG_ASSERT(data_length < length - FULL_PAGE_SIZE(block_size));
+ DBUG_PRINT("info", ("Splitting blocks into full and tail"));
+ cur_block[1].page= (cur_block->page + cur_block->page_count - 1);
+ cur_block[1].page_count= 1; /* Avoid DBUG_ASSERT */
+ cur_block[1].used= BLOCKUSED_USED | BLOCKUSED_TAIL;
+ cur_block->page_count--;
+ cur_block->used|= BLOCKUSED_USED;
+ last_head_block= head_tail_block= cur_block+1;
+ }
+ if (end_block[-1].used & BLOCKUSED_TAIL)
+ bitmap_blocks->tail_page_skipped= 1;
+ }
+ }
+ else
+ {
+ /* Must be an empty or tail page */
+ DBUG_ASSERT(cur_block->page_count == 0 ||
+ cur_block->used & BLOCKUSED_TAIL);
+ if (end_block[-1].used & BLOCKUSED_TAIL)
+ bitmap_blocks->tail_page_skipped= 1;
+ }
+
+ /*
+ Write all extents into page or tmp_data
+
+ Note that we still don't have a correct position for the tail
+ of the non-blob fields.
+ */
+ store_extent_info(row_extents_first_part,
+ row_extents_second_part,
+ head_block+1, bitmap_blocks->count - 1);
+ if (head_tail_block)
+ {
+ ulong block_length= (ulong) (tmp_data - info->rec_buff);
+ uchar *extent_data;
+
+ length= (uint) (block_length % FULL_PAGE_SIZE(block_size));
+ if (write_tail(info, head_tail_block,
+ info->rec_buff + block_length - length,
+ length))
+ goto disk_err;
+ tmp_data-= length; /* Remove the tail */
+ if (tmp_data == info->rec_buff)
+ {
+ /* We have no full blocks to write for the head part */
+ tmp_data_used= 0;
+ }
+
+ /* Store the tail position for the non-blob fields */
+ if (head_tail_block == head_block + 1)
+ {
+ /*
+ We had a head block + tail block, which means that the
+ tail block is the first extent
+ */
+ extent_data= row_extents_first_part;
+ }
+ else
+ {
+ /*
+ We have a head block + some full blocks + tail block
+ last_head_block is pointing after the last used extent
+ for the head block.
+ */
+ extent_data= row_extents_second_part +
+ ((last_head_block - head_block) - 2) * ROW_EXTENT_SIZE;
+ }
+ DBUG_ASSERT(uint2korr(extent_data+5) & TAIL_BIT);
+ page_store(extent_data, head_tail_block->page);
+ int2store(extent_data + PAGE_STORE_SIZE, head_tail_block->page_count);
+ }
+ }
+ else
+ store_extent_info(row_extents_first_part,
+ row_extents_second_part,
+ head_block+1, bitmap_blocks->count - 1);
+ }
+
+ if (share->now_transactional)
+ {
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+
+ /* Log REDO changes of head page */
+ page_store(log_data + FILEID_STORE_SIZE, head_block->page);
+ dirpos_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE,
+ row_pos->rownr);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= row_pos->data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= head_length;
+ if (translog_write_record(&lsn,
+ head_block_is_read ?
+ LOGREC_REDO_INSERT_ROW_HEAD :
+ LOGREC_REDO_NEW_ROW_HEAD,
+ info->trn,
+ info,
+ (translog_size_t) (sizeof(log_data) +
+ head_length),
+ TRANSLOG_INTERNAL_PARTS + 2, log_array,
+ log_data, NULL))
+ goto disk_err;
+ }
+
+#ifdef RECOVERY_EXTRA_DEBUG
+ if (info->trn->undo_lsn != LSN_IMPOSSIBLE)
+ {
+ /* Stop right after the REDO; testing incomplete log record groups */
+ DBUG_EXECUTE_IF("maria_flush_whole_log",
+ {
+ DBUG_PRINT("maria_flush_whole_log", ("now"));
+ translog_flush(translog_get_horizon());
+ });
+ DBUG_EXECUTE_IF("maria_crash",
+ { DBUG_PRINT("maria_crash", ("now")); DBUG_ABORT(); });
+ }
+#endif
+
+ /* Increase data file size, if extended */
+ position= (my_off_t) head_block->page * block_size;
+ if (share->state.state.data_file_length <= position)
+ _ma_set_share_data_file_length(share, position + block_size);
+
+ if (head_block_is_read)
+ {
+ MARIA_PINNED_PAGE *page_link;
+ /* Head page is always the first pinned page */
+ page_link= dynamic_element(&info->pinned_pages, 0,
+ MARIA_PINNED_PAGE*);
+ pagecache_unlock_by_link(share->pagecache, page_link->link,
+ PAGECACHE_LOCK_WRITE_TO_READ,
+ PAGECACHE_PIN_LEFT_PINNED, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 1, FALSE);
+ page_link->unlock= PAGECACHE_LOCK_READ_UNLOCK;
+ page_link->changed= 1;
+ }
+ else
+ {
+ if (pagecache_write(share->pagecache,
+ &info->dfile, head_block->page, 0,
+ page_buff, share->page_type,
+ head_block_is_read ? PAGECACHE_LOCK_WRITE_TO_READ :
+ PAGECACHE_LOCK_READ,
+ head_block_is_read ? PAGECACHE_PIN_LEFT_PINNED :
+ PAGECACHE_PIN,
+ PAGECACHE_WRITE_DELAY, &page_link.link,
+ LSN_IMPOSSIBLE))
+ goto disk_err;
+ page_link.unlock= PAGECACHE_LOCK_READ_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ }
+
+ if (share->now_transactional && (tmp_data_used || blob_full_pages_exists))
+ {
+ /*
+ Log REDO writes for all full pages (head part and all blobs)
+ We write all here to be able to generate the UNDO record early
+ so that we can write the LSN for the UNDO record to all full pages.
+ */
+ uchar tmp_log_data[FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE +
+ (ROW_EXTENT_SIZE + BLOCK_FILLER_SIZE + SUB_RANGE_SIZE) *
+ ROW_EXTENTS_ON_STACK];
+ uchar *log_data, *log_pos;
+ LEX_CUSTRING tmp_log_array[TRANSLOG_INTERNAL_PARTS + 2 +
+ ROW_EXTENTS_ON_STACK];
+ LEX_CUSTRING *log_array_pos, *log_array;
+ int error;
+ translog_size_t log_entry_length= 0;
+ uint ext_length, extents= 0, sub_extents= 0;
+
+ /* If few extents, then allocate things on stack to avoid a malloc call */
+ if (bitmap_blocks->count < ROW_EXTENTS_ON_STACK)
+ {
+ log_array= tmp_log_array;
+ log_data= tmp_log_data;
+ }
+ else
+ {
+ if (!my_multi_malloc(MY_WME, &log_array,
+ (uint) ((bitmap_blocks->count +
+ TRANSLOG_INTERNAL_PARTS + 2) *
+ sizeof(*log_array)),
+ &log_data, FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE +
+ bitmap_blocks->count * (ROW_EXTENT_SIZE +
+ BLOCK_FILLER_SIZE +
+ SUB_RANGE_SIZE),
+ NullS))
+ goto disk_err;
+ }
+ log_pos= log_data + FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE * 2;
+ log_array_pos= log_array+ TRANSLOG_INTERNAL_PARTS+1;
+
+ if (tmp_data_used)
+ {
+ /* Full head page */
+ translog_size_t block_length= (translog_size_t) (tmp_data -
+ info->rec_buff);
+ log_pos= store_page_range(log_pos, head_block+1, block_size,
+ (ulong) block_length, &extents);
+ log_array_pos->str= info->rec_buff;
+ log_array_pos->length= block_length;
+ log_entry_length+= block_length;
+ log_array_pos++;
+ sub_extents++;
+ }
+ if (blob_full_pages_exists)
+ {
+ MARIA_COLUMNDEF *tmp_column= column;
+ ulong *tmp_blob_lengths= blob_lengths;
+ MARIA_BITMAP_BLOCK *tmp_block= block;
+
+ /* Full blob pages */
+ for (; tmp_column < end_column; tmp_column++, tmp_blob_lengths++)
+ {
+ ulong blob_length;
+ uint length;
+
+ if (!*tmp_blob_lengths) /* Null or "" */
+ continue;
+ blob_length= *tmp_blob_lengths;
+ length= tmp_column->length - portable_sizeof_char_ptr;
+ /*
+ If last part of blog was on tail page, change blob_length to
+ reflect this
+ */
+ if (tmp_block[tmp_block->sub_blocks - 1].used & BLOCKUSED_TAIL)
+ blob_length-= (blob_length % FULL_PAGE_SIZE(block_size));
+ if (blob_length)
+ {
+ memcpy_fixed((uchar*) &log_array_pos->str,
+ record + tmp_column->offset + length,
+ sizeof(uchar*));
+ log_array_pos->length= blob_length;
+ log_entry_length+= blob_length;
+ log_array_pos++;
+ sub_extents++;
+
+ log_pos= store_page_range(log_pos, tmp_block, block_size,
+ blob_length, &extents);
+ }
+ tmp_block+= tmp_block->sub_blocks;
+ }
+ }
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ ext_length= (uint) (log_pos - log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= ext_length;
+ pagerange_store(log_data+ FILEID_STORE_SIZE, extents);
+ pagerange_store(log_data+ FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE,
+ sub_extents);
+
+ log_entry_length+= ext_length;
+ /* trn->rec_lsn is already set earlier in this function */
+ error= translog_write_record(&lsn, LOGREC_REDO_INSERT_ROW_BLOBS,
+ info->trn, info, log_entry_length,
+ (uint) (log_array_pos - log_array),
+ log_array, log_data, NULL);
+ if (log_array != tmp_log_array)
+ my_free(log_array, MYF(0));
+ if (error)
+ goto disk_err;
+ }
+
+ /* Write UNDO or CLR record */
+ lsn= LSN_IMPOSSIBLE;
+ if (share->now_transactional)
+ {
+ LEX_CUSTRING *log_array= info->log_row_parts;
+
+ if (undo_lsn != LSN_ERROR)
+ {
+ /*
+ Store if this CLR is about UNDO_DELETE or UNDO_UPDATE;
+ in the first case, Recovery, when it sees the CLR_END in the
+ REDO phase, may decrement the records' count.
+ */
+ if (_ma_write_clr(info, undo_lsn,
+ old_record ? LOGREC_UNDO_ROW_UPDATE :
+ LOGREC_UNDO_ROW_DELETE,
+ share->calc_checksum != 0,
+ row->checksum - old_record_checksum,
+ &lsn, (void*) 0))
+ goto disk_err;
+ }
+ else
+ {
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE +
+ HA_CHECKSUM_STORE_SIZE + 2 + PAGERANGE_STORE_SIZE +
+ ROW_EXTENT_SIZE];
+ ha_checksum checksum_delta;
+
+ /* LOGREC_UNDO_ROW_INSERT & LOGREC_UNDO_ROW_UPDATE share same header */
+ lsn_store(log_data, info->trn->undo_lsn);
+ page_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
+ head_block->page);
+ dirpos_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE,
+ row_pos->rownr);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length=
+ (LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE +
+ DIRPOS_STORE_SIZE);
+ store_checksum_in_rec(share, checksum_delta,
+ row->checksum - old_record_checksum,
+ log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length);
+ compile_time_assert(sizeof(ha_checksum) == HA_CHECKSUM_STORE_SIZE);
+
+ if (!old_record)
+ {
+ /* Store undo_lsn in case we are aborting the insert */
+ row->orig_undo_lsn= info->trn->undo_lsn;
+ /* Write UNDO log record for the INSERT */
+ if (translog_write_record(&lsn, LOGREC_UNDO_ROW_INSERT,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ log_array,
+ log_data + LSN_STORE_SIZE, &checksum_delta))
+ goto disk_err;
+ }
+ else
+ {
+ /* Write UNDO log record for the UPDATE */
+ uchar *log_pos= (log_data +
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length);
+ size_t row_length, extents_length;
+ uint row_parts_count;
+
+ /*
+ Write head length and extents of the original row so that we
+ during UNDO can put it back in the original position
+ */
+ int2store(log_pos, info->cur_row.head_length);
+ pagerange_store(log_pos + 2, info->cur_row.extents_count);
+ log_pos+= 2 + PAGERANGE_STORE_SIZE;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length+= (2 +
+ PAGERANGE_STORE_SIZE);
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS+1].str=
+ info->cur_row.extents;
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS+1].length=
+ extents_length= info->cur_row.extents_count * ROW_EXTENT_SIZE;
+
+ row_length= fill_update_undo_parts(info, old_record, record,
+ log_array +
+ TRANSLOG_INTERNAL_PARTS + 2,
+ &row_parts_count);
+ if (translog_write_record(&lsn, LOGREC_UNDO_ROW_UPDATE, info->trn,
+ info,
+ (translog_size_t)
+ (log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + extents_length +
+ row_length),
+ TRANSLOG_INTERNAL_PARTS + 2 +
+ row_parts_count,
+ log_array,
+ log_data + LSN_STORE_SIZE,
+ &checksum_delta))
+ goto disk_err;
+ }
+ }
+ }
+ /* Release not used space in used pages */
+ if (_ma_bitmap_release_unused(info, bitmap_blocks))
+ goto disk_err;
+ _ma_unpin_all_pages(info, lsn);
+
+ if (tmp_data_used)
+ {
+ /*
+ Write data stored in info->rec_buff to pages
+ This is the char/varchar data that didn't fit into the head page.
+ */
+ DBUG_ASSERT(bitmap_blocks->count != 0);
+ if (write_full_pages(info, lsn, head_block + 1,
+ info->rec_buff, (ulong) (tmp_data - info->rec_buff)))
+ goto disk_err;
+ }
+
+ /* Write rest of blobs (data, but no tails as they are already written) */
+ for (; column < end_column; column++, blob_lengths++)
+ {
+ uchar *blob_pos;
+ uint length;
+ ulong blob_length;
+ if (!*blob_lengths) /* Null or "" */
+ continue;
+ length= column->length - portable_sizeof_char_ptr;
+ memcpy_fixed((uchar*) &blob_pos, record + column->offset + length,
+ sizeof(char*));
+ /* remove tail part */
+ blob_length= *blob_lengths;
+ if (block[block->sub_blocks - 1].used & BLOCKUSED_TAIL)
+ blob_length-= (blob_length % FULL_PAGE_SIZE(block_size));
+
+ if (blob_length && write_full_pages(info, lsn, block,
+ blob_pos, blob_length))
+ goto disk_err;
+ block+= block->sub_blocks;
+ }
+
+ _ma_finalize_row(info);
+ DBUG_RETURN(0);
+
+crashed:
+ /* Something was wrong with data on page */
+ my_errno= HA_ERR_WRONG_IN_RECORD;
+
+disk_err:
+ /**
+ @todo RECOVERY we are going to let dirty pages go to disk while we have
+ logged UNDO, this violates WAL. We must mark the table corrupted!
+
+ @todo RECOVERY we have written some REDOs without a closing UNDO,
+ it's possible that a next operation by this transaction succeeds and then
+ Recovery would glue the "orphan REDOs" to the succeeded operation and
+ execute the failed REDOs. We need some mark "abort this group" in the
+ log, or mark the table corrupted (then user will repair it and thus REDOs
+ will be skipped).
+
+ @todo RECOVERY to not let write errors go unnoticed, pagecache_write()
+ should take a MARIA_HA* in argument, and it it
+ fails when flushing a page to disk it should call
+ (*the_maria_ha->write_error_func)(the_maria_ha)
+ and this hook will mark the table corrupted.
+ Maybe hook should be stored in the pagecache's block structure, or in a
+ hash "file->maria_ha*".
+
+ @todo RECOVERY we should distinguish below between log write error and
+ table write error. The former should stop Maria immediately, the latter
+ should mark the table corrupted.
+ */
+ /*
+ Unpin all pinned pages to not cause problems for disk cache. This is
+ safe to call even if we already called _ma_unpin_all_pages() above.
+ */
+ save_my_errno= my_errno;
+ _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
+ my_errno= save_my_errno;
+ DBUG_RETURN(1);
+}
+
+
+/*
+ @brief Write a record
+
+ @fn allocate_and_write_block_record()
+ @param info Maria handler
+ @param record Record to write
+ @param row Information about fields in 'record'
+ @param undo_lsn <> LSN_ERROR if we are executing an UNDO
+
+ @return
+ @retval 0 ok
+ @retval 1 Error
+*/
+
+static my_bool allocate_and_write_block_record(MARIA_HA *info,
+ const uchar *record,
+ MARIA_ROW *row,
+ LSN undo_lsn)
+{
+ struct st_row_pos_info row_pos;
+ MARIA_BITMAP_BLOCKS *blocks= &row->insert_blocks;
+ int save_my_errno;
+ DBUG_ENTER("allocate_and_write_block_record");
+
+ _ma_bitmap_flushable(info, 1);
+ if (_ma_bitmap_find_place(info, row, blocks))
+ goto err; /* Error reading bitmap */
+
+ /*
+ Sleep; a checkpoint will happen and should not send this over-allocated
+ bitmap to disk but rather wait.
+ */
+ DBUG_EXECUTE_IF("maria_over_alloc_bitmap", sleep(10););
+
+ /* page will be pinned & locked by get_head_or_tail_page */
+ if (get_head_or_tail_page(info, blocks->block, info->buff,
+ row->space_on_head_page, HEAD_PAGE,
+ PAGECACHE_LOCK_WRITE, &row_pos))
+ goto err;
+ row->lastpos= ma_recordpos(blocks->block->page, row_pos.rownr);
+ if (info->s->calc_checksum)
+ {
+ if (undo_lsn == LSN_ERROR)
+ row->checksum= (info->s->calc_checksum)(info, record);
+ else
+ {
+ /* _ma_apply_undo_row_delete() already set row's checksum. Verify it. */
+ DBUG_ASSERT(row->checksum == (info->s->calc_checksum)(info, record));
+ }
+ }
+ if (write_block_record(info, (uchar*) 0, record, row,
+ blocks, blocks->block->org_bitmap_value != 0,
+ &row_pos, undo_lsn, 0))
+ goto err; /* Error reading bitmap */
+ DBUG_PRINT("exit", ("rowid: %lu (%lu:%u)", (ulong) row->lastpos,
+ (ulong) ma_recordpos_to_page(row->lastpos),
+ ma_recordpos_to_dir_entry(row->lastpos)));
+ /* Now let checkpoint happen but don't commit */
+ DBUG_EXECUTE_IF("maria_over_alloc_bitmap", sleep(1000););
+ DBUG_RETURN(0);
+
+err:
+ save_my_errno= my_errno;
+ if (info->non_flushable_state)
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
+ my_errno= save_my_errno;
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Write a record and return rowid for it
+
+ SYNOPSIS
+ _ma_write_init_block_record()
+ info Maria handler
+ record Record to write
+
+ NOTES
+ This is done BEFORE we write the keys to the row!
+
+ RETURN
+ HA_OFFSET_ERROR Something went wrong
+ # Rowid for row
+*/
+
+MARIA_RECORD_POS _ma_write_init_block_record(MARIA_HA *info,
+ const uchar *record)
+{
+ DBUG_ENTER("_ma_write_init_block_record");
+
+ calc_record_size(info, record, &info->cur_row);
+ if (allocate_and_write_block_record(info, record,
+ &info->cur_row, LSN_ERROR))
+ DBUG_RETURN(HA_OFFSET_ERROR);
+ DBUG_RETURN(info->cur_row.lastpos);
+}
+
+
+/*
+ Dummy function for (*info->s->write_record)()
+
+ Nothing to do here, as we already wrote the record in
+ _ma_write_init_block_record()
+*/
+
+my_bool _ma_write_block_record(MARIA_HA *info __attribute__ ((unused)),
+ const uchar *record __attribute__ ((unused)))
+{
+ return 0; /* Row already written */
+}
+
+
+/**
+ @brief Remove row written by _ma_write_block_record() and log undo
+
+ @param info Maria handler
+
+ @note
+ This is called in case we got a duplicate unique key while
+ writing keys.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool _ma_write_abort_block_record(MARIA_HA *info)
+{
+ my_bool res= 0;
+ MARIA_BITMAP_BLOCKS *blocks= &info->cur_row.insert_blocks;
+ MARIA_BITMAP_BLOCK *block, *end;
+ LSN lsn= LSN_IMPOSSIBLE;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_write_abort_block_record");
+
+ _ma_bitmap_flushable(info, 1);
+ if (delete_head_or_tail(info,
+ ma_recordpos_to_page(info->cur_row.lastpos),
+ ma_recordpos_to_dir_entry(info->cur_row.lastpos), 1,
+ 0))
+ res= 1;
+ for (block= blocks->block + 1, end= block + blocks->count - 1; block < end;
+ block++)
+ {
+ if (block->used & BLOCKUSED_USED)
+ {
+ if (block->used & BLOCKUSED_TAIL)
+ {
+ /*
+ block->page_count is set to the tail directory entry number in
+ write_block_record()
+ */
+ if (delete_head_or_tail(info, block->page,
+ block->page_count & ~TAIL_BIT,
+ 0, 0))
+ res= 1;
+ }
+ else
+ {
+ if (free_full_page_range(info, block->page, block->page_count))
+ res= 1;
+ }
+ }
+ }
+ if (share->now_transactional)
+ {
+ if (_ma_write_clr(info, info->cur_row.orig_undo_lsn,
+ LOGREC_UNDO_ROW_INSERT,
+ share->calc_checksum != 0,
+ (ha_checksum) 0 - info->cur_row.checksum,
+ &lsn, (void*) 0))
+ res= 1;
+ }
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Update a record
+
+ NOTES
+ For the moment, we assume that info->curr_row.extents is always updated
+ when a row is read. In the future we may decide to read this on demand
+ for rows split into many extents.
+*/
+
+static my_bool _ma_update_block_record2(MARIA_HA *info,
+ MARIA_RECORD_POS record_pos,
+ const uchar *oldrec,
+ const uchar *record,
+ LSN undo_lsn)
+{
+ MARIA_BITMAP_BLOCKS *blocks= &info->cur_row.insert_blocks;
+ uchar *buff;
+ MARIA_ROW *cur_row= &info->cur_row, *new_row= &info->new_row;
+ MARIA_PINNED_PAGE page_link;
+ uint rownr, org_empty_size, head_length;
+ uint block_size= info->s->block_size;
+ uchar *dir;
+ pgcache_page_no_t page;
+ struct st_row_pos_info row_pos;
+ my_bool res;
+ ha_checksum old_checksum;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_update_block_record2");
+ DBUG_PRINT("enter", ("rowid: %lu", (long) record_pos));
+
+#ifdef ENABLE_IF_PROBLEM_WITH_UPDATE
+ DBUG_DUMP("oldrec", oldrec, share->base.reclength);
+ DBUG_DUMP("newrec", record, share->base.reclength);
+#endif
+
+ /*
+ Checksums of new and old rows were computed by callers already; new
+ row's was put into cur_row, old row's was put into new_row.
+ */
+ old_checksum= new_row->checksum;
+ new_row->checksum= cur_row->checksum;
+ calc_record_size(info, record, new_row);
+ page= ma_recordpos_to_page(record_pos);
+
+ _ma_bitmap_flushable(info, 1);
+ buff= pagecache_read(share->pagecache,
+ &info->dfile, (pgcache_page_no_t) page, 0, 0,
+ share->page_type,
+ PAGECACHE_LOCK_WRITE, &page_link.link);
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= buff != 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ if (!buff)
+ goto err;
+
+ org_empty_size= uint2korr(buff + EMPTY_SPACE_OFFSET);
+ rownr= ma_recordpos_to_dir_entry(record_pos);
+ dir= dir_entry_pos(buff, block_size, rownr);
+
+ if ((org_empty_size + cur_row->head_length) >= new_row->total_length)
+ {
+ uint rec_offset, length;
+ MARIA_BITMAP_BLOCK block;
+
+ /*
+ We can fit the new row in the same page as the original head part
+ of the row
+ */
+ block.org_bitmap_value= _ma_free_size_to_head_pattern(&share->bitmap,
+ org_empty_size);
+ if (extend_area_on_page(info, buff, dir, rownr, block_size,
+ new_row->total_length, &org_empty_size,
+ &rec_offset, &length))
+ goto err;
+
+ row_pos.buff= buff;
+ row_pos.rownr= rownr;
+ row_pos.empty_space= org_empty_size;
+ row_pos.dir= dir;
+ row_pos.data= buff + rec_offset;
+ row_pos.length= length;
+ blocks->block= &block;
+ blocks->count= 1;
+ block.page= page;
+ block.sub_blocks= 1;
+ block.used= BLOCKUSED_USED | BLOCKUSED_USE_ORG_BITMAP;
+ block.empty_space= row_pos.empty_space;
+
+ if (*cur_row->tail_positions &&
+ delete_tails(info, cur_row->tail_positions))
+ goto err;
+ if (cur_row->extents_count && free_full_pages(info, cur_row))
+ goto err;
+ res= write_block_record(info, oldrec, record, new_row, blocks,
+ 1, &row_pos, undo_lsn, old_checksum);
+ /* We can't update or delete this without re-reading it again */
+ info->update&= ~HA_STATE_AKTIV;
+ DBUG_RETURN(res);
+ }
+ /* Delete old row */
+ if (*cur_row->tail_positions &&
+ delete_tails(info, cur_row->tail_positions))
+ goto err;
+ if (cur_row->extents_count && free_full_pages(info, cur_row))
+ goto err;
+
+ head_length= uint2korr(dir + 2);
+ if (_ma_bitmap_find_new_place(info, new_row, page, head_length +
+ org_empty_size, blocks))
+ goto err;
+
+ /*
+ Allocate all size in block for record
+ TODO:
+ Need to improve this to do compact if we can fit one more blob into
+ the head page
+ */
+ if ((head_length < new_row->space_on_head_page ||
+ (new_row->total_length <= head_length &&
+ org_empty_size + head_length >= new_row->total_length)))
+ {
+ _ma_compact_block_page(buff, block_size, rownr, 1,
+ info->trn->min_read_from,
+ share->base.min_block_length);
+ org_empty_size= 0;
+ head_length= uint2korr(dir + 2);
+ }
+
+ row_pos.buff= buff;
+ row_pos.rownr= rownr;
+ row_pos.empty_space= org_empty_size + head_length;
+ row_pos.dir= dir;
+ row_pos.data= buff + uint2korr(dir);
+ row_pos.length= head_length;
+ if ((res= write_block_record(info, oldrec, record, new_row, blocks, 1,
+ &row_pos, undo_lsn, old_checksum)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ if (info->non_flushable_state)
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
+ DBUG_RETURN(1);
+}
+
+
+/*
+ @brief Store new row on it's original position
+
+ @note
+ This is basicly a copy of _ma_update_block_record2
+ When we have a purge thread for deleted row, we can remove this function
+ and use _ma_update_block_record2 instead.
+
+ This is the main reason we don't make a lot of subfunctions that are
+ common between _ma_update_block_record2() and this function.
+*/
+
+static my_bool _ma_update_at_original_place(MARIA_HA *info,
+ pgcache_page_no_t page,
+ uint rownr,
+ uint length_on_head_page,
+ uint extent_count,
+ const uchar *extent_info,
+ const uchar *oldrec,
+ const uchar *record,
+ LSN undo_lsn)
+{
+ MARIA_BITMAP_BLOCKS *blocks;
+ MARIA_BITMAP_BLOCK *block;
+ MARIA_ROW *cur_row= &info->cur_row, *new_row= &info->new_row;
+ MARIA_PINNED_PAGE page_link;
+ MARIA_SHARE *share= info->s;
+ ha_checksum old_checksum;
+ uint org_empty_size, empty_size;
+ uint block_size= info->s->block_size;
+ uchar *dir, *buff;
+ struct st_row_pos_info row_pos;
+ my_bool res;
+ uint rec_offset, length;
+ DBUG_ENTER("_ma_update_at_original_place");
+
+#ifdef ENABLE_IF_PROBLEM_WITH_UPDATE
+ DBUG_DUMP("oldrec", oldrec, share->base.reclength);
+ DBUG_DUMP("newrec", record, share->base.reclength);
+#endif
+
+ /*
+ Checksums of new and old rows were computed by callers already; new
+ row's was put into cur_row, old row's was put into new_row.
+ */
+ old_checksum= new_row->checksum;
+ new_row->checksum= cur_row->checksum;
+ calc_record_size(info, record, new_row);
+
+ _ma_bitmap_flushable(info, 1);
+ buff= pagecache_read(share->pagecache,
+ &info->dfile, (pgcache_page_no_t) page, 0, 0,
+ share->page_type,
+ PAGECACHE_LOCK_WRITE, &page_link.link);
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= buff != 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ if (!buff)
+ goto err;
+
+ org_empty_size= uint2korr(buff + EMPTY_SPACE_OFFSET);
+ dir= dir_entry_pos(buff, block_size, rownr);
+
+ if ((org_empty_size + cur_row->head_length) < length_on_head_page)
+ {
+ my_errno= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+
+ /*
+ We can fit the new row in the same page as the original head part
+ of the row
+ */
+ empty_size= org_empty_size;
+ if (extend_area_on_page(info, buff, dir, rownr, block_size,
+ length_on_head_page, &empty_size,
+ &rec_offset, &length))
+ goto err;
+
+ row_pos.buff= buff;
+ row_pos.rownr= rownr;
+ row_pos.empty_space= empty_size;
+ row_pos.dir= dir;
+ row_pos.data= buff + rec_offset;
+ row_pos.length= length_on_head_page;
+
+ /* Delete old row */
+ if (*cur_row->tail_positions &&
+ delete_tails(info, cur_row->tail_positions))
+ goto err;
+ if (cur_row->extents_count && free_full_pages(info, cur_row))
+ goto err;
+
+ /* Change extent information to be usable by write_block_record() */
+ blocks= &cur_row->insert_blocks;
+ if (extent_to_bitmap_blocks(info, blocks, page, extent_count, extent_info))
+ goto err;
+ block= blocks->block;
+ block->empty_space= row_pos.empty_space;
+ block->org_bitmap_value= _ma_free_size_to_head_pattern(&share->bitmap,
+ org_empty_size);
+ DBUG_ASSERT(block->org_bitmap_value ==
+ _ma_bitmap_get_page_bits(info, &info->s->bitmap, page));
+ block->used|= BLOCKUSED_USE_ORG_BITMAP;
+
+ /*
+ We have to use <= below as the new_row may be smaller than the original
+ row as the new row doesn't have transaction id
+ */
+
+ DBUG_ASSERT(blocks->count > 1 ||
+ max(new_row->total_length, share->base.min_block_length) <=
+ length_on_head_page);
+
+ if ((res= write_block_record(info, oldrec, record, new_row, blocks,
+ 1, &row_pos, undo_lsn, old_checksum)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ if (info->non_flushable_state)
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
+ DBUG_RETURN(1);
+}
+
+
+/* Wrapper for _ma_update_block_record2() used by ma_update() */
+
+my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos,
+ const uchar *orig_rec, const uchar *new_rec)
+{
+ return _ma_update_block_record2(info, record_pos, orig_rec, new_rec,
+ LSN_ERROR);
+}
+
+
+/*
+ Delete a directory entry
+
+ SYNOPSIS
+ delete_dir_entry()
+ buff Page buffer
+ block_size Block size
+ record_number Record number to delete
+ empty_space Empty space on page after delete
+
+ RETURN
+ -1 Error on page
+ 0 ok
+ 1 Page is now empty
+*/
+
+static int delete_dir_entry(uchar *buff, uint block_size, uint record_number,
+ uint *empty_space_res)
+{
+ uint number_of_records= (uint) buff[DIR_COUNT_OFFSET];
+ uint length, empty_space;
+ uchar *dir;
+ DBUG_ENTER("delete_dir_entry");
+
+#ifdef SANITY_CHECKS
+ if (record_number >= number_of_records ||
+ record_number > ((block_size - LSN_SIZE - PAGE_TYPE_SIZE - 1 -
+ PAGE_SUFFIX_SIZE) / DIR_ENTRY_SIZE))
+ {
+ DBUG_PRINT("error", ("record_number: %u number_of_records: %u",
+ record_number, number_of_records));
+
+ DBUG_RETURN(-1);
+ }
+#endif
+
+ check_directory(buff, block_size, 0);
+ empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
+ dir= dir_entry_pos(buff, block_size, record_number);
+ length= uint2korr(dir + 2);
+
+ if (record_number == number_of_records - 1)
+ {
+ /* Delete this entry and all following free directory entries */
+ uchar *end= buff + block_size - PAGE_SUFFIX_SIZE;
+ number_of_records--;
+ dir+= DIR_ENTRY_SIZE;
+ empty_space+= DIR_ENTRY_SIZE;
+
+ /* Unlink and free the next empty ones */
+ while (dir < end && dir[0] == 0 && dir[1] == 0)
+ {
+ number_of_records--;
+ if (dir[2] == END_OF_DIR_FREE_LIST)
+ buff[DIR_FREE_OFFSET]= dir[3];
+ else
+ {
+ uchar *prev_entry= dir_entry_pos(buff, block_size, (uint) dir[2]);
+ DBUG_ASSERT(uint2korr(prev_entry) == 0 && prev_entry[3] ==
+ number_of_records);
+ prev_entry[3]= dir[3];
+ }
+ if (dir[3] != END_OF_DIR_FREE_LIST)
+ {
+ uchar *next_entry= dir_entry_pos(buff, block_size, (uint) dir[3]);
+ DBUG_ASSERT(uint2korr(next_entry) == 0 && next_entry[2] ==
+ number_of_records);
+ next_entry[2]= dir[2];
+ }
+ dir+= DIR_ENTRY_SIZE;
+ empty_space+= DIR_ENTRY_SIZE;
+ }
+
+ if (number_of_records == 0)
+ {
+ /* All entries on page deleted */
+ DBUG_PRINT("info", ("Page marked as unallocated"));
+ buff[PAGE_TYPE_OFFSET]= UNALLOCATED_PAGE;
+#ifdef IDENTICAL_PAGES_AFTER_RECOVERY
+ {
+ dir= dir_entry_pos(buff, block_size, record_number);
+ bzero(dir, (record_number+1) * DIR_ENTRY_SIZE);
+ }
+#endif
+ *empty_space_res= block_size;
+ DBUG_RETURN(1);
+ }
+ buff[DIR_COUNT_OFFSET]= (uchar) number_of_records;
+ }
+ else
+ {
+ /* Update directory */
+ dir[0]= dir[1]= 0;
+ dir[2]= END_OF_DIR_FREE_LIST;
+ if ((dir[3]= buff[DIR_FREE_OFFSET]) != END_OF_DIR_FREE_LIST)
+ {
+ /* Relink next entry to point to newly freed entry */
+ uchar *next_entry= dir_entry_pos(buff, block_size, (uint) dir[3]);
+ DBUG_ASSERT(uint2korr(next_entry) == 0 &&
+ next_entry[2] == END_OF_DIR_FREE_LIST);
+ next_entry[2]= record_number;
+ }
+ buff[DIR_FREE_OFFSET]= record_number;
+ }
+ empty_space+= length;
+
+ int2store(buff + EMPTY_SPACE_OFFSET, empty_space);
+ buff[PAGE_TYPE_OFFSET]|= (uchar) PAGE_CAN_BE_COMPACTED;
+
+ *empty_space_res= empty_space;
+
+ check_directory(buff, block_size, 0);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Delete a head a tail part
+
+ SYNOPSIS
+ delete_head_or_tail()
+ info Maria handler
+ page Page (not file offset!) on which the row is
+ head 1 if this is a head page
+ from_update 1 if we are called from update. In this case we
+ leave the page as write locked as we may put
+ the new row into the old position.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool delete_head_or_tail(MARIA_HA *info,
+ pgcache_page_no_t page, uint record_number,
+ my_bool head, my_bool from_update)
+{
+ MARIA_SHARE *share= info->s;
+ uint empty_space;
+ uint block_size= share->block_size;
+ uchar *buff;
+ LSN lsn;
+ MARIA_PINNED_PAGE page_link;
+ int res;
+ enum pagecache_page_lock lock_at_write, lock_at_unpin;
+ DBUG_ENTER("delete_head_or_tail");
+ DBUG_PRINT("enter", ("id: %lu (%lu:%u)",
+ (ulong) ma_recordpos(page, record_number),
+ (ulong) page, record_number));
+
+ buff= pagecache_read(share->pagecache,
+ &info->dfile, page, 0, 0,
+ share->page_type,
+ PAGECACHE_LOCK_WRITE, &page_link.link);
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= buff != 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ if (!buff)
+ DBUG_RETURN(1);
+ DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) ==
+ (head ? HEAD_PAGE : TAIL_PAGE));
+
+ if (from_update)
+ {
+ lock_at_write= PAGECACHE_LOCK_LEFT_WRITELOCKED;
+ lock_at_unpin= PAGECACHE_LOCK_WRITE_UNLOCK;
+ }
+ else
+ {
+ lock_at_write= PAGECACHE_LOCK_WRITE_TO_READ;
+ lock_at_unpin= PAGECACHE_LOCK_READ_UNLOCK;
+ }
+
+ res= delete_dir_entry(buff, block_size, record_number, &empty_space);
+ if (res < 0)
+ DBUG_RETURN(1);
+ if (res == 0) /* after our deletion, page is still not empty */
+ {
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ if (share->now_transactional)
+ {
+ /* Log REDO data */
+ page_store(log_data + FILEID_STORE_SIZE, page);
+ dirpos_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE,
+ record_number);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ if (translog_write_record(&lsn, (head ? LOGREC_REDO_PURGE_ROW_HEAD :
+ LOGREC_REDO_PURGE_ROW_TAIL),
+ info->trn, info,
+ (translog_size_t) sizeof(log_data),
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data, NULL))
+ DBUG_RETURN(1);
+ }
+ }
+ else /* page is now empty */
+ {
+ if (share->now_transactional)
+ {
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ page_store(log_data + FILEID_STORE_SIZE, page);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ if (translog_write_record(&lsn, LOGREC_REDO_FREE_HEAD_OR_TAIL,
+ info->trn, info,
+ (translog_size_t) sizeof(log_data),
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data, NULL))
+ DBUG_RETURN(1);
+ }
+ DBUG_ASSERT(empty_space >= share->bitmap.sizes[0]);
+ }
+
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ lock_at_write,
+ PAGECACHE_PIN_LEFT_PINNED, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 1, FALSE);
+ page_link.unlock= lock_at_unpin;
+ set_dynamic(&info->pinned_pages, (void*) &page_link,
+ info->pinned_pages.elements-1);
+
+ DBUG_PRINT("info", ("empty_space: %u", empty_space));
+
+ /*
+ If there is not enough space for all possible tails, mark the
+ page full
+ */
+ if (!head && !enough_free_entries(buff, share->block_size,
+ 1 + share->base.blobs))
+ empty_space= 0;
+
+ DBUG_RETURN(_ma_bitmap_set(info, page, head, empty_space));
+}
+
+
+/*
+ delete all tails
+
+ SYNOPSIS
+ delete_tails()
+ info Handler
+ tails Pointer to vector of tail positions, ending with 0
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool delete_tails(MARIA_HA *info, MARIA_RECORD_POS *tails)
+{
+ my_bool res= 0;
+ DBUG_ENTER("delete_tails");
+ for (; *tails; tails++)
+ {
+ if (delete_head_or_tail(info,
+ ma_recordpos_to_page(*tails),
+ ma_recordpos_to_dir_entry(*tails), 0, 1))
+ res= 1;
+ }
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Delete a record
+
+ NOTES
+ For the moment, we assume that info->cur_row.extents is always updated
+ when a row is read. In the future we may decide to read this on demand
+ for rows with many splits.
+*/
+
+my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record)
+{
+ pgcache_page_no_t page;
+ uint record_number;
+ MARIA_SHARE *share= info->s;
+ LSN lsn= LSN_IMPOSSIBLE;
+ DBUG_ENTER("_ma_delete_block_record");
+
+ page= ma_recordpos_to_page(info->cur_row.lastpos);
+ record_number= ma_recordpos_to_dir_entry(info->cur_row.lastpos);
+ DBUG_PRINT("enter", ("rowid: %lu (%lu:%u)", (ulong) info->cur_row.lastpos,
+ (ulong) page, record_number));
+
+ _ma_bitmap_flushable(info, 1);
+ if (delete_head_or_tail(info, page, record_number, 1, 0) ||
+ delete_tails(info, info->cur_row.tail_positions))
+ goto err;
+
+ if (info->cur_row.extents_count && free_full_pages(info, &info->cur_row))
+ goto err;
+
+ if (share->now_transactional)
+ {
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE +
+ DIRPOS_STORE_SIZE + 2 + PAGERANGE_STORE_SIZE +
+ HA_CHECKSUM_STORE_SIZE];
+ uchar *log_pos;
+ size_t row_length;
+ uint row_parts_count, extents_length;
+ ha_checksum checksum_delta;
+
+ /* Write UNDO record */
+ lsn_store(log_data, info->trn->undo_lsn);
+ page_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE, page);
+ log_pos= log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE;
+ dirpos_store(log_pos, record_number);
+ log_pos+= DIRPOS_STORE_SIZE;
+ int2store(log_pos, info->cur_row.head_length);
+ log_pos+= 2;
+ pagerange_store(log_pos, info->cur_row.extents_count);
+ log_pos+= PAGERANGE_STORE_SIZE;
+
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS].str= log_data;
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS].length=
+ sizeof(log_data) - HA_CHECKSUM_STORE_SIZE;
+ store_checksum_in_rec(share, checksum_delta,
+ (ha_checksum) 0 - info->cur_row.checksum, log_pos,
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS +
+ 0].length);
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS+1].str=
+ info->cur_row.extents;
+ info->log_row_parts[TRANSLOG_INTERNAL_PARTS+1].length=
+ extents_length= info->cur_row.extents_count * ROW_EXTENT_SIZE;
+
+ row_length= fill_insert_undo_parts(info, record,
+ (info->log_row_parts +
+ TRANSLOG_INTERNAL_PARTS + 2),
+ &row_parts_count);
+
+ if (translog_write_record(&lsn, LOGREC_UNDO_ROW_DELETE, info->trn,
+ info,
+ (translog_size_t)
+ (info->log_row_parts[TRANSLOG_INTERNAL_PARTS +
+ 0].length + row_length +
+ extents_length),
+ TRANSLOG_INTERNAL_PARTS + 2 + row_parts_count,
+ info->log_row_parts,
+ log_data + LSN_STORE_SIZE,
+ &checksum_delta))
+ goto err;
+ }
+
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+ DBUG_RETURN(0);
+
+err:
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
+ DBUG_RETURN(1);
+}
+
+
+/****************************************************************************
+ Reading of records
+****************************************************************************/
+
+/*
+ Read position to record from record directory at end of page
+
+ SYNOPSIS
+ get_record_position()
+ buff page buffer
+ block_size block size for page
+ record_number Record number in index
+ end_of_data pointer to end of data for record
+
+ RETURN
+ 0 Error in data
+ # Pointer to start of record.
+ In this case *end_of_data is set.
+*/
+
+static uchar *get_record_position(uchar *buff, uint block_size,
+ uint record_number, uchar **end_of_data)
+{
+ uint number_of_records= (uint) buff[DIR_COUNT_OFFSET];
+ uchar *dir;
+ uchar *data;
+ uint offset, length;
+
+#ifdef SANITY_CHECKS
+ if (record_number >= number_of_records ||
+ record_number > ((block_size - PAGE_HEADER_SIZE - PAGE_SUFFIX_SIZE) /
+ DIR_ENTRY_SIZE))
+ {
+ DBUG_PRINT("error",
+ ("Wrong row number: record_number: %u number_of_records: %u",
+ record_number, number_of_records));
+ return 0;
+ }
+#endif
+
+ dir= dir_entry_pos(buff, block_size, record_number);
+ offset= uint2korr(dir);
+ length= uint2korr(dir + 2);
+#ifdef SANITY_CHECKS
+ if (offset < PAGE_HEADER_SIZE ||
+ offset + length > (block_size -
+ number_of_records * DIR_ENTRY_SIZE -
+ PAGE_SUFFIX_SIZE))
+ {
+ DBUG_PRINT("error",
+ ("Wrong row position: record_number: %u offset: %u "
+ "length: %u number_of_records: %u",
+ record_number, offset, length, number_of_records));
+ return 0;
+ }
+#endif
+ data= buff + offset;
+ *end_of_data= data + length;
+ return data;
+}
+
+
+/*
+ Init extent
+
+ NOTES
+ extent is a cursor over which pages to read
+*/
+
+static void init_extent(MARIA_EXTENT_CURSOR *extent, uchar *extent_info,
+ uint extents, MARIA_RECORD_POS *tail_positions)
+{
+ uint page_count;
+ extent->extent= extent_info;
+ extent->extent_count= extents;
+ extent->page= page_korr(extent_info); /* First extent */
+ page_count= (uint2korr(extent_info + ROW_EXTENT_PAGE_SIZE) &
+ ~START_EXTENT_BIT);
+ extent->tail= page_count & TAIL_BIT;
+ if (extent->tail)
+ {
+ extent->page_count= 1;
+ extent->tail_row_nr= page_count & ~TAIL_BIT;
+ }
+ else
+ extent->page_count= page_count;
+ extent->tail_positions= tail_positions;
+ extent->lock_for_tail_pages= PAGECACHE_LOCK_LEFT_UNLOCKED;
+}
+
+
+/*
+ Read next extent
+
+ SYNOPSIS
+ read_next_extent()
+ info Maria handler
+ extent Pointer to current extent (this is updated to point
+ to next)
+ end_of_data Pointer to end of data in read block (out)
+
+ NOTES
+ New block is read into info->buff
+
+ RETURN
+ 0 Error; my_errno is set
+ # Pointer to start of data in read block
+ In this case end_of_data is updated to point to end of data.
+*/
+
+static uchar *read_next_extent(MARIA_HA *info, MARIA_EXTENT_CURSOR *extent,
+ uchar **end_of_data)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *buff, *data;
+ MARIA_PINNED_PAGE page_link;
+ enum pagecache_page_lock lock;
+ DBUG_ENTER("read_next_extent");
+
+ if (!extent->page_count)
+ {
+ uint page_count;
+ if (!--extent->extent_count)
+ goto crashed;
+ extent->extent+= ROW_EXTENT_SIZE;
+ extent->page= page_korr(extent->extent);
+ page_count= (uint2korr(extent->extent+ROW_EXTENT_PAGE_SIZE) &
+ ~START_EXTENT_BIT);
+ if (!page_count)
+ goto crashed;
+ extent->tail= page_count & TAIL_BIT;
+ if (extent->tail)
+ extent->tail_row_nr= page_count & ~TAIL_BIT;
+ else
+ extent->page_count= page_count;
+ DBUG_PRINT("info",("New extent. Page: %lu page_count: %u tail_flag: %d",
+ (ulong) extent->page, extent->page_count,
+ extent->tail != 0));
+ }
+ extent->first_extent= 0;
+
+ lock= PAGECACHE_LOCK_LEFT_UNLOCKED;
+ if (extent->tail)
+ lock= extent->lock_for_tail_pages;
+
+ buff= pagecache_read(share->pagecache,
+ &info->dfile, extent->page, 0,
+ info->buff, share->page_type,
+ lock, &page_link.link);
+ if (lock != PAGECACHE_LOCK_LEFT_UNLOCKED)
+ {
+ /* Read during UNDO */
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= buff != 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ }
+ if (!buff)
+ {
+ /* check if we tried to read over end of file (ie: bad data in record) */
+ if ((extent->page + 1) * share->block_size >
+ share->state.state.data_file_length)
+ goto crashed;
+ DBUG_RETURN(0);
+ }
+
+ if (!extent->tail)
+ {
+ /* Full data page */
+ if ((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) != BLOB_PAGE)
+ goto crashed;
+ extent->page++; /* point to next page */
+ extent->page_count--;
+ *end_of_data= buff + share->block_size - PAGE_SUFFIX_SIZE;
+ info->cur_row.full_page_count++; /* For maria_chk */
+ DBUG_RETURN(extent->data_start= buff + LSN_SIZE + PAGE_TYPE_SIZE);
+ }
+
+ /* Found tail */
+ if ((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) != TAIL_PAGE)
+ goto crashed;
+ *(extent->tail_positions++)= ma_recordpos(extent->page,
+ extent->tail_row_nr);
+ info->cur_row.tail_count++; /* For maria_chk */
+
+ if (!(data= get_record_position(buff, share->block_size,
+ extent->tail_row_nr,
+ end_of_data)))
+ goto crashed;
+ extent->data_start= data;
+ extent->page_count= 0; /* No more data in extent */
+ DBUG_RETURN(data);
+
+
+crashed:
+ my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */
+ DBUG_PRINT("error", ("wrong extent information"));
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Read data that may be split over many blocks
+
+ SYNOPSIS
+ read_long_data()
+ info Maria handler
+ to Store result string here (this is allocated)
+ extent Pointer to current extent position
+ data Current position in buffer
+ end_of_data End of data in buffer
+
+ NOTES
+ When we have to read a new buffer, it's read into info->buff
+
+ This loop is implemented by goto's instead of a for() loop as
+ the code is notable smaller and faster this way (and it's not nice
+ to jump into a for loop() or into a 'then' clause)
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static my_bool read_long_data(MARIA_HA *info, uchar *to, ulong length,
+ MARIA_EXTENT_CURSOR *extent,
+ uchar **data, uchar **end_of_data)
+{
+ DBUG_ENTER("read_long_data");
+ DBUG_PRINT("enter", ("length: %lu left_length: %u",
+ length, (uint) (*end_of_data - *data)));
+ DBUG_ASSERT(*data <= *end_of_data);
+
+ /*
+ Fields are never split in middle. This means that if length > rest-of-data
+ we should start reading from the next extent. The reason we may have
+ data left on the page is that if the fixed part of the row was less than
+ min_block_length the head block was extended to min_block_length.
+
+ This may change in the future, which is why we have the loop written
+ the way it's written.
+ */
+ if (extent->first_extent && length > (ulong) (*end_of_data - *data))
+ *end_of_data= *data;
+
+ for(;;)
+ {
+ uint left_length;
+ left_length= (uint) (*end_of_data - *data);
+ if (likely(left_length >= length))
+ {
+ memcpy(to, *data, length);
+ (*data)+= length;
+ DBUG_PRINT("info", ("left_length: %u", left_length - (uint) length));
+ DBUG_RETURN(0);
+ }
+ memcpy(to, *data, left_length);
+ to+= left_length;
+ length-= left_length;
+ if (!(*data= read_next_extent(info, extent, end_of_data)))
+ break;
+ }
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Read a record from page (helper function for _ma_read_block_record())
+
+ SYNOPSIS
+ _ma_read_block_record2()
+ info Maria handler
+ record Store record here
+ data Start of head data for row
+ end_of_data End of data for row
+
+ NOTES
+ The head page is already read by caller
+ Following data is update in info->cur_row:
+
+ cur_row.head_length is set to size of entry in head block
+ cur_row.tail_positions is set to point to all tail blocks
+ cur_row.extents points to extents data
+ cur_row.extents_counts contains number of extents
+ cur_row.empty_bits is set to empty bits
+ cur_row.field_lengths contains packed length of all fields
+ cur_row.blob_length contains total length of all blobs
+ cur_row.checksum contains checksum of read record.
+
+ RETURN
+ 0 ok
+ # Error code
+*/
+
+int _ma_read_block_record2(MARIA_HA *info, uchar *record,
+ uchar *data, uchar *end_of_data)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *field_length_data, *blob_buffer, *start_of_data;
+ uint flag, null_bytes, cur_null_bytes, row_extents, field_lengths;
+ my_bool found_blob= 0;
+ MARIA_EXTENT_CURSOR extent;
+ MARIA_COLUMNDEF *column, *end_column;
+ MARIA_ROW *cur_row= &info->cur_row;
+ DBUG_ENTER("_ma_read_block_record2");
+
+ LINT_INIT(field_length_data);
+ LINT_INIT(blob_buffer);
+
+ start_of_data= data;
+ flag= (uint) (uchar) data[0];
+ cur_null_bytes= share->base.original_null_bytes;
+ null_bytes= share->base.null_bytes;
+ cur_row->head_length= (uint) (end_of_data - data);
+ cur_row->full_page_count= cur_row->tail_count= 0;
+ cur_row->blob_length= 0;
+
+ if (flag & ROW_FLAG_TRANSID)
+ {
+ cur_row->trid= transid_korr(data+1);
+ if (!info->trn)
+ DBUG_RETURN(my_errno= HA_ERR_WRONG_IN_RECORD); /* File crashed */
+ if (!trnman_can_read_from(info->trn, cur_row->trid))
+ DBUG_RETURN(my_errno= HA_ERR_ROW_NOT_VISIBLE);
+ }
+
+ /* Skip trans header (for now, until we have MVCC csupport) */
+ data+= total_header_size[(flag & PRECALC_HEADER_BITMASK)];
+ if (flag & ROW_FLAG_NULLS_EXTENDED)
+ cur_null_bytes+= data[-1];
+
+ row_extents= 0;
+ if (flag & ROW_FLAG_EXTENTS)
+ {
+ uint row_extent_size;
+ /*
+ Record is split over many data pages.
+ Get number of extents and first extent
+ */
+ get_key_length(row_extents, data);
+ cur_row->extents_count= row_extents;
+ row_extent_size= row_extents * ROW_EXTENT_SIZE;
+ if (cur_row->extents_buffer_length < row_extent_size &&
+ _ma_alloc_buffer(&cur_row->extents,
+ &cur_row->extents_buffer_length,
+ row_extent_size))
+ DBUG_RETURN(my_errno);
+ memcpy(cur_row->extents, data, ROW_EXTENT_SIZE);
+ data+= ROW_EXTENT_SIZE;
+ init_extent(&extent, cur_row->extents, row_extents,
+ cur_row->tail_positions);
+ }
+ else
+ {
+ cur_row->extents_count= 0;
+ (*cur_row->tail_positions)= 0;
+ extent.page_count= 0;
+ extent.extent_count= 1;
+ }
+ extent.first_extent= 1;
+
+ field_lengths= 0;
+ if (share->base.max_field_lengths)
+ {
+ get_key_length(field_lengths, data);
+ cur_row->field_lengths_length= field_lengths;
+#ifdef SANITY_CHECKS
+ if (field_lengths > share->base.max_field_lengths)
+ goto err;
+#endif
+ }
+
+ if (share->calc_checksum)
+ cur_row->checksum= (uint) (uchar) *data++;
+ /* data now points on null bits */
+ memcpy(record, data, cur_null_bytes);
+ if (unlikely(cur_null_bytes != null_bytes))
+ {
+ /*
+ This only happens if we have added more NULL columns with
+ ALTER TABLE and are fetching an old, not yet modified old row
+ */
+ bzero(record + cur_null_bytes, (uint) (null_bytes - cur_null_bytes));
+ }
+ data+= null_bytes;
+ /* We copy the empty bits to be able to use them for delete/update */
+ memcpy(cur_row->empty_bits, data, share->base.pack_bytes);
+ data+= share->base.pack_bytes;
+
+ /* TODO: Use field offsets, instead of just skipping them */
+ data+= share->base.field_offsets * FIELD_OFFSET_SIZE;
+
+ /*
+ Read row extents (note that first extent was already read into
+ cur_row->extents above)
+ */
+ if (row_extents > 1)
+ {
+ if (read_long_data(info, cur_row->extents + ROW_EXTENT_SIZE,
+ (row_extents - 1) * ROW_EXTENT_SIZE,
+ &extent, &data, &end_of_data))
+ DBUG_RETURN(my_errno);
+ }
+
+ /*
+ Data now points to start of fixed length field data that can't be null
+ or 'empty'. Note that these fields can't be split over blocks.
+ */
+ for (column= share->columndef,
+ end_column= column + share->base.fixed_not_null_fields;
+ column < end_column; column++)
+ {
+ uint column_length= column->length;
+ if (data + column_length > end_of_data &&
+ !(data= read_next_extent(info, &extent, &end_of_data)))
+ goto err;
+ memcpy(record + column->offset, data, column_length);
+ data+= column_length;
+ }
+
+ /* Read array of field lengths. This may be stored in several extents */
+ if (field_lengths)
+ {
+ field_length_data= cur_row->field_lengths;
+ if (read_long_data(info, field_length_data, field_lengths, &extent,
+ &data, &end_of_data))
+ DBUG_RETURN(my_errno);
+ }
+
+ /* Read variable length data. Each of these may be split over many extents */
+ for (end_column= share->columndef + share->base.fields;
+ column < end_column; column++)
+ {
+ enum en_fieldtype type= column->type;
+ uchar *field_pos= record + column->offset;
+ /* First check if field is present in record */
+ if ((record[column->null_pos] & column->null_bit) ||
+ (cur_row->empty_bits[column->empty_pos] & column->empty_bit))
+ {
+ bfill(record + column->offset, column->fill_length,
+ type == FIELD_SKIP_ENDSPACE ? ' ' : 0);
+ continue;
+ }
+ switch (type) {
+ case FIELD_NORMAL: /* Fixed length field */
+ case FIELD_SKIP_PRESPACE:
+ case FIELD_SKIP_ZERO: /* Fixed length field */
+ if (data + column->length > end_of_data &&
+ !(data= read_next_extent(info, &extent, &end_of_data)))
+ goto err;
+ memcpy(field_pos, data, column->length);
+ data+= column->length;
+ break;
+ case FIELD_SKIP_ENDSPACE: /* CHAR */
+ {
+ /* Char that is space filled */
+ uint length;
+ if (column->length <= 255)
+ length= (uint) (uchar) *field_length_data++;
+ else
+ {
+ length= uint2korr(field_length_data);
+ field_length_data+= 2;
+ }
+#ifdef SANITY_CHECKS
+ if (length > column->length)
+ goto err;
+#endif
+ if (read_long_data(info, field_pos, length, &extent, &data,
+ &end_of_data))
+ DBUG_RETURN(my_errno);
+ bfill(field_pos + length, column->length - length, ' ');
+ break;
+ }
+ case FIELD_VARCHAR:
+ {
+ ulong length;
+ if (column->length <= 256)
+ {
+ length= (uint) (uchar) (*field_pos++= *field_length_data++);
+ }
+ else
+ {
+ length= uint2korr(field_length_data);
+ field_pos[0]= field_length_data[0];
+ field_pos[1]= field_length_data[1];
+ field_pos+= 2;
+ field_length_data+= 2;
+ }
+#ifdef SANITY_CHECKS
+ if (length > column->length)
+ goto err;
+#endif
+ if (read_long_data(info, field_pos, length, &extent, &data,
+ &end_of_data))
+ DBUG_RETURN(my_errno);
+ break;
+ }
+ case FIELD_BLOB:
+ {
+ uint column_size_length= column->length - portable_sizeof_char_ptr;
+ ulong blob_length= _ma_calc_blob_length(column_size_length,
+ field_length_data);
+
+ if (!found_blob)
+ {
+ /* Calculate total length for all blobs */
+ ulong blob_lengths= 0;
+ uchar *length_data= field_length_data;
+ MARIA_COLUMNDEF *blob_field= column;
+
+ found_blob= 1;
+ for (; blob_field < end_column; blob_field++)
+ {
+ uint size_length;
+ if ((record[blob_field->null_pos] & blob_field->null_bit) ||
+ (cur_row->empty_bits[blob_field->empty_pos] &
+ blob_field->empty_bit))
+ continue;
+ size_length= blob_field->length - portable_sizeof_char_ptr;
+ blob_lengths+= _ma_calc_blob_length(size_length, length_data);
+ length_data+= size_length;
+ }
+ cur_row->blob_length= blob_lengths;
+ DBUG_PRINT("info", ("Total blob length: %lu", blob_lengths));
+ if (_ma_alloc_buffer(&info->blob_buff, &info->blob_buff_size,
+ blob_lengths))
+ DBUG_RETURN(my_errno);
+ blob_buffer= info->blob_buff;
+ }
+
+ memcpy(field_pos, field_length_data, column_size_length);
+ memcpy_fixed(field_pos + column_size_length, (uchar *) &blob_buffer,
+ sizeof(char*));
+ field_length_data+= column_size_length;
+
+ /*
+ After we have read one extent, then each blob is in it's own extent
+ */
+ if (!extent.first_extent || (ulong) (end_of_data - data) < blob_length)
+ end_of_data= data; /* Force read of next extent */
+
+ if (read_long_data(info, blob_buffer, blob_length, &extent, &data,
+ &end_of_data))
+ DBUG_RETURN(my_errno);
+ blob_buffer+= blob_length;
+ break;
+ }
+ default:
+#ifdef EXTRA_DEBUG
+ DBUG_ASSERT(0); /* purecov: deadcode */
+#endif
+ goto err;
+ }
+ continue;
+ }
+
+ if (row_extents)
+ {
+ DBUG_PRINT("info", ("Row read: page_count: %u extent_count: %u",
+ extent.page_count, extent.extent_count));
+ *extent.tail_positions= 0; /* End marker */
+ if (extent.page_count)
+ goto err;
+ if (extent.extent_count > 1)
+ {
+ if (_ma_check_if_zero(extent.extent + ROW_EXTENT_SIZE,
+ (extent.extent_count-1) * ROW_EXTENT_SIZE))
+ {
+ DBUG_PRINT("error", ("Data in extent is not zero"));
+ DBUG_DUMP("extent", extent.extent + ROW_EXTENT_SIZE,
+ (extent.extent_count-1) * ROW_EXTENT_SIZE);
+ goto err;
+ }
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Row read"));
+ /*
+ data should normally point to end_of_date. The only exception is if
+ the row is very short in which case we allocated 'min_block_length' data
+ for allowing the row to expand.
+ */
+ if (data != end_of_data && (uint) (end_of_data - start_of_data) >
+ share->base.min_block_length)
+ goto err;
+ }
+#ifdef EXTRA_DEBUG
+ if (share->calc_checksum)
+ {
+ /* Esnure that row checksum is correct */
+ DBUG_ASSERT(((share->calc_checksum)(info, record) & 255) ==
+ cur_row->checksum);
+ }
+#endif
+ info->update|= HA_STATE_AKTIV; /* We have an active record */
+ DBUG_RETURN(0);
+
+err:
+ /* Something was wrong with data on record */
+ DBUG_PRINT("error", ("Found record with wrong data"));
+ DBUG_RETURN((my_errno= HA_ERR_WRONG_IN_RECORD));
+}
+
+
+/** @brief Read positions to tail blocks and full blocks
+
+ @fn read_row_extent_info()
+ @param info Handler
+
+ @notes
+ This function is a simpler version of _ma_read_block_record2()
+ The data about the used pages is stored in info->cur_row.
+
+ @return Status
+ @retval 0 ok
+ @retval 1 Error. my_errno contains error number
+*/
+
+static my_bool read_row_extent_info(MARIA_HA *info, uchar *buff,
+ uint record_number)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_EXTENT_CURSOR extent;
+ MARIA_RECORD_POS *tail_pos;
+ uchar *data, *end_of_data;
+ uint flag, row_extents, row_extents_size, field_lengths;
+ uchar *extents, *end;
+ DBUG_ENTER("read_row_extent_info");
+
+ if (!(data= get_record_position(buff, share->block_size,
+ record_number, &end_of_data)))
+ DBUG_RETURN(1); /* Wrong in record */
+
+ flag= (uint) (uchar) data[0];
+ /* Skip trans header */
+ data+= total_header_size[(flag & PRECALC_HEADER_BITMASK)];
+
+ row_extents= 0;
+ row_extents_size= 0;
+ if (flag & ROW_FLAG_EXTENTS)
+ {
+ /*
+ Record is split over many data pages.
+ Get number of extents and first extent
+ */
+ get_key_length(row_extents, data);
+ row_extents_size= row_extents * ROW_EXTENT_SIZE;
+ if (info->cur_row.extents_buffer_length < row_extents_size &&
+ _ma_alloc_buffer(&info->cur_row.extents,
+ &info->cur_row.extents_buffer_length,
+ row_extents_size))
+ DBUG_RETURN(1);
+ memcpy(info->cur_row.extents, data, ROW_EXTENT_SIZE);
+ data+= ROW_EXTENT_SIZE;
+ init_extent(&extent, info->cur_row.extents, row_extents,
+ info->cur_row.tail_positions);
+ extent.first_extent= 1;
+ }
+ info->cur_row.extents_count= row_extents;
+
+ if (share->base.max_field_lengths)
+ get_key_length(field_lengths, data);
+
+ if (share->calc_checksum)
+ info->cur_row.checksum= (uint) (uchar) *data++;
+ if (row_extents > 1)
+ {
+ data+= share->base.null_bytes;
+ data+= share->base.pack_bytes;
+ data+= share->base.field_offsets * FIELD_OFFSET_SIZE;
+
+ /*
+ Read row extents (note that first extent was already read into
+ info->cur_row.extents above)
+ Lock tails with write lock as we will delete them later.
+ */
+ extent.lock_for_tail_pages= PAGECACHE_LOCK_LEFT_WRITELOCKED;
+ if (read_long_data(info, info->cur_row.extents + ROW_EXTENT_SIZE,
+ row_extents_size - ROW_EXTENT_SIZE,
+ &extent, &data, &end_of_data))
+ DBUG_RETURN(1);
+ }
+
+ /* Update tail_positions with pointer to tails */
+ tail_pos= info->cur_row.tail_positions;
+ for (extents= info->cur_row.extents, end= extents + row_extents_size;
+ extents < end;
+ extents+= ROW_EXTENT_SIZE)
+ {
+ pgcache_page_no_t page= uint5korr(extents);
+ uint page_count= uint2korr(extents + ROW_EXTENT_PAGE_SIZE);
+ if (page_count & TAIL_BIT)
+ *(tail_pos++)= ma_recordpos(page, (page_count & ~ (TAIL_BIT |
+ START_EXTENT_BIT)));
+ }
+ *tail_pos= 0; /* End marker */
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Read a record based on record position
+
+ @fn _ma_read_block_record()
+ @param info Maria handler
+ @param record Store record here
+ @param record_pos Record position
+
+ @return Status
+ @retval 0 ok
+ @retval # Error number
+*/
+
+int _ma_read_block_record(MARIA_HA *info, uchar *record,
+ MARIA_RECORD_POS record_pos)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *data, *end_of_data, *buff;
+ uint offset;
+ uint block_size= share->block_size;
+ DBUG_ENTER("_ma_read_block_record");
+ DBUG_PRINT("enter", ("rowid: %lu", (long) record_pos));
+
+ offset= ma_recordpos_to_dir_entry(record_pos);
+
+ if (!(buff= pagecache_read(share->pagecache,
+ &info->dfile, ma_recordpos_to_page(record_pos), 0,
+ info->buff, share->page_type,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ DBUG_RETURN(my_errno);
+ DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == HEAD_PAGE);
+ if (!(data= get_record_position(buff, block_size, offset, &end_of_data)))
+ {
+ DBUG_PRINT("error", ("Wrong directory entry in data block"));
+ my_errno= HA_ERR_RECORD_DELETED; /* File crashed */
+ DBUG_RETURN(HA_ERR_RECORD_DELETED);
+ }
+ DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data));
+}
+
+
+/* compare unique constraint between stored rows */
+
+my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
+ const uchar *record, MARIA_RECORD_POS pos)
+{
+ uchar *org_rec_buff, *old_record;
+ size_t org_rec_buff_size;
+ int error;
+ DBUG_ENTER("_ma_cmp_block_unique");
+
+ if (!(old_record= my_alloca(info->s->base.reclength)))
+ DBUG_RETURN(1);
+
+ /* Don't let the compare destroy blobs that may be in use */
+ org_rec_buff= info->rec_buff;
+ org_rec_buff_size= info->rec_buff_size;
+ if (info->s->base.blobs)
+ {
+ /* Force realloc of record buffer*/
+ info->rec_buff= 0;
+ info->rec_buff_size= 0;
+ }
+ error= _ma_read_block_record(info, old_record, pos);
+ if (!error)
+ error= _ma_unique_comp(def, record, old_record, def->null_are_equal);
+ if (info->s->base.blobs)
+ {
+ my_free(info->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
+ info->rec_buff= org_rec_buff;
+ info->rec_buff_size= org_rec_buff_size;
+ }
+ DBUG_PRINT("exit", ("result: %d", error));
+ my_afree(old_record);
+ DBUG_RETURN(error != 0);
+}
+
+
+/****************************************************************************
+ Table scan
+****************************************************************************/
+
+/*
+ Allocate buffers for table scan
+
+ SYNOPSIS
+ _ma_scan_init_block_record(MARIA_HA *info)
+
+ IMPLEMENTATION
+ We allocate one buffer for the current bitmap and one buffer for the
+ current page
+
+ RETURN
+ 0 ok
+ 1 error (couldn't allocate memory or disk error)
+*/
+
+my_bool _ma_scan_init_block_record(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_scan_init_block_record");
+ /*
+ bitmap_buff may already be allocated if this is the second call to
+ rnd_init() without a rnd_end() in between, see sql/handler.h
+ */
+ if (!(info->scan.bitmap_buff ||
+ ((info->scan.bitmap_buff=
+ (uchar *) my_malloc(share->block_size * 2, MYF(MY_WME))))))
+ DBUG_RETURN(1);
+ info->scan.page_buff= info->scan.bitmap_buff + share->block_size;
+ info->scan.bitmap_end= info->scan.bitmap_buff + share->bitmap.total_size;
+
+ /* Set scan variables to get _ma_scan_block() to start with reading bitmap */
+ info->scan.number_of_rows= 0;
+ info->scan.bitmap_pos= info->scan.bitmap_end;
+ info->scan.bitmap_page= (pgcache_page_no_t) 0 - share->bitmap.pages_covered;
+ /*
+ We need to flush what's in memory (bitmap.map) to page cache otherwise, as
+ we are going to read bitmaps from page cache in table scan (see
+ _ma_scan_block_record()), we may miss recently inserted rows (bitmap page
+ in page cache would be too old).
+ */
+ DBUG_RETURN(_ma_bitmap_flush(info->s));
+}
+
+
+/* Free buffers allocated by _ma_scan_block_init() */
+
+void _ma_scan_end_block_record(MARIA_HA *info)
+{
+ DBUG_ENTER("_ma_scan_end_block_record");
+ my_free(info->scan.bitmap_buff, MYF(MY_ALLOW_ZERO_PTR));
+ info->scan.bitmap_buff= 0;
+ if (info->scan_save)
+ {
+ my_free(info->scan_save, MYF(0));
+ info->scan_save= 0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Save current scan position
+
+ @note
+ For the moment we can only remember one position, but this is
+ good enough for MySQL usage
+
+ @Warning
+ When this function is called, we assume that the thread is not deleting
+ or updating the current row before ma_scan_restore_block_record()
+ is called!
+
+ @return
+ @retval 0 ok
+ @retval HA_ERR_WRONG_IN_RECORD Could not allocate memory to hold position
+*/
+
+int _ma_scan_remember_block_record(MARIA_HA *info,
+ MARIA_RECORD_POS *lastpos)
+{
+ uchar *bitmap_buff;
+ DBUG_ENTER("_ma_scan_remember_block_record");
+ if (!(info->scan_save))
+ {
+ if (!(info->scan_save= my_malloc(ALIGN_SIZE(sizeof(*info->scan_save)) +
+ info->s->block_size * 2,
+ MYF(MY_WME))))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ info->scan_save->bitmap_buff= ((uchar*) info->scan_save +
+ ALIGN_SIZE(sizeof(*info->scan_save)));
+ }
+ /* Point to the last read row */
+ *lastpos= info->cur_row.nextpos - 1;
+ info->scan.dir+= DIR_ENTRY_SIZE;
+
+ /* Remember used bitmap and used head page */
+ bitmap_buff= info->scan_save->bitmap_buff;
+ memcpy(info->scan_save, &info->scan, sizeof(*info->scan_save));
+ info->scan_save->bitmap_buff= bitmap_buff;
+ memcpy(bitmap_buff, info->scan.bitmap_buff, info->s->block_size * 2);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief restore scan block it's original values
+
+ @note
+ In theory we could swap bitmap buffers instead of copy them.
+ For the moment we don't do that because there are variables pointing
+ inside the buffers and it's a bit of hassle to either make them relative
+ or repoint them.
+*/
+
+void _ma_scan_restore_block_record(MARIA_HA *info,
+ MARIA_RECORD_POS lastpos)
+{
+ uchar *bitmap_buff;
+ DBUG_ENTER("_ma_scan_restore_block_record");
+
+ info->cur_row.nextpos= lastpos;
+ bitmap_buff= info->scan.bitmap_buff;
+ memcpy(&info->scan, info->scan_save, sizeof(*info->scan_save));
+ info->scan.bitmap_buff= bitmap_buff;
+ memcpy(bitmap_buff, info->scan_save->bitmap_buff, info->s->block_size * 2);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Read next record while scanning table
+
+ SYNOPSIS
+ _ma_scan_block_record()
+ info Maria handler
+ record Store found here
+ record_pos Value stored in info->cur_row.next_pos after last call
+ skip_deleted
+
+ NOTES
+ - One must have called mi_scan() before this
+ - In this version, we don't actually need record_pos, we as easily
+ use a variable in info->scan
+
+ IMPLEMENTATION
+ Current code uses a lot of goto's to separate the different kind of
+ states we may be in. This gives us a minimum of executed if's for
+ the normal cases. I tried several different ways to code this, but
+ the current one was in the end the most readable and fastest.
+
+ RETURN
+ 0 ok
+ # Error code
+*/
+
+int _ma_scan_block_record(MARIA_HA *info, uchar *record,
+ MARIA_RECORD_POS record_pos,
+ my_bool skip_deleted __attribute__ ((unused)))
+{
+ uint block_size;
+ my_off_t filepos;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_scan_block_record");
+
+restart_record_read:
+ /* Find next row in current page */
+ while (likely(record_pos < info->scan.number_of_rows))
+ {
+ uint length, offset;
+ uchar *data, *end_of_data;
+ int error;
+
+ while (!(offset= uint2korr(info->scan.dir)))
+ {
+ info->scan.dir-= DIR_ENTRY_SIZE;
+ record_pos++;
+#ifdef SANITY_CHECKS
+ if (info->scan.dir < info->scan.dir_end)
+ {
+ DBUG_ASSERT(0);
+ goto err;
+ }
+#endif
+ }
+ /* found row */
+ info->cur_row.lastpos= info->scan.row_base_page + record_pos;
+ info->cur_row.nextpos= record_pos + 1;
+ data= info->scan.page_buff + offset;
+ length= uint2korr(info->scan.dir + 2);
+ end_of_data= data + length;
+ info->scan.dir-= DIR_ENTRY_SIZE; /* Point to previous row */
+#ifdef SANITY_CHECKS
+ if (end_of_data > info->scan.dir_end ||
+ offset < PAGE_HEADER_SIZE || length < share->base.min_block_length)
+ {
+ DBUG_ASSERT(!(end_of_data > info->scan.dir_end));
+ DBUG_ASSERT(!(offset < PAGE_HEADER_SIZE));
+ DBUG_ASSERT(!(length < share->base.min_block_length));
+ goto err;
+ }
+#endif
+ DBUG_PRINT("info", ("rowid: %lu", (ulong) info->cur_row.lastpos));
+ error= _ma_read_block_record2(info, record, data, end_of_data);
+ if (error != HA_ERR_ROW_NOT_VISIBLE)
+ DBUG_RETURN(error);
+ record_pos++;
+ }
+
+ /* Find next head page in current bitmap */
+restart_bitmap_scan:
+ block_size= share->block_size;
+ if (likely(info->scan.bitmap_pos < info->scan.bitmap_end))
+ {
+ uchar *data= info->scan.bitmap_pos;
+ longlong bits= info->scan.bits;
+ uint bit_pos= info->scan.bit_pos;
+
+ do
+ {
+ while (likely(bits))
+ {
+ uint pattern= (uint) (bits & 7);
+ bits >>= 3;
+ bit_pos++;
+ if (pattern > 0 && pattern <= 4)
+ {
+ /* Found head page; Read it */
+ pgcache_page_no_t page;
+ info->scan.bitmap_pos= data;
+ info->scan.bits= bits;
+ info->scan.bit_pos= bit_pos;
+ page= (info->scan.bitmap_page + 1 +
+ (data - info->scan.bitmap_buff) / 6 * 16 + bit_pos - 1);
+ info->scan.row_base_page= ma_recordpos(page, 0);
+ if (!(pagecache_read(share->pagecache,
+ &info->dfile,
+ page, 0, info->scan.page_buff,
+ share->page_type,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ DBUG_RETURN(my_errno);
+ if (((info->scan.page_buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) !=
+ HEAD_PAGE))
+ {
+ /*
+ This may happen if someone has been deleting all rows
+ from a page since we read the bitmap, so it may be ok.
+ Print warning in debug log and continue.
+ */
+ DBUG_PRINT("warning",
+ ("Found page of type %d when expecting head page",
+ (info->scan.page_buff[PAGE_TYPE_OFFSET] &
+ PAGE_TYPE_MASK)));
+ continue;
+ }
+ if ((info->scan.number_of_rows=
+ (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) == 0)
+ {
+ DBUG_PRINT("error", ("Wrong page header"));
+ DBUG_RETURN((my_errno= HA_ERR_WRONG_IN_RECORD));
+ }
+ DBUG_PRINT("info", ("Page %lu has %u rows",
+ (ulong) page, info->scan.number_of_rows));
+ info->scan.dir= (info->scan.page_buff + block_size -
+ PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE);
+ info->scan.dir_end= (info->scan.dir -
+ (info->scan.number_of_rows - 1) *
+ DIR_ENTRY_SIZE);
+ record_pos= 0;
+ goto restart_record_read;
+ }
+ }
+ for (data+= 6; data < info->scan.bitmap_end; data+= 6)
+ {
+ bits= uint6korr(data);
+ /* Skip not allocated pages and blob / full tail pages */
+ if (bits && bits != LL(07777777777777777))
+ break;
+ }
+ bit_pos= 0;
+ } while (data < info->scan.bitmap_end);
+ }
+
+ /* Read next bitmap */
+ info->scan.bitmap_page+= share->bitmap.pages_covered;
+ filepos= (my_off_t) info->scan.bitmap_page * block_size;
+ if (unlikely(filepos >= share->state.state.data_file_length))
+ {
+ DBUG_PRINT("info", ("Found end of file"));
+ DBUG_RETURN((my_errno= HA_ERR_END_OF_FILE));
+ }
+ DBUG_PRINT("info", ("Reading bitmap at %lu",
+ (ulong) info->scan.bitmap_page));
+ if (!(pagecache_read(share->pagecache, &info->s->bitmap.file,
+ info->scan.bitmap_page,
+ 0, info->scan.bitmap_buff, PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ DBUG_RETURN(my_errno);
+ /* Skip scanning 'bits' in bitmap scan code */
+ info->scan.bitmap_pos= info->scan.bitmap_buff - 6;
+ info->scan.bits= 0;
+ goto restart_bitmap_scan;
+
+err:
+ DBUG_PRINT("error", ("Wrong data on page"));
+ DBUG_RETURN((my_errno= HA_ERR_WRONG_IN_RECORD));
+}
+
+
+/*
+ Compare a row against a stored one
+
+ NOTES
+ Not implemented, as block record is not supposed to be used in a shared
+ global environment
+*/
+
+my_bool _ma_compare_block_record(MARIA_HA *info __attribute__ ((unused)),
+ const uchar *record __attribute__ ((unused)))
+{
+ return 0;
+}
+
+
+/*
+ Store an integer with simple packing
+
+ SYNOPSIS
+ ma_store_integer()
+ to Store the packed integer here
+ nr Integer to store
+
+ NOTES
+ This is mostly used to store field numbers and lengths of strings.
+ We have to cast the result for the LL() becasue of a bug in Forte CC
+ compiler.
+
+ Packing used is:
+ nr < 251 is stored as is (in 1 byte)
+ Numbers that require 1-4 bytes are stored as char(250+byte_length), data
+ Bigger numbers are stored as 255, data as ulonglong (not yet done).
+
+ RETURN
+ Position in 'to' after the packed length
+*/
+
+uchar *ma_store_length(uchar *to, ulong nr)
+{
+ if (nr < 251)
+ {
+ *to=(uchar) nr;
+ return to+1;
+ }
+ if (nr < 65536)
+ {
+ if (nr <= 255)
+ {
+ to[0]= (uchar) 251;
+ to[1]= (uchar) nr;
+ return to+2;
+ }
+ to[0]= (uchar) 252;
+ int2store(to+1, nr);
+ return to+3;
+ }
+ if (nr < 16777216)
+ {
+ *to++= (uchar) 253;
+ int3store(to, nr);
+ return to+3;
+ }
+ *to++= (uchar) 254;
+ int4store(to, nr);
+ return to+4;
+}
+
+
+/* Calculate how many bytes needed to store a number */
+
+uint ma_calc_length_for_store_length(ulong nr)
+{
+ if (nr < 251)
+ return 1;
+ if (nr < 65536)
+ {
+ if (nr <= 255)
+ return 2;
+ return 3;
+ }
+ if (nr < 16777216)
+ return 4;
+ return 5;
+}
+
+
+/* Retrive a stored number */
+
+static ulong ma_get_length(const uchar **packet)
+{
+ reg1 const uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (ulong) *pos;
+ }
+ if (*pos == 251)
+ {
+ (*packet)+= 2;
+ return (ulong) pos[1];
+ }
+ if (*pos == 252)
+ {
+ (*packet)+= 3;
+ return (ulong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+= 4;
+ return (ulong) uint3korr(pos+1);
+ }
+ DBUG_ASSERT(*pos == 254);
+ (*packet)+= 5;
+ return (ulong) uint4korr(pos+1);
+}
+
+
+/*
+ Fill array with pointers to field parts to be stored in log for insert
+
+ SYNOPSIS
+ fill_insert_undo_parts()
+ info Maria handler
+ record Inserted row
+ log_parts Store pointers to changed memory areas here
+ log_parts_count See RETURN
+
+ NOTES
+ We have information in info->cur_row about the read row.
+
+ RETURN
+ length of data in log_parts.
+ log_parts_count contains number of used log_parts
+*/
+
+static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record,
+ LEX_CUSTRING *log_parts,
+ uint *log_parts_count)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_COLUMNDEF *column, *end_column;
+ uchar *field_lengths= info->cur_row.field_lengths;
+ size_t row_length;
+ MARIA_ROW *cur_row= &info->cur_row;
+ LEX_CUSTRING *start_log_parts;
+ DBUG_ENTER("fill_insert_undo_parts");
+
+ start_log_parts= log_parts;
+
+ /* Store null bits */
+ log_parts->str= record;
+ log_parts->length= share->base.null_bytes;
+ row_length= log_parts->length;
+ log_parts++;
+
+ /* Stored bitmap over packed (zero length or all-zero fields) */
+ log_parts->str= info->cur_row.empty_bits;
+ log_parts->length= share->base.pack_bytes;
+ row_length+= log_parts->length;
+ log_parts++;
+
+ if (share->base.max_field_lengths)
+ {
+ /* Store length of all not empty char, varchar and blob fields */
+ log_parts->str= field_lengths - 2;
+ log_parts->length= info->cur_row.field_lengths_length+2;
+ int2store(log_parts->str, info->cur_row.field_lengths_length);
+ row_length+= log_parts->length;
+ log_parts++;
+ }
+
+ if (share->base.blobs)
+ {
+ /*
+ Store total blob length to make buffer allocation easier during UNDO
+ */
+ log_parts->str= info->length_buff;
+ log_parts->length= (uint) (ma_store_length((uchar *) log_parts->str,
+ info->cur_row.blob_length) -
+ (uchar*) log_parts->str);
+ row_length+= log_parts->length;
+ log_parts++;
+ }
+
+ /* Handle constant length fields that are always present */
+ for (column= share->columndef,
+ end_column= column+ share->base.fixed_not_null_fields;
+ column < end_column;
+ column++)
+ {
+ log_parts->str= record + column->offset;
+ log_parts->length= column->length;
+ row_length+= log_parts->length;
+ log_parts++;
+ }
+
+ /* Handle NULL fields and CHAR/VARCHAR fields */
+ for (end_column= share->columndef + share->base.fields - share->base.blobs;
+ column < end_column;
+ column++)
+ {
+ const uchar *column_pos;
+ size_t column_length;
+ if ((record[column->null_pos] & column->null_bit) ||
+ cur_row->empty_bits[column->empty_pos] & column->empty_bit)
+ continue;
+
+ column_pos= record+ column->offset;
+ column_length= column->length;
+
+ switch (column->type) {
+ case FIELD_CHECK:
+ case FIELD_NORMAL: /* Fixed length field */
+ case FIELD_ZERO:
+ case FIELD_SKIP_PRESPACE: /* Not packed */
+ case FIELD_SKIP_ZERO: /* Fixed length field */
+ break;
+ case FIELD_SKIP_ENDSPACE: /* CHAR */
+ {
+ if (column->length <= 255)
+ column_length= *field_lengths++;
+ else
+ {
+ column_length= uint2korr(field_lengths);
+ field_lengths+= 2;
+ }
+ break;
+ }
+ case FIELD_VARCHAR:
+ {
+ if (column->fill_length == 1)
+ column_length= *field_lengths;
+ else
+ column_length= uint2korr(field_lengths);
+ field_lengths+= column->fill_length;
+ column_pos+= column->fill_length;
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ }
+ log_parts->str= column_pos;
+ log_parts->length= column_length;
+ row_length+= log_parts->length;
+ log_parts++;
+ }
+
+ /* Add blobs */
+ for (end_column+= share->base.blobs; column < end_column; column++)
+ {
+ const uchar *field_pos= record + column->offset;
+ uint size_length= column->length - portable_sizeof_char_ptr;
+ ulong blob_length= _ma_calc_blob_length(size_length, field_pos);
+
+ /*
+ We don't have to check for null, as blob_length is guranteed to be 0
+ if the blob is null
+ */
+ if (blob_length)
+ {
+ uchar *blob_pos;
+ memcpy_fixed(&blob_pos, record + column->offset + size_length,
+ sizeof(blob_pos));
+ log_parts->str= blob_pos;
+ log_parts->length= blob_length;
+ row_length+= log_parts->length;
+ log_parts++;
+ }
+ }
+ *log_parts_count= (uint) (log_parts - start_log_parts);
+ DBUG_RETURN(row_length);
+}
+
+
+/*
+ Fill array with pointers to field parts to be stored in log for update
+
+ SYNOPSIS
+ fill_update_undo_parts()
+ info Maria handler
+ oldrec Original row
+ newrec New row
+ log_parts Store pointers to changed memory areas here
+ log_parts_count See RETURN
+
+ IMPLEMENTATION
+ Format of undo record:
+
+ Fields are stored in same order as the field array.
+
+ Offset to changed field data (packed)
+
+ For each changed field
+ Fieldnumber (packed)
+ Length, if variable length field (packed)
+
+ For each changed field
+ Data
+
+ Packing is using ma_store_integer()
+
+ The reason we store field numbers & length separated from data (ie, not
+ after each other) is to get better cpu caching when we loop over
+ fields (as we probably don't have to access data for each field when we
+ want to read and old row through the undo log record).
+
+ As a special case, we use '255' for the field number of the null bitmap.
+
+ RETURN
+ length of data in log_parts.
+ log_parts_count contains number of used log_parts
+*/
+
+static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec,
+ const uchar *newrec,
+ LEX_CUSTRING *log_parts,
+ uint *log_parts_count)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_COLUMNDEF *column, *end_column;
+ MARIA_ROW *old_row= &info->cur_row, *new_row= &info->new_row;
+ uchar *field_data, *start_field_data;
+ uchar *old_field_lengths= old_row->field_lengths;
+ uchar *new_field_lengths= new_row->field_lengths;
+ size_t row_length= 0;
+ uint field_lengths;
+ LEX_CUSTRING *start_log_parts;
+ my_bool new_column_is_empty;
+ DBUG_ENTER("fill_update_undo_parts");
+
+ start_log_parts= log_parts;
+
+ /*
+ First log part is for number of fields, field numbers and lengths
+ The +4 is to reserve place for the number of changed fields.
+ */
+ start_field_data= field_data= info->update_field_data + 4;
+ log_parts++;
+
+ if (memcmp(oldrec, newrec, share->base.null_bytes))
+ {
+ /* Store changed null bits */
+ *field_data++= (uchar) 255; /* Special case */
+ log_parts->str= oldrec;
+ log_parts->length= share->base.null_bytes;
+ row_length= log_parts->length;
+ log_parts++;
+ }
+
+ /* Handle constant length fields */
+ for (column= share->columndef,
+ end_column= column+ share->base.fixed_not_null_fields;
+ column < end_column;
+ column++)
+ {
+ if (memcmp(oldrec + column->offset, newrec + column->offset,
+ column->length))
+ {
+ field_data= ma_store_length(field_data,
+ (uint) (column - share->columndef));
+ log_parts->str= oldrec + column->offset;
+ log_parts->length= column->length;
+ row_length+= column->length;
+ log_parts++;
+ }
+ }
+
+ /* Handle the rest: NULL fields and CHAR/VARCHAR fields and BLOB's */
+ for (end_column= share->columndef + share->base.fields;
+ column < end_column;
+ column++)
+ {
+ const uchar *new_column_pos, *old_column_pos;
+ size_t new_column_length, old_column_length;
+
+ /* First check if old column is null or empty */
+ if (oldrec[column->null_pos] & column->null_bit)
+ {
+ /*
+ It's safe to skip this one as either the new column is also null
+ (no change) or the new_column is not null, in which case the null-bit
+ maps differed and we have already stored the null bitmap.
+ */
+ continue;
+ }
+ if (old_row->empty_bits[column->empty_pos] & column->empty_bit)
+ {
+ if (new_row->empty_bits[column->empty_pos] & column->empty_bit)
+ continue; /* Both are empty; skip */
+
+ /* Store null length column */
+ field_data= ma_store_length(field_data,
+ (uint) (column - share->columndef));
+ field_data= ma_store_length(field_data, 0);
+ continue;
+ }
+ /*
+ Remember if the 'new' value is empty (as in this case we must always
+ log the original value
+ */
+ new_column_is_empty= ((newrec[column->null_pos] & column->null_bit) ||
+ (new_row->empty_bits[column->empty_pos] &
+ column->empty_bit));
+
+ old_column_pos= oldrec + column->offset;
+ new_column_pos= newrec + column->offset;
+ old_column_length= new_column_length= column->length;
+
+ switch (column->type) {
+ case FIELD_CHECK:
+ case FIELD_NORMAL: /* Fixed length field */
+ case FIELD_ZERO:
+ case FIELD_SKIP_PRESPACE: /* Not packed */
+ case FIELD_SKIP_ZERO: /* Fixed length field */
+ break;
+ case FIELD_VARCHAR:
+ new_column_length--; /* Skip length prefix */
+ old_column_pos+= column->fill_length;
+ new_column_pos+= column->fill_length;
+ /* Fall through */
+ case FIELD_SKIP_ENDSPACE: /* CHAR */
+ {
+ if (new_column_length <= 255)
+ {
+ old_column_length= *old_field_lengths++;
+ if (!new_column_is_empty)
+ new_column_length= *new_field_lengths++;
+ }
+ else
+ {
+ old_column_length= uint2korr(old_field_lengths);
+ old_field_lengths+= 2;
+ if (!new_column_is_empty)
+ {
+ new_column_length= uint2korr(new_field_lengths);
+ new_field_lengths+= 2;
+ }
+ }
+ break;
+ }
+ case FIELD_BLOB:
+ {
+ uint size_length= column->length - portable_sizeof_char_ptr;
+ old_column_length= _ma_calc_blob_length(size_length, old_column_pos);
+ memcpy_fixed((uchar*) &old_column_pos,
+ oldrec + column->offset + size_length,
+ sizeof(old_column_pos));
+ if (!new_column_is_empty)
+ {
+ new_column_length= _ma_calc_blob_length(size_length, new_column_pos);
+ memcpy_fixed((uchar*) &new_column_pos,
+ newrec + column->offset + size_length,
+ sizeof(old_column_pos));
+ }
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ }
+
+ if (new_column_is_empty || new_column_length != old_column_length ||
+ memcmp(old_column_pos, new_column_pos, new_column_length))
+ {
+ field_data= ma_store_length(field_data,
+ (ulong) (column - share->columndef));
+ field_data= ma_store_length(field_data, (ulong) old_column_length);
+
+ log_parts->str= old_column_pos;
+ log_parts->length= old_column_length;
+ row_length+= old_column_length;
+ log_parts++;
+ }
+ }
+
+ *log_parts_count= (uint) (log_parts - start_log_parts);
+
+ /* Store length of field length data before the field/field_lengths */
+ field_lengths= (uint) (field_data - start_field_data);
+ start_log_parts->str= ((start_field_data -
+ ma_calc_length_for_store_length(field_lengths)));
+ ma_store_length((uchar*)start_log_parts->str, field_lengths);
+ start_log_parts->length= (size_t) (field_data - start_log_parts->str);
+ row_length+= start_log_parts->length;
+ DBUG_RETURN(row_length);
+}
+
+/***************************************************************************
+ In-write hooks called under log's lock when log record is written
+***************************************************************************/
+
+/**
+ @brief Sets transaction's rec_lsn if needed
+
+ A transaction sometimes writes a REDO even before the page is in the
+ pagecache (example: brand new head or tail pages; full pages). So, if
+ Checkpoint happens just after the REDO write, it needs to know that the
+ REDO phase must start before this REDO. Scanning the pagecache cannot
+ tell that as the page is not in the cache. So, transaction sets its rec_lsn
+ to the REDO's LSN or somewhere before, and Checkpoint reads the
+ transaction's rec_lsn.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_redo(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn, void *hook_arg
+ __attribute__ ((unused)))
+{
+ /*
+ Users of dummy_transaction_object must keep this TRN clean as it
+ is used by many threads (like those manipulating non-transactional
+ tables). It might be dangerous if one user sets rec_lsn or some other
+ member and it is picked up by another user (like putting this rec_lsn into
+ a page of a non-transactional table); it's safer if all members stay 0. So
+ non-transactional log records (REPAIR, CREATE, RENAME, DROP) should not
+ call this hook; we trust them but verify ;)
+ */
+ DBUG_ASSERT(trn->trid != 0);
+ /*
+ If the hook stays so simple, it would be faster to pass
+ !trn->rec_lsn ? trn->rec_lsn : some_dummy_lsn
+ to translog_write_record(), like Monty did in his original code, and not
+ have a hook. For now we keep it like this.
+ */
+ if (trn->rec_lsn == 0)
+ trn->rec_lsn= *lsn;
+ return 0;
+}
+
+
+/**
+ @brief Sets transaction's undo_lsn, first_undo_lsn if needed
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn, void *hook_arg
+ __attribute__ ((unused)))
+{
+ DBUG_ASSERT(trn->trid != 0);
+ trn->undo_lsn= *lsn;
+ if (unlikely(LSN_WITH_FLAGS_TO_LSN(trn->first_undo_lsn) == 0))
+ trn->first_undo_lsn=
+ trn->undo_lsn | LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
+ return 0;
+ /*
+ when we implement purging, we will specialize this hook: UNDO_PURGE
+ records will additionally set trn->undo_purge_lsn
+ */
+}
+
+
+/**
+ @brief Sets the table's records count and checksum and others to 0, then
+ calls the generic REDO hook.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_redo_delete_all(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn, void *hook_arg)
+{
+ _ma_reset_status(tbl_info);
+ return write_hook_for_redo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Updates "records" and "checksum" and calls the generic UNDO hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_row_insert(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ share->state.state.records++;
+ share->state.state.checksum+= *(ha_checksum *)hook_arg;
+ return write_hook_for_undo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Upates "records" and calls the generic UNDO hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_row_delete(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ share->state.state.records--;
+ share->state.state.checksum+= *(ha_checksum *)hook_arg;
+ return write_hook_for_undo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Upates "records" and "checksum" and calls the generic UNDO hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_row_update(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ share->state.state.checksum+= *(ha_checksum *)hook_arg;
+ return write_hook_for_undo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+my_bool write_hook_for_undo_bulk_insert(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ /*
+ We are going to call maria_delete_all_rows(), but without logging and
+ syncing, as an optimization (if we crash before commit, the UNDO will
+ empty; if we crash after commit, we have flushed and forced the files).
+ Status still needs to be reset under log mutex, in case of a concurrent
+ checkpoint.
+ */
+ _ma_reset_status(tbl_info);
+ return write_hook_for_undo(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Updates table's lsn_of_file_id.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_file_id(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn
+ __attribute__ ((unused)),
+ MARIA_HA *tbl_info,
+ LSN *lsn,
+ void *hook_arg
+ __attribute__ ((unused)))
+{
+ DBUG_ASSERT(cmp_translog_addr(tbl_info->s->lsn_of_file_id, *lsn) < 0);
+ tbl_info->s->lsn_of_file_id= *lsn;
+ return 0;
+}
+
+
+/**
+ Updates transaction's rec_lsn when committing.
+
+ A transaction writes its commit record before being committed in trnman, so
+ if Checkpoint happens just between the COMMIT record log write and the
+ commit in trnman, it will record that transaction is not committed. Assume
+ the transaction (trn1) did an INSERT; after the checkpoint, a second
+ transaction (trn2) does a DELETE of what trn1 has inserted. Then crash,
+ Checkpoint record says that trn1 was not committed, and REDO phase starts
+ from Checkpoint record's LSN. So it will not find the COMMIT record of
+ trn1, will want to roll back trn1, which will fail because the row/key
+ which it wants to delete does not exist anymore.
+ To avoid this, Checkpoint needs to know that the REDO phase must start
+ before this COMMIT record, so transaction sets its rec_lsn to the COMMIT's
+ record LSN, and as Checkpoint reads the transaction's rec_lsn, Checkpoint
+ will know.
+
+ @note so after commit trn->rec_lsn is a "commit LSN", which could be of
+ use later.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_commit(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn,
+ MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn,
+ void *hook_arg
+ __attribute__ ((unused)))
+{
+ trn->rec_lsn= *lsn;
+ return 0;
+}
+
+
+/***************************************************************************
+ Applying of REDO log records
+***************************************************************************/
+
+/*
+ Apply changes to head and tail pages
+
+ SYNOPSIS
+ _ma_apply_redo_insert_row_head_or_tail()
+ info Maria handler
+ lsn LSN to put on page
+ page_type HEAD_PAGE or TAIL_PAGE
+ new_page True if this is first entry on page
+ header Header (without FILEID)
+ data Data to be put on page
+ data_length Length of data
+
+ NOTE
+ Handles LOGREC_REDO_INSERT_ROW_HEAD, LOGREC_REDO_INSERT_ROW_TAIL
+ LOGREC_REDO_NEW_ROW_HEAD and LOGREC_REDO_NEW_ROW_TAIL
+
+ RETURN
+ 0 ok
+ # Error number
+*/
+
+uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
+ uint page_type,
+ my_bool new_page,
+ const uchar *header,
+ const uchar *data,
+ size_t data_length)
+{
+ MARIA_SHARE *share= info->s;
+ pgcache_page_no_t page;
+ uint rownr, empty_space;
+ uint block_size= share->block_size;
+ uint rec_offset;
+ uchar *buff, *dir;
+ uint result;
+ MARIA_PINNED_PAGE page_link;
+ enum pagecache_page_lock unlock_method;
+ enum pagecache_page_pin unpin_method;
+ my_off_t end_of_page;
+ uint error;
+ DBUG_ENTER("_ma_apply_redo_insert_row_head_or_tail");
+
+ page= page_korr(header);
+ rownr= dirpos_korr(header + PAGE_STORE_SIZE);
+
+ DBUG_PRINT("enter", ("rowid: %lu page: %lu rownr: %u data_length: %u",
+ (ulong) ma_recordpos(page, rownr),
+ (ulong) page, rownr, (uint) data_length));
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ end_of_page= (page + 1) * share->block_size;
+ if (end_of_page > share->state.state.data_file_length)
+ {
+ DBUG_PRINT("info", ("Enlarging data file from %lu to %lu",
+ (ulong) share->state.state.data_file_length,
+ (ulong) end_of_page));
+ /*
+ New page at end of file. Note that the test above is also positive if
+ data_file_length is not a multiple of block_size (system crashed while
+ writing the last page): in this case we just extend the last page and
+ fill it entirely with zeroes, then the REDO will put correct data on
+ it.
+ */
+ unlock_method= PAGECACHE_LOCK_WRITE;
+ unpin_method= PAGECACHE_PIN;
+
+ DBUG_ASSERT(rownr == 0 && new_page);
+ if (rownr != 0 || !new_page)
+ goto crashed_file;
+
+ buff= info->keyread_buff;
+ info->keyread_buff_used= 1;
+ make_empty_page(info, buff, page_type, 1);
+ empty_space= (block_size - PAGE_OVERHEAD_SIZE);
+ rec_offset= PAGE_HEADER_SIZE;
+ dir= buff+ block_size - PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE;
+ }
+ else
+ {
+ unlock_method= PAGECACHE_LOCK_LEFT_WRITELOCKED;
+ unpin_method= PAGECACHE_PIN_LEFT_PINNED;
+
+ share->pagecache->readwrite_flags&= ~MY_WME;
+ buff= pagecache_read(share->pagecache, &info->dfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link);
+ share->pagecache->readwrite_flags= share->pagecache->org_readwrite_flags;
+ if (!buff)
+ {
+ /* Skip errors when reading outside of file and uninitialized pages */
+ if (!new_page || (my_errno != HA_ERR_FILE_TOO_SHORT &&
+ my_errno != HA_ERR_WRONG_CRC))
+ goto err;
+ /* Create new page */
+ buff= pagecache_block_link_to_buffer(page_link.link);
+ buff[PAGE_TYPE_OFFSET]= UNALLOCATED_PAGE;
+ }
+ else if (lsn_korr(buff) >= lsn) /* Test if already applied */
+ {
+ /* Fix bitmap, just in case */
+ empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
+ if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
+ goto err;
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ DBUG_RETURN(0);
+ }
+
+ if (((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) != page_type))
+ {
+ /*
+ This is a page that has been freed before and now should be
+ changed to new type.
+ */
+ if (!new_page)
+ goto crashed_file;
+ make_empty_page(info, buff, page_type, 0);
+ empty_space= block_size - PAGE_HEADER_SIZE - PAGE_SUFFIX_SIZE;
+ (void) extend_directory(page_type == HEAD_PAGE ? info: 0, buff,
+ block_size, 0, rownr, &empty_space);
+ rec_offset= PAGE_HEADER_SIZE;
+ dir= dir_entry_pos(buff, block_size, rownr);
+ empty_space+= uint2korr(dir+2);
+ }
+ else
+ {
+ uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
+ uint length;
+
+ DBUG_ASSERT(!new_page);
+ dir= dir_entry_pos(buff, block_size, rownr);
+ empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
+
+ if (max_entry <= rownr)
+ {
+ /* Add directory entry first in directory and data last on page */
+ if (extend_directory(page_type == HEAD_PAGE ? info : 0, buff,
+ block_size, max_entry, rownr, &empty_space))
+ goto crashed_file;
+ }
+ if (extend_area_on_page(page_type == HEAD_PAGE ? info : 0, buff,
+ dir, rownr, block_size,
+ (uint) data_length, &empty_space,
+ &rec_offset, &length))
+ goto crashed_file;
+ }
+ }
+ /* Copy data */
+ int2store(dir+2, data_length);
+ memcpy(buff + rec_offset, data, data_length);
+ empty_space-= (uint) data_length;
+ int2store(buff + EMPTY_SPACE_OFFSET, empty_space);
+
+ /*
+ If page was not read before, write it but keep it pinned.
+ We don't update its LSN When we have processed all REDOs for this page
+ in the current REDO's group, we will stamp page with UNDO's LSN
+ (if we stamped it now, a next REDO, in
+ this group, for this page, would be skipped) and unpin then.
+ */
+ result= 0;
+ if (unlock_method == PAGECACHE_LOCK_WRITE &&
+ pagecache_write(share->pagecache,
+ &info->dfile, page, 0,
+ buff, PAGECACHE_PLAIN_PAGE,
+ unlock_method, unpin_method,
+ PAGECACHE_WRITE_DELAY, &page_link.link,
+ LSN_IMPOSSIBLE))
+ result= my_errno;
+
+ /* Fix bitmap */
+ if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
+ goto err;
+
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+
+ /*
+ Data page and bitmap page are in place, we can update data_file_length in
+ case we extended the file. We could not do it earlier: bitmap code tests
+ data_file_length to know if it has to create a new page or not.
+ */
+ set_if_bigger(share->state.state.data_file_length, end_of_page);
+ DBUG_RETURN(result);
+
+crashed_file:
+ my_errno= HA_ERR_WRONG_IN_RECORD;
+err:
+ error= my_errno;
+ if (unlock_method == PAGECACHE_LOCK_LEFT_WRITELOCKED)
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ _ma_mark_file_crashed(share);
+ DBUG_ASSERT(0); /* catch recovery errors early */
+ DBUG_RETURN((my_errno= error));
+}
+
+
+/*
+ Apply LOGREC_REDO_PURGE_ROW_HEAD & LOGREC_REDO_PURGE_ROW_TAIL
+
+ SYNOPSIS
+ _ma_apply_redo_purge_row_head_or_tail()
+ info Maria handler
+ lsn LSN to put on page
+ page_type HEAD_PAGE or TAIL_PAGE
+ header Header (without FILEID)
+
+ NOTES
+ This function is very similar to delete_head_or_tail()
+
+ RETURN
+ 0 ok
+ # Error number
+*/
+
+uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
+ uint page_type,
+ const uchar *header)
+{
+ MARIA_SHARE *share= info->s;
+ pgcache_page_no_t page;
+ uint rownr, empty_space;
+ uint block_size= share->block_size;
+ uchar *buff;
+ int result;
+ uint error;
+ MARIA_PINNED_PAGE page_link;
+ DBUG_ENTER("_ma_apply_redo_purge_row_head_or_tail");
+
+ page= page_korr(header);
+ rownr= dirpos_korr(header+PAGE_STORE_SIZE);
+ DBUG_PRINT("enter", ("rowid: %lu page: %lu rownr: %u",
+ (ulong) ma_recordpos(page, rownr),
+ (ulong) page, rownr));
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ if (!(buff= pagecache_read(share->pagecache, &info->dfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
+ goto err;
+
+ if (lsn_korr(buff) >= lsn)
+ {
+ /*
+ Already applied
+ Note that in case the page is not anymore a head or tail page
+ a future redo will fix the bitmap.
+ */
+ if ((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == page_type)
+ {
+ empty_space= uint2korr(buff+EMPTY_SPACE_OFFSET);
+ if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE,
+ empty_space))
+ goto err;
+ }
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ DBUG_RETURN(0);
+ }
+
+ DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == (uchar) page_type);
+
+ if (delete_dir_entry(buff, block_size, rownr, &empty_space) < 0)
+ {
+ my_errno= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+
+ result= 0;
+ /* This will work even if the page was marked as UNALLOCATED_PAGE */
+ if (_ma_bitmap_set(info, page, page_type == HEAD_PAGE, empty_space))
+ result= my_errno;
+
+ DBUG_RETURN(result);
+
+err:
+ error= my_errno;
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ _ma_mark_file_crashed(share);
+ DBUG_ASSERT(0);
+ DBUG_RETURN((my_errno= error));
+
+}
+
+
+/**
+ @brief Apply LOGREC_REDO_FREE_BLOCKS
+
+ @param info Maria handler
+ @param header Header (without FILEID)
+
+ @note It marks the pages free in the bitmap
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+uint _ma_apply_redo_free_blocks(MARIA_HA *info,
+ LSN lsn __attribute__((unused)),
+ const uchar *header)
+{
+ MARIA_SHARE *share= info->s;
+ uint ranges;
+ DBUG_ENTER("_ma_apply_redo_free_blocks");
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ ranges= pagerange_korr(header);
+ header+= PAGERANGE_STORE_SIZE;
+ DBUG_ASSERT(ranges > 0);
+
+ while (ranges--)
+ {
+ my_bool res;
+ uint page_range;
+ pgcache_page_no_t page, start_page;
+
+ start_page= page= page_korr(header);
+ header+= PAGE_STORE_SIZE;
+ /* Page range may have this bit set to indicate a tail page */
+ page_range= pagerange_korr(header) & ~(TAIL_BIT | START_EXTENT_BIT);
+ DBUG_ASSERT(page_range > 0);
+
+ header+= PAGERANGE_STORE_SIZE;
+
+ DBUG_PRINT("info", ("page: %lu pages: %u", (long) page, page_range));
+
+ /** @todo leave bitmap lock to the bitmap code... */
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+ res= _ma_bitmap_reset_full_page_bits(info, &share->bitmap, start_page,
+ page_range);
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ if (res)
+ {
+ _ma_mark_file_crashed(share);
+ DBUG_ASSERT(0);
+ DBUG_RETURN(res);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Apply LOGREC_REDO_FREE_HEAD_OR_TAIL
+
+ @param info Maria handler
+ @param header Header (without FILEID)
+
+ @note It marks the page free in the bitmap, and sets the directory's count
+ to 0.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+uint _ma_apply_redo_free_head_or_tail(MARIA_HA *info, LSN lsn,
+ const uchar *header)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *buff;
+ pgcache_page_no_t page;
+ MARIA_PINNED_PAGE page_link;
+ my_bool res;
+ DBUG_ENTER("_ma_apply_redo_free_head_or_tail");
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ page= page_korr(header);
+
+ if (!(buff= pagecache_read(share->pagecache,
+ &info->dfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE, &page_link.link)))
+ {
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ goto err;
+ }
+ if (lsn_korr(buff) >= lsn)
+ {
+ /* Already applied */
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ }
+ else
+ {
+ buff[PAGE_TYPE_OFFSET]= UNALLOCATED_PAGE;
+#ifdef IDENTICAL_PAGES_AFTER_RECOVERY
+ {
+ uint number_of_records= (uint) buff[DIR_COUNT_OFFSET];
+ uchar *dir= dir_entry_pos(buff, share->block_size,
+ number_of_records-1);
+ buff[DIR_FREE_OFFSET]= END_OF_DIR_FREE_LIST;
+ bzero(dir, number_of_records * DIR_ENTRY_SIZE);
+ }
+#endif
+
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ }
+ /** @todo leave bitmap lock to the bitmap code... */
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+ res= _ma_bitmap_reset_full_page_bits(info, &share->bitmap, page, 1);
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ if (res)
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ _ma_mark_file_crashed(share);
+ DBUG_ASSERT(0);
+ DBUG_RETURN(1);
+}
+
+
+/**
+ @brief Apply LOGREC_REDO_INSERT_ROW_BLOBS
+
+ @param info Maria handler
+ @parma lsn LSN to put on pages
+ @param header Header (with FILEID)
+ @param redo_lsn REDO record's LSN
+ @param[out] number_of_blobs Number of blobs found in log record
+ @param[out] number_of_ranges Number of ranges found
+ @param[out] first_page First page touched
+ @param[out] last_page Last page touched
+
+ @note Write full pages (full head & blob pages)
+
+ @return Operation status
+ @retval 0 OK
+ @retval !=0 Error
+*/
+
+uint _ma_apply_redo_insert_row_blobs(MARIA_HA *info,
+ LSN lsn, const uchar *header,
+ LSN redo_lsn,
+ uint * const number_of_blobs,
+ uint * const number_of_ranges,
+ pgcache_page_no_t * const first_page,
+ pgcache_page_no_t * const last_page)
+{
+ MARIA_SHARE *share= info->s;
+ const uchar *data;
+ uint data_size= FULL_PAGE_SIZE(share->block_size);
+ uint blob_count, ranges;
+ uint16 sid;
+ pgcache_page_no_t first_page2= ULONGLONG_MAX, last_page2= 0;
+ DBUG_ENTER("_ma_apply_redo_insert_row_blobs");
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ sid= fileid_korr(header);
+ header+= FILEID_STORE_SIZE;
+ *number_of_ranges= ranges= pagerange_korr(header);
+ header+= PAGERANGE_STORE_SIZE;
+ *number_of_blobs= blob_count= pagerange_korr(header);
+ header+= PAGERANGE_STORE_SIZE;
+ DBUG_ASSERT(ranges >= blob_count);
+
+ data= (header + ranges * ROW_EXTENT_SIZE +
+ blob_count * (SUB_RANGE_SIZE + BLOCK_FILLER_SIZE));
+
+ while (blob_count--)
+ {
+ uint sub_ranges, empty_space;
+
+ sub_ranges= uint2korr(header);
+ header+= SUB_RANGE_SIZE;
+ empty_space= uint2korr(header);
+ header+= BLOCK_FILLER_SIZE;
+ DBUG_ASSERT(sub_ranges <= ranges && empty_space < data_size);
+ ranges-= sub_ranges;
+
+ while (sub_ranges--)
+ {
+ uint i;
+ uint res;
+ uint page_range;
+ pgcache_page_no_t page, start_page;
+ uchar *buff;
+
+ start_page= page= page_korr(header);
+ header+= PAGE_STORE_SIZE;
+ page_range= pagerange_korr(header);
+ header+= PAGERANGE_STORE_SIZE;
+
+ for (i= page_range; i-- > 0 ; page++)
+ {
+ MARIA_PINNED_PAGE page_link;
+ enum pagecache_page_lock unlock_method;
+ enum pagecache_page_pin unpin_method;
+ uint length;
+
+ set_if_smaller(first_page2, page);
+ set_if_bigger(last_page2, page);
+ if (_ma_redo_not_needed_for_page(sid, redo_lsn, page, FALSE))
+ continue;
+
+ if (((page + 1) * share->block_size) >
+ share->state.state.data_file_length)
+ {
+ /* New page or half written page at end of file */
+ DBUG_PRINT("info", ("Enlarging data file from %lu to %lu",
+ (ulong) share->state.state.data_file_length,
+ (ulong) ((page + 1 ) * share->block_size)));
+ share->state.state.data_file_length= (page + 1) * share->block_size;
+ buff= info->keyread_buff;
+ info->keyread_buff_used= 1;
+ make_empty_page(info, buff, BLOB_PAGE, 0);
+ unlock_method= PAGECACHE_LOCK_LEFT_UNLOCKED;
+ unpin_method= PAGECACHE_PIN_LEFT_UNPINNED;
+ }
+ else
+ {
+ share->pagecache->readwrite_flags&= ~MY_WME;
+ buff= pagecache_read(share->pagecache,
+ &info->dfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE, &page_link.link);
+ share->pagecache->readwrite_flags= share->pagecache->
+ org_readwrite_flags;
+ if (!buff)
+ {
+ if (my_errno != HA_ERR_FILE_TOO_SHORT &&
+ my_errno != HA_ERR_WRONG_CRC)
+ {
+ /* If not read outside of file */
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ goto err;
+ }
+ /*
+ Physical file was too short, create new page. It can be that
+ recovery started with a file with N pages, wrote page N+2 into
+ pagecache (increased data_file_length but not physical file
+ length), now reads page N+1: the read fails.
+ */
+ buff= pagecache_block_link_to_buffer(page_link.link);
+ make_empty_page(info, buff, BLOB_PAGE, 0);
+ }
+ else
+ {
+#ifndef DBUG_OFF
+ uchar found_page_type= (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK);
+#endif
+ if (lsn_korr(buff) >= lsn)
+ {
+ /* Already applied */
+ DBUG_PRINT("info", ("already applied %llu >= %llu",
+ lsn_korr(buff), lsn));
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ continue;
+ }
+ DBUG_ASSERT((found_page_type == (uchar) BLOB_PAGE) ||
+ (found_page_type == (uchar) UNALLOCATED_PAGE));
+ }
+ unlock_method= PAGECACHE_LOCK_WRITE_UNLOCK;
+ unpin_method= PAGECACHE_UNPIN;
+ }
+
+ /*
+ Blob pages are never updated twice in same redo-undo chain, so
+ it's safe to update lsn for them here
+ */
+ lsn_store(buff, lsn);
+ buff[PAGE_TYPE_OFFSET]= BLOB_PAGE;
+
+ length= data_size;
+ if (i == 0 && sub_ranges == 0)
+ {
+ /*
+ Last page may be only partly filled. We zero the rest, like
+ write_full_pages() does.
+ */
+ length-= empty_space;
+ bzero(buff + share->block_size - PAGE_SUFFIX_SIZE - empty_space,
+ empty_space);
+ }
+ memcpy(buff+ PAGE_TYPE_OFFSET + 1, data, length);
+ data+= length;
+ if (pagecache_write(share->pagecache,
+ &info->dfile, page, 0,
+ buff, PAGECACHE_PLAIN_PAGE,
+ unlock_method, unpin_method,
+ PAGECACHE_WRITE_DELAY, 0, LSN_IMPOSSIBLE))
+ goto err;
+ }
+ /** @todo leave bitmap lock to the bitmap code... */
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+ res= _ma_bitmap_set_full_page_bits(info, &share->bitmap, start_page,
+ page_range);
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ if (res)
+ goto err;
+ }
+ }
+ *first_page= first_page2;
+ *last_page= last_page2;
+ DBUG_RETURN(0);
+
+err:
+ _ma_mark_file_crashed(share);
+ DBUG_ASSERT(0);
+ DBUG_RETURN(1);
+}
+
+
+/****************************************************************************
+ Applying of UNDO entries
+****************************************************************************/
+
+/** Execute undo of a row insert (delete the inserted row) */
+
+my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header)
+{
+ pgcache_page_no_t page;
+ uint rownr;
+ uchar *buff;
+ my_bool res= 1;
+ MARIA_PINNED_PAGE page_link;
+ MARIA_SHARE *share= info->s;
+ ha_checksum checksum;
+ LSN lsn;
+ DBUG_ENTER("_ma_apply_undo_row_insert");
+
+ page= page_korr(header);
+ header+= PAGE_STORE_SIZE;
+ rownr= dirpos_korr(header);
+ header+= DIRPOS_STORE_SIZE;
+ DBUG_PRINT("enter", ("rowid: %lu page: %lu rownr: %u",
+ (ulong) ma_recordpos(page, rownr),
+ (ulong) page, rownr));
+
+ buff= pagecache_read(share->pagecache,
+ &info->dfile, page, 0,
+ 0, share->page_type,
+ PAGECACHE_LOCK_WRITE,
+ &page_link.link);
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= buff != 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ if (!buff)
+ goto err;
+
+ if (read_row_extent_info(info, buff, rownr))
+ goto err;
+
+ _ma_bitmap_flushable(info, 1);
+ if (delete_head_or_tail(info, page, rownr, 1, 1) ||
+ delete_tails(info, info->cur_row.tail_positions))
+ goto err;
+
+ if (info->cur_row.extents_count && free_full_pages(info, &info->cur_row))
+ goto err;
+
+ checksum= 0;
+ if (share->calc_checksum)
+ checksum= (ha_checksum) 0 - ha_checksum_korr(header);
+ info->last_auto_increment= ~ (ulonglong) 0;
+ if (_ma_write_clr(info, undo_lsn, LOGREC_UNDO_ROW_INSERT,
+ share->calc_checksum != 0, checksum, &lsn, (void*) 0))
+ goto err;
+
+ res= 0;
+err:
+ if (info->non_flushable_state)
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+ DBUG_RETURN(res);
+}
+
+
+/** Execute undo of a row delete (insert the row back where it was) */
+
+my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header, size_t header_length
+ __attribute__((unused)))
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_ROW row;
+ MARIA_COLUMNDEF *column, *end_column;
+ MARIA_BITMAP_BLOCKS *blocks;
+ struct st_row_pos_info row_pos;
+ uchar *record;
+ const uchar *null_bits, *field_length_data, *extent_info;
+ pgcache_page_no_t page;
+ ulong *blob_lengths;
+ uint *null_field_lengths, extent_count, rownr, length_on_head_page;
+ DBUG_ENTER("_ma_apply_undo_row_delete");
+
+ /*
+ Use cur row as a base; We need to make a copy as we will change
+ some buffers to point directly to 'header'
+ */
+ memcpy(&row, &info->cur_row, sizeof(row));
+
+ page= page_korr(header);
+ header+= PAGE_STORE_SIZE;
+ rownr= dirpos_korr(header);
+ header+= DIRPOS_STORE_SIZE;
+ length_on_head_page= uint2korr(header);
+ header+= 2;
+ extent_count= pagerange_korr(header);
+ header+= PAGERANGE_STORE_SIZE;
+ DBUG_PRINT("enter", ("rowid: %lu page: %lu rownr: %u",
+ (ulong) ma_recordpos(page, rownr),
+ (ulong) page, rownr));
+
+ if (share->calc_checksum)
+ {
+ /*
+ We extract the checksum delta here, saving a recomputation in
+ allocate_and_write_block_record(). It's only an optimization.
+ */
+ row.checksum= (ha_checksum) 0 - ha_checksum_korr(header);
+ header+= HA_CHECKSUM_STORE_SIZE;
+ }
+ extent_info= header;
+ header+= extent_count * ROW_EXTENT_SIZE;
+
+ null_field_lengths= row.null_field_lengths;
+ blob_lengths= row.blob_lengths;
+
+ /*
+ Fill in info->cur_row with information about the row, like in
+ calc_record_size(), to be used by write_block_record()
+ */
+
+ row.normal_length= row.char_length= row.varchar_length=
+ row.blob_length= row.extents_count= row.field_lengths_length= 0;
+
+ null_bits= header;
+ header+= share->base.null_bytes;
+ /* This will not be changed */
+ row.empty_bits= (uchar*) header;
+ header+= share->base.pack_bytes;
+ if (share->base.max_field_lengths)
+ {
+ row.field_lengths_length= uint2korr(header);
+ row.field_lengths= (uchar*) header + 2 ;
+ header+= 2 + row.field_lengths_length;
+ }
+ if (share->base.blobs)
+ row.blob_length= ma_get_length(&header);
+
+ /* We need to build up a record (without blobs) in rec_buff */
+ if (!(record= my_malloc(share->base.reclength, MYF(MY_WME))))
+ DBUG_RETURN(1);
+
+ memcpy(record, null_bits, share->base.null_bytes);
+
+ /* Copy field information from header to record */
+
+ /* Handle constant length fields that are always present */
+ for (column= share->columndef,
+ end_column= column+ share->base.fixed_not_null_fields;
+ column < end_column;
+ column++)
+ {
+ memcpy(record + column->offset, header, column->length);
+ header+= column->length;
+ }
+
+ /* Handle NULL fields and CHAR/VARCHAR fields */
+ field_length_data= row.field_lengths;
+ for (end_column= share->columndef + share->base.fields;
+ column < end_column;
+ column++, null_field_lengths++)
+ {
+ if ((record[column->null_pos] & column->null_bit) ||
+ row.empty_bits[column->empty_pos] & column->empty_bit)
+ {
+ if (column->type != FIELD_BLOB)
+ *null_field_lengths= 0;
+ else
+ *blob_lengths++= 0;
+ if (share->calc_checksum)
+ bfill(record + column->offset, column->fill_length,
+ column->type == FIELD_SKIP_ENDSPACE ? ' ' : 0);
+ continue;
+ }
+ switch (column->type) {
+ case FIELD_CHECK:
+ case FIELD_NORMAL: /* Fixed length field */
+ case FIELD_ZERO:
+ case FIELD_SKIP_PRESPACE: /* Not packed */
+ case FIELD_SKIP_ZERO: /* Fixed length field */
+ row.normal_length+= column->length;
+ *null_field_lengths= column->length;
+ memcpy(record + column->offset, header, column->length);
+ header+= column->length;
+ break;
+ case FIELD_SKIP_ENDSPACE: /* CHAR */
+ {
+ uint length;
+ if (column->length <= 255)
+ length= (uint) *field_length_data++;
+ else
+ {
+ length= uint2korr(field_length_data);
+ field_length_data+= 2;
+ }
+ row.char_length+= length;
+ *null_field_lengths= length;
+ memcpy(record + column->offset, header, length);
+ if (share->calc_checksum)
+ bfill(record + column->offset + length, (column->length - length),
+ ' ');
+ header+= length;
+ break;
+ }
+ case FIELD_VARCHAR:
+ {
+ uint length;
+ uchar *field_pos= record + column->offset;
+
+ /* 256 is correct as this includes the length uchar */
+ if (column->fill_length == 1)
+ {
+ field_pos[0]= *field_length_data;
+ length= (uint) *field_length_data;
+ }
+ else
+ {
+ field_pos[0]= field_length_data[0];
+ field_pos[1]= field_length_data[1];
+ length= uint2korr(field_length_data);
+ }
+ field_length_data+= column->fill_length;
+ field_pos+= column->fill_length;
+ row.varchar_length+= length;
+ *null_field_lengths= length;
+ memcpy(field_pos, header, length);
+ header+= length;
+ break;
+ }
+ case FIELD_BLOB:
+ {
+ /* Copy length of blob and pointer to blob data to record */
+ uchar *field_pos= record + column->offset;
+ uint size_length= column->length - portable_sizeof_char_ptr;
+ ulong blob_length= _ma_calc_blob_length(size_length, field_length_data);
+
+ memcpy(field_pos, field_length_data, size_length);
+ field_length_data+= size_length;
+ memcpy(field_pos + size_length, &header, sizeof(&header));
+ header+= blob_length;
+ *blob_lengths++= blob_length;
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ row.head_length= (info->row_base_length +
+ share->base.fixed_not_null_fields_length +
+ row.field_lengths_length +
+ size_to_store_key_length(row.field_lengths_length) +
+ row.normal_length +
+ row.char_length + row.varchar_length);
+ row.total_length= (row.head_length + row.blob_length);
+ if (row.total_length < share->base.min_block_length)
+ row.total_length= share->base.min_block_length;
+
+ /*
+ Row is now generated. Now we need to insert record on the original
+ pages with original size on each page.
+ */
+
+ _ma_bitmap_flushable(info, 1);
+ /* Change extent information to be usable by write_block_record() */
+ blocks= &row.insert_blocks;
+ if (extent_to_bitmap_blocks(info, blocks, page, extent_count, extent_info))
+ goto err;
+ blocks->block->org_bitmap_value= _ma_bitmap_get_page_bits(info,
+ &share->bitmap,
+ page);
+ blocks->block->used|= BLOCKUSED_USE_ORG_BITMAP;
+
+ /* Read head page and allocate data for rowid */
+ if (get_rowpos_in_head_or_tail_page(info, blocks->block,
+ info->buff,
+ length_on_head_page,
+ HEAD_PAGE, PAGECACHE_LOCK_WRITE,
+ rownr, &row_pos))
+ goto err;
+
+ if (share->calc_checksum)
+ {
+ DBUG_ASSERT(row.checksum == (share->calc_checksum)(info, record));
+ }
+ if (write_block_record(info, (uchar*) 0, record, &row,
+ blocks, blocks->block->org_bitmap_value != 0,
+ &row_pos, undo_lsn, 0))
+ goto err;
+
+ my_free(record, MYF(0));
+ DBUG_RETURN(0);
+
+err:
+ if (info->non_flushable_state)
+ _ma_bitmap_flushable(info, -1);
+ _ma_unpin_all_pages_and_finalize_row(info, LSN_IMPOSSIBLE);
+ my_free(record, MYF(0));
+ DBUG_RETURN(1);
+}
+
+
+/**
+ Execute undo of a row update
+
+ @fn _ma_apply_undo_row_update()
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header,
+ size_t header_length
+ __attribute__((unused)))
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_RECORD_POS record_pos;
+ const uchar *field_length_data, *field_length_data_end, *extent_info;
+ uchar *current_record, *orig_record;
+ pgcache_page_no_t page;
+ ha_checksum checksum_delta;
+ uint rownr, field_length_header, extent_count, length_on_head_page;
+ int error= 1;
+ DBUG_ENTER("_ma_apply_undo_row_update");
+ LINT_INIT(checksum_delta);
+
+ page= page_korr(header);
+ header+= PAGE_STORE_SIZE;
+ rownr= dirpos_korr(header);
+ header+= DIRPOS_STORE_SIZE;
+ record_pos= ma_recordpos(page, rownr);
+ DBUG_PRINT("enter", ("rowid: %lu page: %lu rownr: %u",
+ (ulong) record_pos, (ulong) page, rownr));
+
+ if (share->calc_checksum)
+ {
+ checksum_delta= ha_checksum_korr(header);
+ header+= HA_CHECKSUM_STORE_SIZE;
+ }
+ length_on_head_page= uint2korr(header);
+ header+= 2;
+ extent_count= pagerange_korr(header);
+ header+= PAGERANGE_STORE_SIZE;
+ extent_info= header;
+ header+= extent_count * ROW_EXTENT_SIZE;
+
+ /*
+ Set header to point to old field values, generated by
+ fill_update_undo_parts()
+ */
+ field_length_header= ma_get_length(&header);
+ field_length_data= (uchar*) header;
+ header+= field_length_header;
+ field_length_data_end= header;
+
+ /* Allocate buffer for current row & original row */
+ if (!(current_record= my_malloc(share->base.reclength * 2, MYF(MY_WME))))
+ DBUG_RETURN(1);
+ orig_record= current_record+ share->base.reclength;
+
+ /* Read current record */
+ if (_ma_read_block_record(info, current_record, record_pos))
+ goto err;
+
+ if (*field_length_data == 255)
+ {
+ /* Bitmap changed */
+ field_length_data++;
+ memcpy(orig_record, header, share->base.null_bytes);
+ header+= share->base.null_bytes;
+ }
+ else
+ memcpy(orig_record, current_record, share->base.null_bytes);
+ bitmap_clear_all(&info->changed_fields);
+
+ while (field_length_data < field_length_data_end)
+ {
+ uint field_nr= ma_get_length(&field_length_data), field_length;
+ MARIA_COLUMNDEF *column= share->columndef + field_nr;
+ uchar *orig_field_pos= orig_record + column->offset;
+
+ bitmap_set_bit(&info->changed_fields, field_nr);
+ if (field_nr >= share->base.fixed_not_null_fields)
+ {
+ if (!(field_length= ma_get_length(&field_length_data)))
+ {
+ /* Null field or empty field */
+ bfill(orig_field_pos, column->fill_length,
+ column->type == FIELD_SKIP_ENDSPACE ? ' ' : 0);
+ continue;
+ }
+ }
+ else
+ field_length= column->length;
+
+ switch (column->type) {
+ case FIELD_CHECK:
+ case FIELD_NORMAL: /* Fixed length field */
+ case FIELD_ZERO:
+ case FIELD_SKIP_PRESPACE: /* Not packed */
+ memcpy(orig_field_pos, header, column->length);
+ header+= column->length;
+ break;
+ case FIELD_SKIP_ZERO: /* Number */
+ case FIELD_SKIP_ENDSPACE: /* CHAR */
+ {
+ uint diff;
+ memcpy(orig_field_pos, header, field_length);
+ if ((diff= (column->length - field_length)))
+ bfill(orig_field_pos + column->length - diff, diff,
+ column->type == FIELD_SKIP_ENDSPACE ? ' ' : 0);
+ header+= field_length;
+ }
+ break;
+ case FIELD_VARCHAR:
+ if (column->length <= 256)
+ {
+ *orig_field_pos++= (uchar) field_length;
+ }
+ else
+ {
+ int2store(orig_field_pos, field_length);
+ orig_field_pos+= 2;
+ }
+ memcpy(orig_field_pos, header, field_length);
+ header+= field_length;
+ break;
+ case FIELD_BLOB:
+ {
+ uint size_length= column->length - portable_sizeof_char_ptr;
+ _ma_store_blob_length(orig_field_pos, size_length, field_length);
+ memcpy_fixed(orig_field_pos + size_length, &header, sizeof(header));
+ header+= field_length;
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ copy_not_changed_fields(info, &info->changed_fields,
+ orig_record, current_record);
+
+ if (share->calc_checksum)
+ {
+ info->new_row.checksum= checksum_delta +
+ (info->cur_row.checksum= (*share->calc_checksum)(info, orig_record));
+ /* verify that record's content is sane */
+ DBUG_ASSERT(info->new_row.checksum ==
+ (*share->calc_checksum)(info, current_record));
+ }
+
+ info->last_auto_increment= ~ (ulonglong) 0;
+ /* Now records are up to date, execute the update to original values */
+ if (_ma_update_at_original_place(info, page, rownr, length_on_head_page,
+ extent_count, extent_info,
+ current_record, orig_record, undo_lsn))
+ goto err;
+
+ error= 0;
+err:
+ my_free(current_record, MYF(0));
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Execute undo of a bulk insert which used repair
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool _ma_apply_undo_bulk_insert(MARIA_HA *info, LSN undo_lsn)
+{
+ my_bool error;
+ LSN lsn;
+ DBUG_ENTER("_ma_apply_undo_bulk_insert");
+ /*
+ We delete all rows, re-enable indices as bulk insert had disabled
+ non-unique ones.
+ */
+ error= (maria_delete_all_rows(info) ||
+ maria_enable_indexes(info) ||
+ /* we enabled indices so need '2' below */
+ _ma_state_info_write(info->s,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO |
+ MA_STATE_INFO_WRITE_LOCK) ||
+ _ma_write_clr(info, undo_lsn, LOGREC_UNDO_BULK_INSERT,
+ FALSE, 0, &lsn, NULL));
+ DBUG_RETURN(error);
+}
+
+
+/**
+ @brief Get the TRANSLOG_ADDRESS to flush up to
+
+ @param page Page's content
+ @param page_no Page's number (<offset>/<page length>)
+ @param data_ptr Callback data pointer (pointer to MARIA_SHARE)
+
+ @note
+ Usable for data (non-bitmap) and index pages
+
+ @retval LSN to flush up to
+*/
+
+TRANSLOG_ADDRESS
+maria_page_get_lsn(uchar *page,
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar* data_ptr __attribute__((unused)))
+{
+#ifndef DBUG_OFF
+ const MARIA_SHARE *share= (MARIA_SHARE*)data_ptr;
+ DBUG_ASSERT(share->page_type == PAGECACHE_LSN_PAGE &&
+ share->now_transactional);
+#endif
+ return lsn_korr(page);
+}
+
+
+/**
+ @brief Enable reading of all rows, ignoring versioning
+
+ @note
+ This is mainly useful in single user applications, like maria_pack,
+ where we want to be able to read all rows without having to read the
+ transaction id from the control file
+*/
+
+void maria_ignore_trids(MARIA_HA *info)
+{
+ if (info->s->base.born_transactional)
+ {
+ if (!info->trn)
+ _ma_set_trn_for_table(info, &dummy_transaction_object);
+ /* Ignore transaction id when row is read */
+ info->trn->min_read_from= ~(TrID) 0;
+ }
+}
diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h
new file mode 100644
index 00000000000..cb682eef701
--- /dev/null
+++ b/storage/maria/ma_blockrec.h
@@ -0,0 +1,285 @@
+/* Copyright (C) 2007 Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Storage of records in block
+*/
+
+#define LSN_SIZE 7
+#define DIR_COUNT_SIZE 1 /* Stores number of rows on page */
+#define DIR_FREE_SIZE 1 /* Pointer to first free dir entry */
+#define EMPTY_SPACE_SIZE 2 /* Stores empty space on page */
+#define PAGE_TYPE_SIZE 1
+#define PAGE_SUFFIX_SIZE 4 /* Bytes for checksum */
+#define PAGE_HEADER_SIZE (LSN_SIZE + DIR_COUNT_SIZE + DIR_FREE_SIZE +\
+ EMPTY_SPACE_SIZE + PAGE_TYPE_SIZE)
+#define PAGE_OVERHEAD_SIZE (PAGE_HEADER_SIZE + DIR_ENTRY_SIZE + \
+ PAGE_SUFFIX_SIZE)
+#define BLOCK_RECORD_POINTER_SIZE 6
+
+#define FULL_PAGE_SIZE(block_size) ((block_size) - LSN_SIZE - \
+ PAGE_TYPE_SIZE - PAGE_SUFFIX_SIZE)
+
+#define ROW_EXTENT_PAGE_SIZE 5
+#define ROW_EXTENT_COUNT_SIZE 2
+#define SUB_RANGE_SIZE 2
+#define BLOCK_FILLER_SIZE 2
+#define ROW_EXTENT_SIZE (ROW_EXTENT_PAGE_SIZE + ROW_EXTENT_COUNT_SIZE)
+#define TAIL_BIT 0x8000 /* Bit in page_count to signify tail */
+#define START_EXTENT_BIT 0x4000 /* Bit in page_count to signify start*/
+/* page_count set by bitmap code for tail pages */
+#define TAIL_PAGE_COUNT_MARKER 0xffff
+/* Number of extents reserved MARIA_BITMAP_BLOCKS to store head part */
+#define ELEMENTS_RESERVED_FOR_MAIN_PART 4
+/* This is just used to prealloc a dynamic array */
+#define AVERAGE_BLOB_SIZE 1024L*1024L
+/* Number of pages to store continuous blob parts */
+#define BLOB_SEGMENT_MIN_SIZE 128
+
+/* Fields before 'row->null_field_lengths' used by find_where_to_split_row */
+#define EXTRA_LENGTH_FIELDS 3
+
+/* Size for the different parts in the row header (and head page) */
+#define FLAG_SIZE 1
+#define VERPTR_SIZE 7
+#define DIR_ENTRY_SIZE 4
+#define FIELD_OFFSET_SIZE 2 /* size of pointers to field starts */
+
+/* Minimum header size needed for a new row */
+#define BASE_ROW_HEADER_SIZE FLAG_SIZE
+#define TRANS_ROW_EXTRA_HEADER_SIZE TRANSID_SIZE
+
+#define PAGE_TYPE_MASK 7
+enum en_page_type { UNALLOCATED_PAGE, HEAD_PAGE, TAIL_PAGE, BLOB_PAGE, MAX_PAGE_TYPE };
+#define PAGE_CAN_BE_COMPACTED 128 /* Bit in PAGE_TYPE */
+
+#define PAGE_TYPE_OFFSET LSN_SIZE
+#define DIR_COUNT_OFFSET (LSN_SIZE+PAGE_TYPE_SIZE)
+#define DIR_FREE_OFFSET (DIR_COUNT_OFFSET+DIR_COUNT_SIZE)
+#define EMPTY_SPACE_OFFSET (DIR_FREE_OFFSET+DIR_FREE_SIZE)
+
+/* Bits used for flag uchar (one byte, first in record) */
+#define ROW_FLAG_TRANSID 1
+#define ROW_FLAG_VER_PTR 2
+#define ROW_FLAG_DELETE_TRANSID 4
+#define ROW_FLAG_NULLS_EXTENDED 8
+#define ROW_FLAG_EXTENTS 128
+#define ROW_FLAG_ALL (1+2+4+8+128)
+
+/******** Variables that affects how data pages are utilized ********/
+
+/* Minium size of tail segment */
+#define MIN_TAIL_SIZE 32
+
+/*
+ Fixed length part of Max possible header size; See row data structure
+ table in ma_blockrec.c.
+*/
+#define MAX_FIXED_HEADER_SIZE (FLAG_SIZE + 3 + ROW_EXTENT_SIZE + 3)
+#define TRANS_MAX_FIXED_HEADER_SIZE (MAX_FIXED_HEADER_SIZE + \
+ TRANSID_SIZE + VERPTR_SIZE + \
+ TRANSID_SIZE)
+
+/* We use 1 uchar in record header to store number of directory entries */
+#define MAX_ROWS_PER_PAGE 255
+#define END_OF_DIR_FREE_LIST ((uchar) 255)
+
+/* Bits for MARIA_BITMAP_BLOCKS->used */
+/* We stored data on disk in the block */
+#define BLOCKUSED_USED 1
+/* Bitmap on disk is block->org_bitmap_value ; Happens only on update */
+#define BLOCKUSED_USE_ORG_BITMAP 2
+/* We stored tail data on disk for the block */
+#define BLOCKUSED_TAIL 4
+
+/******* defines that affects allocation (density) of data *******/
+
+/*
+ If the tail part (from the main block or a blob) would use more than 75 % of
+ the size of page, store the tail on a full page instead of a shared
+ tail page.
+*/
+#define MAX_TAIL_SIZE(block_size) ((block_size) *3 / 4)
+
+/* Don't allocate memory for too many row extents on the stack */
+#define ROW_EXTENTS_ON_STACK 32
+
+/* Functions to convert MARIA_RECORD_POS to/from page:offset */
+
+static inline MARIA_RECORD_POS ma_recordpos(pgcache_page_no_t page,
+ uint dir_entry)
+{
+ DBUG_ASSERT(dir_entry <= 255);
+ DBUG_ASSERT(page > 0); /* page 0 is bitmap, not data page */
+ return (MARIA_RECORD_POS) (((ulonglong) page << 8) | dir_entry);
+}
+
+static inline pgcache_page_no_t ma_recordpos_to_page(MARIA_RECORD_POS record_pos)
+{
+ return (pgcache_page_no_t) (record_pos >> 8);
+}
+
+static inline uint ma_recordpos_to_dir_entry(MARIA_RECORD_POS record_pos)
+{
+ return (uint) (record_pos & 255);
+}
+
+static inline uchar *dir_entry_pos(uchar *buff, uint block_size, uint pos)
+{
+ return (buff + block_size - DIR_ENTRY_SIZE * pos - PAGE_SUFFIX_SIZE -
+ DIR_ENTRY_SIZE);
+}
+
+/* ma_blockrec.c */
+void _ma_init_block_record_data(void);
+my_bool _ma_once_init_block_record(MARIA_SHARE *share, File dfile);
+my_bool _ma_once_end_block_record(MARIA_SHARE *share);
+my_bool _ma_init_block_record(MARIA_HA *info);
+void _ma_end_block_record(MARIA_HA *info);
+
+my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS pos,
+ const uchar *oldrec, const uchar *newrec);
+my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record);
+int _ma_read_block_record(MARIA_HA *info, uchar *record,
+ MARIA_RECORD_POS record_pos);
+int _ma_read_block_record2(MARIA_HA *info, uchar *record,
+ uchar *data, uchar *end_of_data);
+int _ma_scan_block_record(MARIA_HA *info, uchar *record,
+ MARIA_RECORD_POS, my_bool);
+my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
+ const uchar *record, MARIA_RECORD_POS pos);
+my_bool _ma_scan_init_block_record(MARIA_HA *info);
+void _ma_scan_end_block_record(MARIA_HA *info);
+int _ma_scan_remember_block_record(MARIA_HA *info,
+ MARIA_RECORD_POS *lastpos);
+void _ma_scan_restore_block_record(MARIA_HA *info,
+ MARIA_RECORD_POS lastpos);
+
+MARIA_RECORD_POS _ma_write_init_block_record(MARIA_HA *info,
+ const uchar *record);
+my_bool _ma_write_block_record(MARIA_HA *info, const uchar *record);
+my_bool _ma_write_abort_block_record(MARIA_HA *info);
+my_bool _ma_compare_block_record(register MARIA_HA *info,
+ register const uchar *record);
+void _ma_compact_block_page(uchar *buff, uint block_size, uint rownr,
+ my_bool extend_block, TrID min_read_from,
+ uint min_row_length);
+TRANSLOG_ADDRESS
+maria_page_get_lsn(uchar *page, pgcache_page_no_t page_no, uchar* data_ptr);
+
+/* ma_bitmap.c */
+my_bool _ma_bitmap_init(MARIA_SHARE *share, File file);
+my_bool _ma_bitmap_end(MARIA_SHARE *share);
+my_bool _ma_bitmap_flush(MARIA_SHARE *share);
+my_bool _ma_bitmap_flush_all(MARIA_SHARE *share);
+void _ma_bitmap_reset_cache(MARIA_SHARE *share);
+my_bool _ma_bitmap_find_place(MARIA_HA *info, MARIA_ROW *row,
+ MARIA_BITMAP_BLOCKS *result_blocks);
+my_bool _ma_bitmap_release_unused(MARIA_HA *info, MARIA_BITMAP_BLOCKS *blocks);
+my_bool _ma_bitmap_free_full_pages(MARIA_HA *info, const uchar *extents,
+ uint count);
+my_bool _ma_bitmap_set(MARIA_HA *info, pgcache_page_no_t pos, my_bool head,
+ uint empty_space);
+my_bool _ma_bitmap_reset_full_page_bits(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page,
+ uint page_count);
+my_bool _ma_bitmap_set_full_page_bits(MARIA_HA *info,
+ MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page, uint page_count);
+uint _ma_free_size_to_head_pattern(MARIA_FILE_BITMAP *bitmap, uint size);
+my_bool _ma_bitmap_find_new_place(MARIA_HA *info, MARIA_ROW *new_row,
+ pgcache_page_no_t page, uint free_size,
+ MARIA_BITMAP_BLOCKS *result_blocks);
+my_bool _ma_check_bitmap_data(MARIA_HA *info,
+ enum en_page_type page_type,
+ pgcache_page_no_t page,
+ uint empty_space, uint *bitmap_pattern);
+my_bool _ma_check_if_right_bitmap_type(MARIA_HA *info,
+ enum en_page_type page_type,
+ pgcache_page_no_t page,
+ uint *bitmap_pattern);
+uint _ma_bitmap_get_page_bits(MARIA_HA *info, MARIA_FILE_BITMAP *bitmap,
+ pgcache_page_no_t page);
+void _ma_bitmap_delete_all(MARIA_SHARE *share);
+int _ma_bitmap_create_first(MARIA_SHARE *share);
+void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc);
+void _ma_bitmap_set_pagecache_callbacks(PAGECACHE_FILE *file,
+ MARIA_SHARE *share);
+#ifndef DBUG_OFF
+void _ma_print_bitmap(MARIA_FILE_BITMAP *bitmap, uchar *data,
+ pgcache_page_no_t page);
+#endif
+
+uint _ma_apply_redo_insert_row_head_or_tail(MARIA_HA *info, LSN lsn,
+ uint page_type,
+ my_bool new_page,
+ const uchar *header,
+ const uchar *data,
+ size_t data_length);
+uint _ma_apply_redo_purge_row_head_or_tail(MARIA_HA *info, LSN lsn,
+ uint page_type,
+ const uchar *header);
+uint _ma_apply_redo_free_blocks(MARIA_HA *info, LSN lsn,
+ const uchar *header);
+uint _ma_apply_redo_free_head_or_tail(MARIA_HA *info, LSN lsn,
+ const uchar *header);
+uint _ma_apply_redo_insert_row_blobs(MARIA_HA *info, LSN lsn,
+ const uchar *header, LSN redo_lsn,
+ uint * const number_of_blobs,
+ uint * const number_of_ranges,
+ pgcache_page_no_t * const first_page,
+ pgcache_page_no_t * const last_page);
+my_bool _ma_apply_redo_bitmap_new_page(MARIA_HA *info, LSN lsn,
+ const uchar *header);
+my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header);
+my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header, size_t length);
+my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header, size_t length);
+my_bool _ma_apply_undo_bulk_insert(MARIA_HA *info, LSN undo_lsn);
+
+my_bool write_hook_for_redo(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+my_bool write_hook_for_undo(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+my_bool write_hook_for_redo_delete_all(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_undo_row_insert(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_undo_row_delete(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_undo_row_update(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_undo_bulk_insert(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+my_bool write_hook_for_file_id(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+my_bool write_hook_for_commit(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+void _ma_block_get_status(void* param, my_bool concurrent_insert);
+void _ma_block_update_status(void *param);
+void _ma_block_restore_status(void *param);
+my_bool _ma_block_check_status(void *param);
diff --git a/storage/maria/ma_cache.c b/storage/maria/ma_cache.c
new file mode 100644
index 00000000000..82b5ddd8047
--- /dev/null
+++ b/storage/maria/ma_cache.c
@@ -0,0 +1,107 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Functions for read record cacheing with maria
+ Used for reading dynamic/compressed records from datafile.
+
+ Can fetch data directly from file (outside cache),
+ if reading a small chunk straight before the cached part (with possible
+ overlap).
+
+ Can be explicitly asked not to use cache (by not setting READING_NEXT in
+ flag) - useful for occasional out-of-cache reads, when the next read is
+ expected to hit the cache again.
+
+ Allows "partial read" errors in the record header (when READING_HEADER flag
+ is set) - unread part is bzero'ed
+
+ Note: out-of-cache reads are enabled for shared IO_CACHE's too,
+ as these reads will be cached by OS cache (and my_pread is always atomic)
+*/
+
+
+#include "maria_def.h"
+
+my_bool _ma_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos,
+ size_t length, uint flag)
+{
+ size_t read_length,in_buff_length;
+ my_off_t offset;
+ uchar *in_buff_pos;
+ DBUG_ENTER("_ma_read_cache");
+
+ if (pos < info->pos_in_file)
+ {
+ read_length=length;
+ if ((my_off_t) read_length > (my_off_t) (info->pos_in_file-pos))
+ read_length=(uint) (info->pos_in_file-pos);
+ info->seek_not_done=1;
+ if (my_pread(info->file,buff,read_length,pos,MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ if (!(length-=read_length))
+ DBUG_RETURN(0);
+ pos+=read_length;
+ buff+=read_length;
+ }
+ if (pos >= info->pos_in_file &&
+ (offset= (my_off_t) (pos - info->pos_in_file)) <
+ (my_off_t) (info->read_end - info->request_pos))
+ {
+ in_buff_pos=info->request_pos+(uint) offset;
+ in_buff_length= min(length,(size_t) (info->read_end-in_buff_pos));
+ memcpy(buff,info->request_pos+(uint) offset,(size_t) in_buff_length);
+ if (!(length-=in_buff_length))
+ DBUG_RETURN(0);
+ pos+=in_buff_length;
+ buff+=in_buff_length;
+ }
+ else
+ in_buff_length=0;
+ if (flag & READING_NEXT)
+ {
+ if (pos != (info->pos_in_file +
+ (uint) (info->read_end - info->request_pos)))
+ {
+ info->pos_in_file=pos; /* Force start here */
+ info->read_pos=info->read_end=info->request_pos; /* Everything used */
+ info->seek_not_done=1;
+ }
+ else
+ info->read_pos=info->read_end; /* All block used */
+ if (!(*info->read_function)(info,buff,length))
+ DBUG_RETURN(0);
+ read_length=info->error;
+ }
+ else
+ {
+ info->seek_not_done=1;
+ if ((read_length=my_pread(info->file,buff,length,pos,MYF(0))) == length)
+ DBUG_RETURN(0);
+ }
+ if (!(flag & READING_HEADER) || (int) read_length == -1 ||
+ read_length+in_buff_length < 3)
+ {
+ DBUG_PRINT("error",
+ ("Error %d reading next-multi-part block (Got %d bytes)",
+ my_errno, (int) read_length));
+ if (!my_errno || my_errno == HA_ERR_FILE_TOO_SHORT)
+ my_errno= HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ bzero(buff+read_length,MARIA_BLOCK_INFO_HEADER_LENGTH - in_buff_length -
+ read_length);
+ DBUG_RETURN(0);
+} /* _ma_read_cache */
diff --git a/storage/maria/ma_changed.c b/storage/maria/ma_changed.c
new file mode 100644
index 00000000000..4d0964581f6
--- /dev/null
+++ b/storage/maria/ma_changed.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Check if somebody has changed table since last check. */
+
+#include "maria_def.h"
+
+ /* Return 0 if table isn't changed */
+
+int maria_is_changed(MARIA_HA *info)
+{
+ int result;
+ DBUG_ENTER("maria_is_changed");
+ if (fast_ma_readinfo(info))
+ DBUG_RETURN(-1);
+ VOID(_ma_writeinfo(info,0));
+ result=(int) info->data_changed;
+ info->data_changed=0;
+ DBUG_PRINT("exit",("result: %d",result));
+ DBUG_RETURN(result);
+}
diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c
new file mode 100644
index 00000000000..8f5e07e27f2
--- /dev/null
+++ b/storage/maria/ma_check.c
@@ -0,0 +1,6692 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Describe, check and repair of MARIA tables */
+
+/*
+ About checksum calculation.
+
+ There are two types of checksums. Table checksum and row checksum.
+
+ Row checksum is an additional uchar at the end of dynamic length
+ records. It must be calculated if the table is configured for them.
+ Otherwise they must not be used. The variable
+ MYISAM_SHARE::calc_checksum determines if row checksums are used.
+ MI_INFO::checksum is used as temporary storage during row handling.
+ For parallel repair we must assure that only one thread can use this
+ variable. There is no problem on the write side as this is done by one
+ thread only. But when checking a record after read this could go
+ wrong. But since all threads read through a common read buffer, it is
+ sufficient if only one thread checks it.
+
+ Table checksum is an eight uchar value in the header of the index file.
+ It can be calculated even if row checksums are not used. The variable
+ MI_CHECK::glob_crc is calculated over all records.
+ MI_SORT_PARAM::calc_checksum determines if this should be done. This
+ variable is not part of MI_CHECK because it must be set per thread for
+ parallel repair. The global glob_crc must be changed by one thread
+ only. And it is sufficient to calculate the checksum once only.
+*/
+
+#include "ma_ftdefs.h"
+#include "ma_rt_index.h"
+#include "ma_blockrec.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+
+#include <stdarg.h>
+#include <my_getopt.h>
+#ifdef HAVE_SYS_VADVISE_H
+#include <sys/vadvise.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+/* Functions defined in this file */
+
+static int check_k_link(HA_CHECK *param, MARIA_HA *info, my_off_t next_link);
+static int chk_index(HA_CHECK *param, MARIA_HA *info,MARIA_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, ha_rows *keys,
+ ha_checksum *key_checksum, uint level);
+static uint isam_key_length(MARIA_HA *info,MARIA_KEYDEF *keyinfo);
+static ha_checksum calc_checksum(ha_rows count);
+static int writekeys(MARIA_SORT_PARAM *sort_param);
+static int sort_one_index(HA_CHECK *param, MARIA_HA *info,
+ MARIA_KEYDEF *keyinfo,
+ my_off_t pagepos, File new_file);
+static int sort_key_read(MARIA_SORT_PARAM *sort_param, uchar *key);
+static int sort_maria_ft_key_read(MARIA_SORT_PARAM *sort_param, uchar *key);
+static int sort_get_next_record(MARIA_SORT_PARAM *sort_param);
+static int sort_key_cmp(MARIA_SORT_PARAM *sort_param, const void *a,
+ const void *b);
+static int sort_maria_ft_key_write(MARIA_SORT_PARAM *sort_param,
+ const uchar *a);
+static int sort_key_write(MARIA_SORT_PARAM *sort_param, const uchar *a);
+static my_off_t get_record_for_key(MARIA_KEYDEF *keyinfo, const uchar *key);
+static int sort_insert_key(MARIA_SORT_PARAM *sort_param,
+ reg1 SORT_KEY_BLOCKS *key_block,
+ const uchar *key, my_off_t prev_block);
+static int sort_delete_record(MARIA_SORT_PARAM *sort_param);
+/*static int _ma_flush_pending_blocks(HA_CHECK *param);*/
+static SORT_KEY_BLOCKS *alloc_key_blocks(HA_CHECK *param, uint blocks,
+ uint buffer_length);
+static ha_checksum maria_byte_checksum(const uchar *buf, uint length);
+static void set_data_file_type(MARIA_SORT_INFO *sort_info, MARIA_SHARE *share);
+static void restore_data_file_type(MARIA_SHARE *share);
+static void change_data_file_descriptor(MARIA_HA *info, File new_file);
+static void unuse_data_file_descriptor(MARIA_HA *info);
+static int _ma_safe_scan_block_record(MARIA_SORT_INFO *sort_info,
+ MARIA_HA *info, uchar *record);
+static void copy_data_file_state(MARIA_STATE_INFO *to,
+ MARIA_STATE_INFO *from);
+static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
+ my_off_t position);
+static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file);
+static my_bool _ma_flush_table_files_before_swap(HA_CHECK *param,
+ MARIA_HA *info);
+static TrID max_trid_in_system(void);
+static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid);
+void retry_if_quick(MARIA_SORT_PARAM *param, int error);
+
+
+/* Initialize check param with default values */
+
+void maria_chk_init(HA_CHECK *param)
+{
+ bzero((uchar*) param,sizeof(*param));
+ param->opt_follow_links=1;
+ param->keys_in_use= ~(ulonglong) 0;
+ param->search_after_block=HA_OFFSET_ERROR;
+ param->auto_increment_value= 0;
+ param->use_buffers=USE_BUFFER_INIT;
+ param->read_buffer_length=READ_BUFFER_INIT;
+ param->write_buffer_length=READ_BUFFER_INIT;
+ param->sort_buffer_length=SORT_BUFFER_INIT;
+ param->sort_key_blocks=BUFFERS_WHEN_SORTING;
+ param->tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
+ param->myf_rw=MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL);
+ param->start_check_pos=0;
+ param->max_record_length= LONGLONG_MAX;
+ param->pagecache_block_size= KEY_CACHE_BLOCK_SIZE;
+ param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
+}
+
+
+/* Initialize check param and maria handler for check of table */
+
+void maria_chk_init_for_check(HA_CHECK *param, MARIA_HA *info)
+{
+ param->not_visible_rows_found= 0;
+ param->max_found_trid= 0;
+
+ /*
+ Set up transaction handler so that we can see all rows. When rows is read
+ we will check the found id against param->max_tried
+ */
+ if (!ma_control_file_inited())
+ param->max_trid= 0; /* Give warning for first trid found */
+ else
+ param->max_trid= max_trid_in_system();
+
+ maria_ignore_trids(info);
+}
+
+
+ /* Check the status flags for the table */
+
+int maria_chk_status(HA_CHECK *param, MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+
+ if (maria_is_crashed_on_repair(info))
+ _ma_check_print_warning(param,
+ "Table is marked as crashed and last repair failed");
+ else if (maria_is_crashed(info))
+ _ma_check_print_warning(param,
+ "Table is marked as crashed");
+ if (share->state.open_count != (uint) (share->global_changed ? 1 : 0))
+ {
+ /* Don't count this as a real warning, as check can correct this ! */
+ uint save=param->warning_printed;
+ _ma_check_print_warning(param,
+ share->state.open_count==1 ?
+ "%d client is using or hasn't closed the table properly" :
+ "%d clients are using or haven't closed the table properly",
+ share->state.open_count);
+ /* If this will be fixed by the check, forget the warning */
+ if (param->testflag & T_UPDATE_STATE)
+ param->warning_printed=save;
+ }
+ return 0;
+}
+
+/*
+ Check delete links in row data
+*/
+
+int maria_chk_del(HA_CHECK *param, register MARIA_HA *info,
+ ulonglong test_flag)
+{
+ MARIA_SHARE *share= info->s;
+ reg2 ha_rows i;
+ uint delete_link_length;
+ my_off_t empty,next_link,old_link;
+ char buff[22],buff2[22];
+ DBUG_ENTER("maria_chk_del");
+
+ LINT_INIT(old_link);
+
+ param->record_checksum=0;
+
+ if (share->data_file_type == BLOCK_RECORD)
+ DBUG_RETURN(0); /* No delete links here */
+
+ delete_link_length=((share->options & HA_OPTION_PACK_RECORD) ? 20 :
+ share->rec_reflength+1);
+
+ if (!(test_flag & T_SILENT))
+ puts("- check record delete-chain");
+
+ next_link=share->state.dellink;
+ if (share->state.state.del == 0)
+ {
+ if (test_flag & T_VERBOSE)
+ {
+ puts("No recordlinks");
+ }
+ }
+ else
+ {
+ if (test_flag & T_VERBOSE)
+ printf("Recordlinks: ");
+ empty=0;
+ for (i= share->state.state.del ; i > 0L && next_link != HA_OFFSET_ERROR ; i--)
+ {
+ if (*_ma_killed_ptr(param))
+ DBUG_RETURN(1);
+ if (test_flag & T_VERBOSE)
+ printf(" %9s",llstr(next_link,buff));
+ if (next_link >= share->state.state.data_file_length)
+ goto wrong;
+ if (my_pread(info->dfile.file, (uchar*) buff, delete_link_length,
+ next_link,MYF(MY_NABP)))
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ _ma_check_print_error(param,"Can't read delete-link at filepos: %s",
+ llstr(next_link,buff));
+ DBUG_RETURN(1);
+ }
+ if (*buff != '\0')
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ _ma_check_print_error(param,"Record at pos: %s is not remove-marked",
+ llstr(next_link,buff));
+ goto wrong;
+ }
+ if (share->options & HA_OPTION_PACK_RECORD)
+ {
+ my_off_t prev_link=mi_sizekorr(buff+12);
+ if (empty && prev_link != old_link)
+ {
+ if (test_flag & T_VERBOSE) puts("");
+ _ma_check_print_error(param,"Deleted block at %s doesn't point back at previous delete link",llstr(next_link,buff2));
+ goto wrong;
+ }
+ old_link=next_link;
+ next_link=mi_sizekorr(buff+4);
+ empty+=mi_uint3korr(buff+1);
+ }
+ else
+ {
+ param->record_checksum+=(ha_checksum) next_link;
+ next_link= _ma_rec_pos(share, (uchar *) buff + 1);
+ empty+=share->base.pack_reclength;
+ }
+ }
+ if (share->state.state.del && (test_flag & T_VERBOSE))
+ puts("\n");
+ if (empty != share->state.state.empty)
+ {
+ _ma_check_print_warning(param,
+ "Found %s deleted space in delete link chain. Should be %s",
+ llstr(empty,buff2),
+ llstr(share->state.state.empty,buff));
+ }
+ if (next_link != HA_OFFSET_ERROR)
+ {
+ _ma_check_print_error(param,
+ "Found more than the expected %s deleted rows in delete link chain",
+ llstr(share->state.state.del, buff));
+ goto wrong;
+ }
+ if (i != 0)
+ {
+ _ma_check_print_error(param,
+ "Found %s deleted rows in delete link chain. Should be %s",
+ llstr(share->state.state.del - i, buff2),
+ llstr(share->state.state.del, buff));
+ goto wrong;
+ }
+ }
+ DBUG_RETURN(0);
+
+wrong:
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ if (test_flag & T_VERBOSE)
+ puts("");
+ _ma_check_print_error(param,"record delete-link-chain corrupted");
+ DBUG_RETURN(1);
+} /* maria_chk_del */
+
+
+/* Check delete links in index file */
+
+static int check_k_link(HA_CHECK *param, register MARIA_HA *info,
+ my_off_t next_link)
+{
+ MARIA_SHARE *share= info->s;
+ uint block_size= share->block_size;
+ ha_rows records;
+ char llbuff[21], llbuff2[21];
+ uchar *buff;
+ DBUG_ENTER("check_k_link");
+
+ if (next_link == HA_OFFSET_ERROR)
+ DBUG_RETURN(0); /* Avoid printing empty line */
+
+ records= (ha_rows) (share->state.state.key_file_length / block_size);
+ while (next_link != HA_OFFSET_ERROR && records > 0)
+ {
+ if (*_ma_killed_ptr(param))
+ DBUG_RETURN(1);
+ if (param->testflag & T_VERBOSE)
+ printf("%16s",llstr(next_link,llbuff));
+
+ /* Key blocks must lay within the key file length entirely. */
+ if (next_link + block_size > share->state.state.key_file_length)
+ {
+ /* purecov: begin tested */
+ _ma_check_print_error(param, "Invalid key block position: %s "
+ "key block size: %u file_length: %s",
+ llstr(next_link, llbuff), block_size,
+ llstr(share->state.state.key_file_length, llbuff2));
+ DBUG_RETURN(1);
+ /* purecov: end */
+ }
+
+ /* Key blocks must be aligned at block_size */
+ if (next_link & (block_size -1))
+ {
+ /* purecov: begin tested */
+ _ma_check_print_error(param, "Mis-aligned key block: %s "
+ "minimum key block length: %u",
+ llstr(next_link, llbuff),
+ block_size);
+ DBUG_RETURN(1);
+ /* purecov: end */
+ }
+
+ DBUG_ASSERT(share->pagecache->block_size == block_size);
+ if (!(buff= pagecache_read(share->pagecache,
+ &share->kfile,
+ (pgcache_page_no_t) (next_link / block_size),
+ DFLT_INIT_HITS,
+ (uchar*) info->buff,
+ PAGECACHE_READ_UNKNOWN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ {
+ /* purecov: begin tested */
+ _ma_check_print_error(param, "key cache read error for block: %s",
+ llstr(next_link,llbuff));
+ DBUG_RETURN(1);
+ /* purecov: end */
+ }
+ if (_ma_get_keynr(info->s, buff) != MARIA_DELETE_KEY_NR)
+ _ma_check_print_error(param, "Page at %s is not delete marked",
+ llstr(next_link, llbuff));
+
+ next_link= mi_sizekorr(buff + share->keypage_header);
+ records--;
+ param->key_file_blocks+=block_size;
+ }
+ if (param->testflag & T_VERBOSE)
+ {
+ if (next_link != HA_OFFSET_ERROR)
+ printf("%16s\n",llstr(next_link,llbuff));
+ else
+ puts("");
+ }
+ DBUG_RETURN (next_link != HA_OFFSET_ERROR);
+} /* check_k_link */
+
+
+ /* Check sizes of files */
+
+int maria_chk_size(HA_CHECK *param, register MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ int error;
+ register my_off_t skr,size;
+ char buff[22],buff2[22];
+ DBUG_ENTER("maria_chk_size");
+
+ if (!(param->testflag & T_SILENT))
+ puts("- check file-size");
+
+ /*
+ The following is needed if called externally (not from maria_chk).
+ To get a correct physical size we need to flush them.
+ */
+ if ((error= _ma_flush_table_files(info,
+ MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE)))
+ _ma_check_print_error(param, "Failed to flush data or index file");
+
+ size= my_seek(share->kfile.file, 0L, MY_SEEK_END, MYF(MY_THREADSAFE));
+ if ((skr=(my_off_t) share->state.state.key_file_length) != size)
+ {
+ /* Don't give error if file generated by mariapack */
+ if (skr > size && maria_is_any_key_active(share->state.key_map))
+ {
+ error=1;
+ _ma_check_print_error(param,
+ "Size of indexfile is: %-8s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ }
+ else if (!(param->testflag & T_VERY_SILENT))
+ _ma_check_print_warning(param,
+ "Size of indexfile is: %-8s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ }
+ if (!(param->testflag & T_VERY_SILENT) &&
+ ! (share->options & HA_OPTION_COMPRESS_RECORD) &&
+ ulonglong2double(share->state.state.key_file_length) >
+ ulonglong2double(share->base.margin_key_file_length)*0.9)
+ _ma_check_print_warning(param,"Keyfile is almost full, %10s of %10s used",
+ llstr(share->state.state.key_file_length,buff),
+ llstr(share->base.max_key_file_length-1,buff));
+
+ size= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
+ skr=(my_off_t) share->state.state.data_file_length;
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ skr+= MEMMAP_EXTRA_MARGIN;
+#ifdef USE_RELOC
+ if (share->data_file_type == STATIC_RECORD &&
+ skr < (my_off_t) share->base.reloc*share->base.min_pack_length)
+ skr=(my_off_t) share->base.reloc*share->base.min_pack_length;
+#endif
+ if (skr != size)
+ {
+ if (skr > size && skr != size + MEMMAP_EXTRA_MARGIN)
+ {
+ share->state.state.data_file_length=size; /* Skip other errors */
+ error=1;
+ _ma_check_print_error(param,"Size of datafile is: %-9s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ }
+ else
+ {
+ _ma_check_print_warning(param,
+ "Size of datafile is: %-9s Should be: %s",
+ llstr(size,buff), llstr(skr,buff2));
+ }
+ }
+ if (!(param->testflag & T_VERY_SILENT) &&
+ !(share->options & HA_OPTION_COMPRESS_RECORD) &&
+ ulonglong2double(share->state.state.data_file_length) >
+ (ulonglong2double(share->base.max_data_file_length)*0.9))
+ _ma_check_print_warning(param, "Datafile is almost full, %10s of %10s used",
+ llstr(share->state.state.data_file_length,buff),
+ llstr(share->base.max_data_file_length-1,buff2));
+ DBUG_RETURN(error);
+} /* maria_chk_size */
+
+
+/* Check keys */
+
+int maria_chk_key(HA_CHECK *param, register MARIA_HA *info)
+{
+ uint key,found_keys=0,full_text_keys=0,result=0;
+ ha_rows keys;
+ ha_checksum old_record_checksum,init_checksum;
+ my_off_t all_keydata,all_totaldata,key_totlength,length;
+ double *rec_per_key_part;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo;
+ char buff[22],buff2[22];
+ DBUG_ENTER("maria_chk_key");
+
+ if (!(param->testflag & T_SILENT))
+ puts("- check key delete-chain");
+
+ param->key_file_blocks=share->base.keystart;
+ if (check_k_link(param, info, share->state.key_del))
+ {
+ if (param->testflag & T_VERBOSE) puts("");
+ _ma_check_print_error(param,"key delete-link-chain corrupted");
+ DBUG_RETURN(-1);
+ }
+
+ if (!(param->testflag & T_SILENT))
+ puts("- check index reference");
+
+ all_keydata=all_totaldata=key_totlength=0;
+ init_checksum=param->record_checksum;
+ old_record_checksum=0;
+ if (share->data_file_type == STATIC_RECORD)
+ old_record_checksum= (calc_checksum(share->state.state.records +
+ share->state.state.del-1) *
+ share->base.pack_reclength);
+ rec_per_key_part= param->new_rec_per_key_part;
+ for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
+ rec_per_key_part+=keyinfo->keysegs, key++, keyinfo++)
+ {
+ param->key_crc[key]=0;
+ if (! maria_is_key_active(share->state.key_map, key))
+ {
+ /* Remember old statistics for key */
+ memcpy((char*) rec_per_key_part,
+ (char*) (share->state.rec_per_key_part +
+ (uint) (rec_per_key_part - param->new_rec_per_key_part)),
+ keyinfo->keysegs*sizeof(*rec_per_key_part));
+ continue;
+ }
+ found_keys++;
+
+ param->record_checksum=init_checksum;
+
+ bzero((char*) &param->unique_count,sizeof(param->unique_count));
+ bzero((char*) &param->notnull_count,sizeof(param->notnull_count));
+
+ if ((!(param->testflag & T_SILENT)))
+ printf ("- check data record references index: %d\n",key+1);
+ if (keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL))
+ full_text_keys++;
+ if (share->state.key_root[key] == HA_OFFSET_ERROR)
+ {
+ if (share->state.state.records != 0 && !(keyinfo->flag & HA_FULLTEXT))
+ _ma_check_print_error(param, "Key tree %u is empty", key + 1);
+ goto do_stat;
+ }
+ if (!_ma_fetch_keypage(info, keyinfo, share->state.key_root[key],
+ PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS,
+ info->buff, 0, 0))
+ {
+ report_keypage_fault(param, info, share->state.key_root[key]);
+ if (!(param->testflag & T_INFO))
+ DBUG_RETURN(-1);
+ result= -1;
+ continue;
+ }
+ param->key_file_blocks+=keyinfo->block_length;
+ keys=0;
+ param->keydata=param->totaldata=0;
+ param->key_blocks=0;
+ param->max_level=0;
+ if (chk_index(param,info,keyinfo,share->state.key_root[key],info->buff,
+ &keys, param->key_crc+key,1))
+ DBUG_RETURN(-1);
+ if (!(keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL | HA_RTREE_INDEX)))
+ {
+ if (keys != share->state.state.records)
+ {
+ _ma_check_print_error(param,"Found %s keys of %s",llstr(keys,buff),
+ llstr(share->state.state.records,buff2));
+ if (!(param->testflag & T_INFO))
+ DBUG_RETURN(-1);
+ result= -1;
+ continue;
+ }
+ if ((found_keys - full_text_keys == 1 &&
+ !(share->data_file_type == STATIC_RECORD)) ||
+ (param->testflag & T_DONT_CHECK_CHECKSUM))
+ old_record_checksum= param->record_checksum;
+ else if (old_record_checksum != param->record_checksum)
+ {
+ if (key)
+ _ma_check_print_error(param,
+ "Key %u doesn't point at same records as "
+ "key 1",
+ key+1);
+ else
+ _ma_check_print_error(param,"Key 1 doesn't point at all records");
+ if (!(param->testflag & T_INFO))
+ DBUG_RETURN(-1);
+ result= -1;
+ continue;
+ }
+ }
+ if ((uint) share->base.auto_key -1 == key)
+ {
+ /* Check that auto_increment key is bigger than max key value */
+ ulonglong auto_increment;
+ const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
+ info->lastinx=key;
+ _ma_read_key_record(info, info->rec_buff, 0);
+ auto_increment=
+ ma_retrieve_auto_increment(info->rec_buff + keyseg->start,
+ keyseg->type);
+ if (auto_increment > share->state.auto_increment)
+ {
+ _ma_check_print_warning(param, "Auto-increment value: %s is smaller "
+ "than max used value: %s",
+ llstr(share->state.auto_increment,buff2),
+ llstr(auto_increment, buff));
+ }
+ if (param->testflag & T_AUTO_INC)
+ {
+ set_if_bigger(share->state.auto_increment,
+ auto_increment);
+ set_if_bigger(share->state.auto_increment,
+ param->auto_increment_value);
+ }
+
+ /* Check that there isn't a row with auto_increment = 0 in the table */
+ maria_extra(info,HA_EXTRA_KEYREAD,0);
+ bzero(info->lastkey_buff, keyinfo->seg->length);
+ if (!maria_rkey(info, info->rec_buff, key,
+ info->lastkey_buff,
+ (key_part_map) 1, HA_READ_KEY_EXACT))
+ {
+ /* Don't count this as a real warning, as maria_chk can't correct it */
+ uint save=param->warning_printed;
+ _ma_check_print_warning(param, "Found row where the auto_increment "
+ "column has the value 0");
+ param->warning_printed=save;
+ }
+ maria_extra(info,HA_EXTRA_NO_KEYREAD,0);
+ }
+
+ length=(my_off_t) isam_key_length(info,keyinfo)*keys + param->key_blocks*2;
+ if (param->testflag & T_INFO && param->totaldata != 0L && keys != 0L)
+ printf("Key: %2d: Keyblocks used: %3d%% Packed: %4d%% Max levels: %2d\n",
+ key+1,
+ (int) (my_off_t2double(param->keydata)*100.0/my_off_t2double(param->totaldata)),
+ (int) ((my_off_t2double(length) - my_off_t2double(param->keydata))*100.0/
+ my_off_t2double(length)),
+ param->max_level);
+ all_keydata+=param->keydata; all_totaldata+=param->totaldata; key_totlength+=length;
+
+do_stat:
+ if (param->testflag & T_STATISTICS)
+ maria_update_key_parts(keyinfo, rec_per_key_part, param->unique_count,
+ param->stats_method == MI_STATS_METHOD_IGNORE_NULLS?
+ param->notnull_count: NULL,
+ (ulonglong)share->state.state.records);
+ }
+ if (param->testflag & T_INFO)
+ {
+ if (all_totaldata != 0L && found_keys > 0)
+ printf("Total: Keyblocks used: %3d%% Packed: %4d%%\n\n",
+ (int) (my_off_t2double(all_keydata)*100.0/
+ my_off_t2double(all_totaldata)),
+ (int) ((my_off_t2double(key_totlength) -
+ my_off_t2double(all_keydata))*100.0/
+ my_off_t2double(key_totlength)));
+ else if (all_totaldata != 0L && maria_is_any_key_active(share->state.key_map))
+ puts("");
+ }
+ if (param->key_file_blocks != share->state.state.key_file_length &&
+ share->state.key_map == ~(ulonglong) 0)
+ _ma_check_print_warning(param, "Some data are unreferenced in keyfile");
+ if (found_keys != full_text_keys)
+ param->record_checksum=old_record_checksum-init_checksum; /* Remove delete links */
+ else
+ param->record_checksum=0;
+ DBUG_RETURN(result);
+} /* maria_chk_key */
+
+
+
+static int chk_index_down(HA_CHECK *param, MARIA_HA *info,
+ MARIA_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, ha_rows *keys,
+ ha_checksum *key_checksum, uint level)
+{
+ char llbuff[22],llbuff2[22];
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("chk_index_down");
+
+ /* Key blocks must lay within the key file length entirely. */
+ if (page + keyinfo->block_length > share->state.state.key_file_length)
+ {
+ /* purecov: begin tested */
+ /* Give it a chance to fit in the real file size. */
+ my_off_t max_length= my_seek(info->s->kfile.file, 0L, MY_SEEK_END,
+ MYF(MY_THREADSAFE));
+ _ma_check_print_error(param, "Invalid key block position: %s "
+ "key block size: %u file_length: %s",
+ llstr(page, llbuff), keyinfo->block_length,
+ llstr(share->state.state.key_file_length, llbuff2));
+ if (page + keyinfo->block_length > max_length)
+ goto err;
+ /* Fix the remembered key file length. */
+ share->state.state.key_file_length= (max_length &
+ ~ (my_off_t) (keyinfo->block_length -
+ 1));
+ /* purecov: end */
+ }
+
+ /* Key blocks must be aligned at block length */
+ if (page & (info->s->block_size -1))
+ {
+ /* purecov: begin tested */
+ _ma_check_print_error(param, "Mis-aligned key block: %s "
+ "key block length: %u",
+ llstr(page, llbuff), info->s->block_size);
+ goto err;
+ /* purecov: end */
+ }
+
+ if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, buff, 0, 0))
+ {
+ report_keypage_fault(param, info, page);
+ goto err;
+ }
+ param->key_file_blocks+=keyinfo->block_length;
+ if (chk_index(param,info,keyinfo,page,buff,keys,key_checksum,level))
+ goto err;
+
+ DBUG_RETURN(0);
+
+ /* purecov: begin tested */
+err:
+ DBUG_RETURN(1);
+ /* purecov: end */
+}
+
+
+/*
+ "Ignore NULLs" statistics collection method: process first index tuple.
+
+ SYNOPSIS
+ maria_collect_stats_nonulls_first()
+ keyseg IN Array of key part descriptions
+ notnull INOUT Array, notnull[i] = (number of {keypart1...keypart_i}
+ tuples that don't contain NULLs)
+ key IN Key values tuple
+
+ DESCRIPTION
+ Process the first index tuple - find out which prefix tuples don't
+ contain NULLs, and update the array of notnull counters accordingly.
+*/
+
+static
+void maria_collect_stats_nonulls_first(HA_KEYSEG *keyseg, ulonglong *notnull,
+ const uchar *key)
+{
+ uint first_null, kp;
+ first_null= ha_find_null(keyseg, key) - keyseg;
+ /*
+ All prefix tuples that don't include keypart_{first_null} are not-null
+ tuples (and all others aren't), increment counters for them.
+ */
+ for (kp= 0; kp < first_null; kp++)
+ notnull[kp]++;
+}
+
+
+/*
+ "Ignore NULLs" statistics collection method: process next index tuple.
+
+ SYNOPSIS
+ maria_collect_stats_nonulls_next()
+ keyseg IN Array of key part descriptions
+ notnull INOUT Array, notnull[i] = (number of {keypart1...keypart_i}
+ tuples that don't contain NULLs)
+ prev_key IN Previous key values tuple
+ last_key IN Next key values tuple
+
+ DESCRIPTION
+ Process the next index tuple:
+ 1. Find out which prefix tuples of last_key don't contain NULLs, and
+ update the array of notnull counters accordingly.
+ 2. Find the first keypart number where the prev_key and last_key tuples
+ are different(A), or last_key has NULL value(B), and return it, so the
+ caller can count number of unique tuples for each key prefix. We don't
+ need (B) to be counted, and that is compensated back in
+ maria_update_key_parts().
+
+ RETURN
+ 1 + number of first keypart where values differ or last_key tuple has NULL
+*/
+
+static
+int maria_collect_stats_nonulls_next(HA_KEYSEG *keyseg, ulonglong *notnull,
+ const uchar *prev_key,
+ const uchar *last_key)
+{
+ uint diffs[2];
+ uint first_null_seg, kp;
+ HA_KEYSEG *seg;
+
+ /*
+ Find the first keypart where values are different or either of them is
+ NULL. We get results in diffs array:
+ diffs[0]= 1 + number of first different keypart
+ diffs[1]=offset: (last_key + diffs[1]) points to first value in
+ last_key that is NULL or different from corresponding
+ value in prev_key.
+ */
+ ha_key_cmp(keyseg, prev_key, last_key, USE_WHOLE_KEY,
+ SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diffs);
+ seg= keyseg + diffs[0] - 1;
+
+ /* Find first NULL in last_key */
+ first_null_seg= ha_find_null(seg, last_key + diffs[1]) - keyseg;
+ for (kp= 0; kp < first_null_seg; kp++)
+ notnull[kp]++;
+
+ /*
+ Return 1+ number of first key part where values differ. Don't care if
+ these were NULLs and not .... We compensate for that in
+ maria_update_key_parts.
+ */
+ return diffs[0];
+}
+
+
+/* Check if index is ok */
+
+static int chk_index(HA_CHECK *param, MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, ha_rows *keys,
+ ha_checksum *key_checksum, uint level)
+{
+ int flag;
+ uint used_length,comp_flag,page_flag,nod_flag;
+ uchar *temp_buff, *keypos, *old_keypos, *endpos;
+ my_off_t next_page,record;
+ MARIA_SHARE *share= info->s;
+ char llbuff[22];
+ uint diff_pos[2];
+ uchar tmp_key_buff[MARIA_MAX_KEY_BUFF];
+ MARIA_KEY tmp_key;
+ DBUG_ENTER("chk_index");
+ DBUG_DUMP("buff", buff, _ma_get_page_used(share, buff));
+
+ /* TODO: implement appropriate check for RTree keys */
+ if (keyinfo->flag & (HA_SPATIAL | HA_RTREE_INDEX))
+ DBUG_RETURN(0);
+
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ _ma_check_print_error(param,"Not enough memory for keyblock");
+ DBUG_RETURN(-1);
+ }
+
+ if (keyinfo->flag & HA_NOSAME)
+ {
+ /* Not real duplicates */
+ comp_flag=SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT;
+ }
+ else
+ comp_flag=SEARCH_SAME; /* Keys in positionorder */
+
+ page_flag= _ma_get_keypage_flag(share, buff);
+ _ma_get_used_and_nod_with_flag(share, page_flag, buff, used_length,
+ nod_flag);
+ old_keypos= buff + share->keypage_header;
+ keypos= old_keypos+ nod_flag;
+ endpos= buff + used_length;
+
+ param->keydata+= used_length;
+ param->totaldata+= keyinfo->block_length; /* INFO */
+ param->key_blocks++;
+ if (level > param->max_level)
+ param->max_level=level;
+
+ if (_ma_get_keynr(share, buff) != (uint) (keyinfo - share->keyinfo))
+ _ma_check_print_error(param, "Page at %s is not marked for index %u",
+ llstr(page, llbuff),
+ (uint) (keyinfo - share->keyinfo));
+ if ((page_flag & KEYPAGE_FLAG_HAS_TRANSID) &&
+ !share->base.born_transactional)
+ {
+ _ma_check_print_error(param,
+ "Page at %s is marked with HAS_TRANSID even if "
+ "table is not transactional",
+ llstr(page, llbuff));
+ }
+
+ if (used_length > (uint) keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)
+ {
+ _ma_check_print_error(param,"Page at %s has impossible (too big) pagelength",
+ llstr(page,llbuff));
+ goto err;
+ }
+
+ info->last_key.keyinfo= tmp_key.keyinfo= keyinfo;
+ tmp_key.data= tmp_key_buff;
+ for ( ;; )
+ {
+ if (*_ma_killed_ptr(param))
+ goto err;
+ if (nod_flag)
+ {
+ next_page= _ma_kpos(nod_flag,keypos);
+ if (chk_index_down(param,info,keyinfo,next_page,
+ temp_buff,keys,key_checksum,level+1))
+ {
+ DBUG_DUMP("page_data", old_keypos, (uint) (keypos - old_keypos));
+ goto err;
+ }
+ }
+ old_keypos=keypos;
+ if (keypos >= endpos ||
+ !(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &keypos))
+ break;
+ if (keypos > endpos)
+ {
+ _ma_check_print_error(param,
+ "Page length and length of keys don't match at "
+ "page: %s",
+ llstr(page,llbuff));
+ goto err;
+ }
+ if (share->data_file_type == BLOCK_RECORD &&
+ !(page_flag & KEYPAGE_FLAG_HAS_TRANSID) &&
+ key_has_transid(tmp_key.data + tmp_key.data_length +
+ share->rec_reflength-1))
+ {
+ _ma_check_print_error(param,
+ "Found key marked for transid on page that is not "
+ "marked for transid at: %s",
+ llstr(page,llbuff));
+ goto err;
+ }
+
+ if ((*keys)++ &&
+ (flag=ha_key_cmp(keyinfo->seg, info->last_key.data, tmp_key.data,
+ tmp_key.data_length + tmp_key.ref_length,
+ (comp_flag | SEARCH_INSERT | (tmp_key.flag >> 1) |
+ info->last_key.flag), diff_pos)) >=0)
+ {
+ DBUG_DUMP_KEY("old", &info->last_key);
+ DBUG_DUMP_KEY("new", &tmp_key);
+ DBUG_DUMP("new_in_page", old_keypos, (uint) (keypos-old_keypos));
+
+ if ((comp_flag & SEARCH_FIND) && flag == 0)
+ _ma_check_print_error(param,"Found duplicated key at page %s",
+ llstr(page,llbuff));
+ else
+ _ma_check_print_error(param,"Key in wrong position at page %s",
+ llstr(page,llbuff));
+ goto err;
+ }
+
+ if (param->testflag & T_STATISTICS)
+ {
+ if (*keys != 1L) /* not first_key */
+ {
+ if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
+ ha_key_cmp(keyinfo->seg, (uchar*) info->last_key.data,
+ tmp_key.data, tmp_key.data_length,
+ SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
+ diff_pos);
+ else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
+ {
+ diff_pos[0]= maria_collect_stats_nonulls_next(keyinfo->seg,
+ param->notnull_count,
+ info->last_key.data,
+ tmp_key.data);
+ }
+ param->unique_count[diff_pos[0]-1]++;
+ }
+ else
+ {
+ if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
+ maria_collect_stats_nonulls_first(keyinfo->seg, param->notnull_count,
+ tmp_key.data);
+ }
+ }
+ _ma_copy_key(&info->last_key, &tmp_key);
+ (*key_checksum)+= maria_byte_checksum(tmp_key.data, tmp_key.data_length);
+ record= _ma_row_pos_from_key(&tmp_key);
+
+ if (keyinfo->flag & HA_FULLTEXT) /* special handling for ft2 */
+ {
+ uint off;
+ int subkeys;
+ get_key_full_length_rdonly(off, tmp_key.data);
+ subkeys= ft_sintXkorr(tmp_key.data + off);
+ if (subkeys < 0)
+ {
+ ha_rows tmp_keys=0;
+ if (chk_index_down(param,info,&share->ft2_keyinfo,record,
+ temp_buff,&tmp_keys,key_checksum,1))
+ goto err;
+ if (tmp_keys + subkeys)
+ {
+ _ma_check_print_error(param,
+ "Number of words in the 2nd level tree "
+ "does not match the number in the header. "
+ "Parent word in on the page %s, offset %u",
+ llstr(page,llbuff), (uint) (old_keypos-buff));
+ goto err;
+ }
+ (*keys)+=tmp_keys-1;
+ continue;
+ }
+ /* fall through */
+ }
+ if ((share->data_file_type != BLOCK_RECORD &&
+ record >= share->state.state.data_file_length) ||
+ (share->data_file_type == BLOCK_RECORD &&
+ ma_recordpos_to_page(record) * share->base.min_block_length >=
+ share->state.state.data_file_length))
+ {
+#ifndef DBUG_OFF
+ char llbuff2[22], llbuff3[22];
+#endif
+ _ma_check_print_error(param,"Found key at page %s that points to record outside datafile",llstr(page,llbuff));
+ DBUG_PRINT("test",("page: %s record: %s filelength: %s",
+ llstr(page,llbuff),llstr(record,llbuff2),
+ llstr(share->state.state.data_file_length,llbuff3)));
+ DBUG_DUMP_KEY("key", &tmp_key);
+ DBUG_DUMP("new_in_page", old_keypos, (uint) (keypos-old_keypos));
+ goto err;
+ }
+ param->record_checksum+= (ha_checksum) record;
+ }
+ if (keypos != endpos)
+ {
+ _ma_check_print_error(param,
+ "Keyblock size at page %s is not correct. "
+ "Block length: %u key length: %u",
+ llstr(page, llbuff), used_length,
+ (uint) (keypos - buff));
+ goto err;
+ }
+ my_afree((uchar*) temp_buff);
+ DBUG_RETURN(0);
+ err:
+ my_afree((uchar*) temp_buff);
+ DBUG_RETURN(1);
+} /* chk_index */
+
+
+ /* Calculate a checksum of 1+2+3+4...N = N*(N+1)/2 without overflow */
+
+static ha_checksum calc_checksum(ha_rows count)
+{
+ ulonglong sum,a,b;
+ DBUG_ENTER("calc_checksum");
+
+ sum=0;
+ a=count; b=count+1;
+ if (a & 1)
+ b>>=1;
+ else
+ a>>=1;
+ while (b)
+ {
+ if (b & 1)
+ sum+=a;
+ a<<=1; b>>=1;
+ }
+ DBUG_PRINT("exit",("sum: %lx",(ulong) sum));
+ DBUG_RETURN((ha_checksum) sum);
+} /* calc_checksum */
+
+
+ /* Calc length of key in normal isam */
+
+static uint isam_key_length(MARIA_HA *info, register MARIA_KEYDEF *keyinfo)
+{
+ uint length;
+ HA_KEYSEG *keyseg;
+ DBUG_ENTER("isam_key_length");
+
+ length= info->s->rec_reflength;
+ for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
+ length+= keyseg->length;
+
+ DBUG_PRINT("exit",("length: %d",length));
+ DBUG_RETURN(length);
+} /* key_length */
+
+
+
+static void record_pos_to_txt(MARIA_HA *info, my_off_t recpos,
+ char *buff)
+{
+ if (info->s->data_file_type != BLOCK_RECORD)
+ llstr(recpos, buff);
+ else
+ {
+ my_off_t page= ma_recordpos_to_page(recpos);
+ uint row= ma_recordpos_to_dir_entry(recpos);
+ char *end= longlong10_to_str(page, buff, 10);
+ *(end++)= ':';
+ longlong10_to_str(row, end, 10);
+ }
+}
+
+
+/*
+ Check that keys in records exist in index tree
+
+ SYNOPSIS
+ check_keys_in_record()
+ param Check paramenter
+ info Maria handler
+ extend Type of check (extended or normal)
+ start_recpos Position to row
+ record Record buffer
+
+ NOTES
+ This function also calculates record checksum & number of rows
+*/
+
+static int check_keys_in_record(HA_CHECK *param, MARIA_HA *info, int extend,
+ my_off_t start_recpos, uchar *record)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo;
+ char llbuff[22+4];
+ uint keynr;
+
+ param->tmp_record_checksum+= (ha_checksum) start_recpos;
+ param->records++;
+ if (param->testflag & T_WRITE_LOOP && param->records % WRITE_COUNT == 0)
+ {
+ printf("%s\r", llstr(param->records, llbuff));
+ VOID(fflush(stdout));
+ }
+
+ /* Check if keys match the record */
+ for (keynr=0, keyinfo= share->keyinfo; keynr < share->base.keys;
+ keynr++, keyinfo++)
+ {
+ if (maria_is_key_active(share->state.key_map, keynr))
+ {
+ MARIA_KEY key;
+ if (!(keyinfo->flag & HA_FULLTEXT))
+ {
+ (*keyinfo->make_key)(info, &key, keynr, info->lastkey_buff, record,
+ start_recpos, 0);
+ if (extend)
+ {
+ /* We don't need to lock the key tree here as we don't allow
+ concurrent threads when running maria_chk
+ */
+ int search_result=
+#ifdef HAVE_RTREE_KEYS
+ (keyinfo->flag & (HA_SPATIAL | HA_RTREE_INDEX)) ?
+ maria_rtree_find_first(info, &key, MBR_EQUAL | MBR_DATA) :
+#endif
+ _ma_search(info, &key, SEARCH_SAME, share->state.key_root[keynr]);
+ if (search_result)
+ {
+ record_pos_to_txt(info, start_recpos, llbuff);
+ _ma_check_print_error(param,
+ "Record at: %14s "
+ "Can't find key for index: %2d",
+ llbuff, keynr+1);
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ return -1;
+ }
+ }
+ else
+ param->tmp_key_crc[keynr]+=
+ maria_byte_checksum(key.data, key.data_length);
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*
+ Functions to loop through all rows and check if they are ok
+
+ NOTES
+ One function for each record format
+
+ RESULT
+ 0 ok
+ -1 Interrupted by user
+ 1 Error
+*/
+
+static int check_static_record(HA_CHECK *param, MARIA_HA *info, int extend,
+ uchar *record)
+{
+ MARIA_SHARE *share= info->s;
+ my_off_t start_recpos, pos;
+ char llbuff[22];
+
+ pos= 0;
+ while (pos < share->state.state.data_file_length)
+ {
+ if (*_ma_killed_ptr(param))
+ return -1;
+ if (my_b_read(&param->read_cache,(uchar*) record,
+ share->base.pack_reclength))
+ {
+ _ma_check_print_error(param,
+ "got error: %d when reading datafile at position: %s",
+ my_errno, llstr(pos, llbuff));
+ return 1;
+ }
+ start_recpos= pos;
+ pos+= share->base.pack_reclength;
+ param->splits++;
+ if (*record == '\0')
+ {
+ param->del_blocks++;
+ param->del_length+= share->base.pack_reclength;
+ continue; /* Record removed */
+ }
+ param->glob_crc+= _ma_static_checksum(info,record);
+ param->used+= share->base.pack_reclength;
+ if (check_keys_in_record(param, info, extend, start_recpos, record))
+ return 1;
+ }
+ return 0;
+}
+
+
+static int check_dynamic_record(HA_CHECK *param, MARIA_HA *info, int extend,
+ uchar *record)
+{
+ MARIA_BLOCK_INFO block_info;
+ MARIA_SHARE *share= info->s;
+ my_off_t start_recpos, start_block, pos;
+ uchar *to;
+ ulong left_length;
+ uint b_type;
+ char llbuff[22],llbuff2[22],llbuff3[22];
+ DBUG_ENTER("check_dynamic_record");
+
+ LINT_INIT(left_length);
+ LINT_INIT(start_recpos);
+ LINT_INIT(to);
+
+ pos= 0;
+ while (pos < share->state.state.data_file_length)
+ {
+ my_bool got_error= 0;
+ int flag;
+ if (*_ma_killed_ptr(param))
+ DBUG_RETURN(-1);
+
+ flag= block_info.second_read=0;
+ block_info.next_filepos=pos;
+ do
+ {
+ if (_ma_read_cache(&param->read_cache,(uchar*) block_info.header,
+ (start_block=block_info.next_filepos),
+ sizeof(block_info.header),
+ (flag ? 0 : READING_NEXT) | READING_HEADER))
+ {
+ _ma_check_print_error(param,
+ "got error: %d when reading datafile at "
+ "position: %s",
+ my_errno, llstr(start_block, llbuff));
+ DBUG_RETURN(1);
+ }
+
+ if (start_block & (MARIA_DYN_ALIGN_SIZE-1))
+ {
+ _ma_check_print_error(param,"Wrong aligned block at %s",
+ llstr(start_block,llbuff));
+ DBUG_RETURN(1);
+ }
+ b_type= _ma_get_block_info(&block_info,-1,start_block);
+ if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & BLOCK_SYNC_ERROR)
+ {
+ if (flag)
+ {
+ _ma_check_print_error(param,"Unexpected byte: %d at link: %s",
+ (int) block_info.header[0],
+ llstr(start_block,llbuff));
+ DBUG_RETURN(1);
+ }
+ pos=block_info.filepos+block_info.block_len;
+ goto next;
+ }
+ if (b_type & BLOCK_DELETED)
+ {
+ if (block_info.block_len < share->base.min_block_length)
+ {
+ _ma_check_print_error(param,
+ "Deleted block with impossible length %lu at %s",
+ block_info.block_len,llstr(pos,llbuff));
+ DBUG_RETURN(1);
+ }
+ if ((block_info.next_filepos != HA_OFFSET_ERROR &&
+ block_info.next_filepos >= share->state.state.data_file_length) ||
+ (block_info.prev_filepos != HA_OFFSET_ERROR &&
+ block_info.prev_filepos >= share->state.state.data_file_length))
+ {
+ _ma_check_print_error(param,"Delete link points outside datafile at %s",
+ llstr(pos,llbuff));
+ DBUG_RETURN(1);
+ }
+ param->del_blocks++;
+ param->del_length+= block_info.block_len;
+ param->splits++;
+ pos= block_info.filepos+block_info.block_len;
+ goto next;
+ }
+ _ma_check_print_error(param,"Wrong bytesec: %d-%d-%d at linkstart: %s",
+ block_info.header[0],block_info.header[1],
+ block_info.header[2],
+ llstr(start_block,llbuff));
+ DBUG_RETURN(1);
+ }
+ if (share->state.state.data_file_length < block_info.filepos+
+ block_info.block_len)
+ {
+ _ma_check_print_error(param,
+ "Recordlink that points outside datafile at %s",
+ llstr(pos,llbuff));
+ got_error=1;
+ break;
+ }
+ param->splits++;
+ if (!flag++) /* First block */
+ {
+ start_recpos=pos;
+ pos=block_info.filepos+block_info.block_len;
+ if (block_info.rec_len > (uint) share->base.max_pack_length)
+ {
+ _ma_check_print_error(param,"Found too long record (%lu) at %s",
+ (ulong) block_info.rec_len,
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ break;
+ }
+ if (share->base.blobs)
+ {
+ if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
+ block_info.rec_len +
+ share->base.extra_rec_buff_size))
+
+ {
+ _ma_check_print_error(param,
+ "Not enough memory (%lu) for blob at %s",
+ (ulong) block_info.rec_len,
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ break;
+ }
+ }
+ to= info->rec_buff;
+ left_length= block_info.rec_len;
+ }
+ if (left_length < block_info.data_len)
+ {
+ _ma_check_print_error(param,"Found too long record (%lu) at %s",
+ (ulong) block_info.data_len,
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ break;
+ }
+ if (_ma_read_cache(&param->read_cache,(uchar*) to,block_info.filepos,
+ (uint) block_info.data_len,
+ flag == 1 ? READING_NEXT : 0))
+ {
+ _ma_check_print_error(param,
+ "got error: %d when reading datafile at position: %s", my_errno, llstr(block_info.filepos, llbuff));
+
+ DBUG_RETURN(1);
+ }
+ to+=block_info.data_len;
+ param->link_used+= block_info.filepos-start_block;
+ param->used+= block_info.filepos - start_block + block_info.data_len;
+ param->empty+= block_info.block_len-block_info.data_len;
+ left_length-= block_info.data_len;
+ if (left_length)
+ {
+ if (b_type & BLOCK_LAST)
+ {
+ _ma_check_print_error(param,
+ "Wrong record length %s of %s at %s",
+ llstr(block_info.rec_len-left_length,llbuff),
+ llstr(block_info.rec_len, llbuff2),
+ llstr(start_recpos,llbuff3));
+ got_error=1;
+ break;
+ }
+ if (share->state.state.data_file_length < block_info.next_filepos)
+ {
+ _ma_check_print_error(param,
+ "Found next-recordlink that points outside datafile at %s",
+ llstr(block_info.filepos,llbuff));
+ got_error=1;
+ break;
+ }
+ }
+ } while (left_length);
+
+ if (! got_error)
+ {
+ if (_ma_rec_unpack(info,record,info->rec_buff,block_info.rec_len) ==
+ MY_FILE_ERROR)
+ {
+ _ma_check_print_error(param,"Found wrong record at %s",
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ }
+ else
+ {
+ ha_checksum checksum= 0;
+ if (share->calc_checksum)
+ checksum= (*share->calc_checksum)(info, record);
+
+ if (param->testflag & (T_EXTEND | T_MEDIUM | T_VERBOSE))
+ {
+ if (_ma_rec_check(info,record, info->rec_buff,block_info.rec_len,
+ test(share->calc_checksum), checksum))
+ {
+ _ma_check_print_error(param,"Found wrong packed record at %s",
+ llstr(start_recpos,llbuff));
+ got_error= 1;
+ }
+ }
+ param->glob_crc+= checksum;
+ }
+
+ if (! got_error)
+ {
+ if (check_keys_in_record(param, info, extend, start_recpos, record))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ DBUG_RETURN(1);
+ }
+ }
+ else if (!flag)
+ pos= block_info.filepos+block_info.block_len;
+next:;
+ }
+ DBUG_RETURN(0);
+}
+
+
+static int check_compressed_record(HA_CHECK *param, MARIA_HA *info, int extend,
+ uchar *record)
+{
+ MARIA_BLOCK_INFO block_info;
+ MARIA_SHARE *share= info->s;
+ my_off_t start_recpos, pos;
+ char llbuff[22];
+ my_bool got_error= 0;
+ DBUG_ENTER("check_compressed_record");
+
+ pos= share->pack.header_length; /* Skip header */
+ while (pos < share->state.state.data_file_length)
+ {
+ if (*_ma_killed_ptr(param))
+ DBUG_RETURN(-1);
+
+ if (_ma_read_cache(&param->read_cache,(uchar*) block_info.header, pos,
+ share->pack.ref_length, READING_NEXT))
+ {
+ _ma_check_print_error(param,
+ "got error: %d when reading datafile at position: %s",
+ my_errno, llstr(pos, llbuff));
+ DBUG_RETURN(1);
+ }
+
+ start_recpos= pos;
+ param->splits++;
+ VOID(_ma_pack_get_block_info(info, &info->bit_buff, &block_info,
+ &info->rec_buff, &info->rec_buff_size, -1,
+ start_recpos));
+ pos=block_info.filepos+block_info.rec_len;
+ if (block_info.rec_len < (uint) share->min_pack_length ||
+ block_info.rec_len > (uint) share->max_pack_length)
+ {
+ _ma_check_print_error(param,
+ "Found block with wrong recordlength: %lu at %s",
+ block_info.rec_len, llstr(start_recpos,llbuff));
+ got_error=1;
+ goto end;
+ }
+ if (_ma_read_cache(&param->read_cache,(uchar*) info->rec_buff,
+ block_info.filepos, block_info.rec_len, READING_NEXT))
+ {
+ _ma_check_print_error(param,
+ "got error: %d when reading datafile at position: %s",
+ my_errno, llstr(block_info.filepos, llbuff));
+ DBUG_RETURN(1);
+ }
+ if (_ma_pack_rec_unpack(info, &info->bit_buff, record,
+ info->rec_buff, block_info.rec_len))
+ {
+ _ma_check_print_error(param,"Found wrong record at %s",
+ llstr(start_recpos,llbuff));
+ got_error=1;
+ goto end;
+ }
+ param->glob_crc+= (*share->calc_checksum)(info,record);
+ param->link_used+= (block_info.filepos - start_recpos);
+ param->used+= (pos-start_recpos);
+
+end:
+ if (! got_error)
+ {
+ if (check_keys_in_record(param, info, extend, start_recpos, record))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ got_error= 0; /* Reset for next loop */
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Check if layout on head or tail page is ok
+
+ NOTES
+ This is for rows-in-block format.
+*/
+
+static int check_page_layout(HA_CHECK *param, MARIA_HA *info,
+ my_off_t page_pos, uchar *page,
+ uint row_count, uint head_empty,
+ uint *real_rows_found, uint *free_slots_found)
+{
+ uint empty, last_row_end, row, first_dir_entry, free_entry, block_size;
+ uint free_entries, prev_free_entry;
+ uchar *dir_entry;
+ char llbuff[22];
+ my_bool error_in_free_list= 0;
+ DBUG_ENTER("check_page_layout");
+
+ block_size= info->s->block_size;
+ empty= 0;
+ last_row_end= PAGE_HEADER_SIZE;
+ *real_rows_found= 0;
+
+ /* Check free directory list */
+ free_entry= (uint) page[DIR_FREE_OFFSET];
+ free_entries= 0;
+ prev_free_entry= END_OF_DIR_FREE_LIST;
+ while (free_entry != END_OF_DIR_FREE_LIST)
+ {
+ uchar *dir;
+ if (free_entry > row_count)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Directory free entry points outside "
+ "directory",
+ llstr(page_pos, llbuff));
+ error_in_free_list= 1;
+ break;
+ }
+ dir= dir_entry_pos(page, block_size, free_entry);
+ if (uint2korr(dir) != 0)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Directory free entry points to "
+ "not deleted entry",
+ llstr(page_pos, llbuff));
+ error_in_free_list= 1;
+ break;
+ }
+ if (dir[2] != prev_free_entry)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Directory free list back pointer "
+ "points to wrong entry",
+ llstr(page_pos, llbuff));
+ error_in_free_list= 1;
+ break;
+ }
+ prev_free_entry= free_entry;
+ free_entry= dir[3];
+ free_entries++;
+ }
+ *free_slots_found= free_entries;
+
+ /* Check directry */
+ dir_entry= page+ block_size - PAGE_SUFFIX_SIZE;
+ first_dir_entry= (block_size - row_count * DIR_ENTRY_SIZE -
+ PAGE_SUFFIX_SIZE);
+ for (row= 0 ; row < row_count ; row++)
+ {
+ uint pos, length;
+ dir_entry-= DIR_ENTRY_SIZE;
+ pos= uint2korr(dir_entry);
+ if (!pos)
+ {
+ free_entries--;
+ if (row == row_count -1)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: First entry in directory is 0",
+ llstr(page_pos, llbuff));
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ DBUG_RETURN(1);
+ }
+ continue; /* Deleted row */
+ }
+ (*real_rows_found)++;
+ length= uint2korr(dir_entry+2);
+ param->used+= length;
+ if (pos < last_row_end)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Row %3u overlapps with previous row",
+ llstr(page_pos, llbuff), row);
+ DBUG_RETURN(1);
+ }
+ empty+= (pos - last_row_end);
+ last_row_end= pos + length;
+ if (last_row_end > first_dir_entry)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Row %3u overlapps with directory",
+ llstr(page_pos, llbuff), row);
+ DBUG_RETURN(1);
+ }
+ }
+ empty+= (first_dir_entry - last_row_end);
+
+ if (empty != head_empty)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Wrong empty size. Stored: %5u Actual: %5u",
+ llstr(page_pos, llbuff), head_empty, empty);
+ param->err_count++;
+ }
+ if (free_entries != 0 && !error_in_free_list)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Directory free link don't include "
+ "all free entries",
+ llstr(page_pos, llbuff));
+ param->err_count++;
+ }
+ DBUG_RETURN(param->err_count &&
+ (param->err_count >= MAXERR || !(param->testflag & T_VERBOSE)));
+}
+
+
+/*
+ Check all rows on head page
+
+ NOTES
+ This is for rows-in-block format.
+
+ Before this, we have already called check_page_layout(), so
+ we know the block is logicaly correct (even if the rows may not be that)
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+
+static my_bool check_head_page(HA_CHECK *param, MARIA_HA *info, uchar *record,
+ int extend, my_off_t page_pos, uchar *page_buff,
+ uint row_count)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *dir_entry;
+ uint row;
+ char llbuff[22], llbuff2[22];
+ ulonglong page= page_pos / share->block_size;
+ DBUG_ENTER("check_head_page");
+
+ dir_entry= page_buff+ share->block_size - PAGE_SUFFIX_SIZE;
+ for (row= 0 ; row < row_count ; row++)
+ {
+ uint pos, length, flag;
+ dir_entry-= DIR_ENTRY_SIZE;
+ pos= uint2korr(dir_entry);
+ if (!pos)
+ continue;
+ length= uint2korr(dir_entry+2);
+ if (length < share->base.min_block_length)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Row %3u is too short "
+ "(%d of min %d bytes)",
+ llstr(page, llbuff), row, length,
+ (uint) share->base.min_block_length);
+ DBUG_RETURN(1);
+ }
+ flag= (uint) (uchar) page_buff[pos];
+ if (flag & ~(ROW_FLAG_ALL))
+ _ma_check_print_error(param,
+ "Page %9s: Row %3u has wrong flag: %u",
+ llstr(page, llbuff), row, flag);
+
+ DBUG_PRINT("info", ("rowid: %s page: %lu row: %u",
+ llstr(ma_recordpos(page, row), llbuff),
+ (ulong) page, row));
+ info->cur_row.trid= 0;
+ if (_ma_read_block_record2(info, record, page_buff+pos,
+ page_buff+pos+length))
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Row %3d is crashed",
+ llstr(page, llbuff), row);
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ DBUG_RETURN(1);
+ continue;
+ }
+ set_if_bigger(param->max_found_trid, info->cur_row.trid);
+ if (info->cur_row.trid > param->max_trid)
+ _ma_check_print_not_visible_error(param, info->cur_row.trid);
+
+ if (share->calc_checksum)
+ {
+ ha_checksum checksum= (*share->calc_checksum)(info, record);
+ if (info->cur_row.checksum != (checksum & 255))
+ _ma_check_print_error(param, "Page %9s: Row %3d has wrong checksum",
+ llstr(page, llbuff), row);
+ param->glob_crc+= checksum;
+ }
+ if (info->cur_row.extents_count)
+ {
+ uchar *extents= info->cur_row.extents;
+ uint i;
+ /* Check that bitmap has the right marker for the found extents */
+ for (i= 0 ; i < info->cur_row.extents_count ; i++)
+ {
+ pgcache_page_no_t extent_page;
+ uint page_count, page_type;
+ extent_page= uint5korr(extents);
+ page_count= uint2korr(extents+5) & ~START_EXTENT_BIT;
+ extents+= ROW_EXTENT_SIZE;
+ page_type= BLOB_PAGE;
+ if (page_count & TAIL_BIT)
+ {
+ page_count= 1;
+ page_type= TAIL_PAGE;
+ }
+ /*
+ TODO OPTIMIZE:
+ Check the whole extent with one test and only do the loop if
+ something is wrong (for exact error reporting)
+ */
+ for ( ; page_count--; extent_page++)
+ {
+ uint bitmap_pattern;
+ if (_ma_check_if_right_bitmap_type(info, page_type, extent_page,
+ &bitmap_pattern))
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Row: %3d has an extent with wrong information in bitmap: Page %9s Page_type: %d Bitmap: %d",
+ llstr(page, llbuff), row,
+ llstr(extent_page, llbuff2),
+ page_type, bitmap_pattern);
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ }
+ param->full_page_count+= info->cur_row.full_page_count;
+ param->tail_count+= info->cur_row.tail_count;
+ if (check_keys_in_record(param, info, extend,
+ ma_recordpos(page, row), record))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Check if rows-in-block data file is consistent
+*/
+
+static int check_block_record(HA_CHECK *param, MARIA_HA *info, int extend,
+ uchar *record)
+{
+ MARIA_SHARE *share= info->s;
+ my_off_t pos;
+ pgcache_page_no_t page;
+ uchar *page_buff, *bitmap_buff, *data;
+ char llbuff[22], llbuff2[22];
+ uint block_size= share->block_size;
+ ha_rows full_page_count, tail_count;
+ my_bool full_dir;
+ uint offset_page, offset, free_count;
+
+ LINT_INIT(full_dir);
+
+ if (_ma_scan_init_block_record(info))
+ {
+ _ma_check_print_error(param, "got error %d when initializing scan",
+ my_errno);
+ return 1;
+ }
+ bitmap_buff= info->scan.bitmap_buff;
+ page_buff= info->scan.page_buff;
+ full_page_count= tail_count= 0;
+ param->full_page_count= param->tail_count= 0;
+ param->used= param->link_used= 0;
+ param->splits= share->state.state.data_file_length / block_size;
+
+ for (pos= 0, page= 0;
+ pos < share->state.state.data_file_length;
+ pos+= block_size, page++)
+ {
+ uint row_count, real_row_count, empty_space, page_type, bitmap_pattern;
+ LINT_INIT(row_count);
+ LINT_INIT(empty_space);
+
+ if (*_ma_killed_ptr(param))
+ {
+ _ma_scan_end_block_record(info);
+ return -1;
+ }
+ if ((page % share->bitmap.pages_covered) == 0)
+ {
+ /* Bitmap page */
+ if (pagecache_read(share->pagecache,
+ &info->s->bitmap.file,
+ page, 1,
+ bitmap_buff,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Got error: %d when reading datafile",
+ llstr(page, llbuff), my_errno);
+ goto err;
+ }
+ param->used+= block_size;
+ param->link_used+= block_size;
+ continue;
+ }
+ /* Skip pages marked as empty in bitmap */
+ offset_page= (uint) ((page % share->bitmap.pages_covered) -1) * 3;
+ offset= offset_page & 7;
+ data= bitmap_buff + offset_page / 8;
+ bitmap_pattern= uint2korr(data);
+ if (!((bitmap_pattern >> offset) & 7))
+ {
+ param->empty+= block_size;
+ param->del_blocks++;
+ continue;
+ }
+
+ if (pagecache_read(share->pagecache,
+ &info->dfile,
+ page, 1,
+ page_buff,
+ share->page_type,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0) == 0)
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Got error: %d when reading datafile",
+ llstr(page, llbuff), my_errno);
+ goto err;
+ }
+ page_type= page_buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK;
+ if (page_type == UNALLOCATED_PAGE || page_type >= MAX_PAGE_TYPE)
+ {
+ _ma_check_print_error(param,
+ "Page: %9s Found wrong page type %d",
+ llstr(page, llbuff), page_type);
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ goto err;
+ continue;
+ }
+ switch ((enum en_page_type) page_type) {
+ case UNALLOCATED_PAGE:
+ case MAX_PAGE_TYPE:
+ default:
+ DBUG_ASSERT(0); /* Impossible */
+ break;
+ case HEAD_PAGE:
+ row_count= ((uchar*) page_buff)[DIR_COUNT_OFFSET];
+ empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET);
+ param->used+= block_size - empty_space;
+ param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE +
+ row_count * DIR_ENTRY_SIZE);
+ if (empty_space < share->bitmap.sizes[3])
+ param->lost+= empty_space;
+ if (check_page_layout(param, info, pos, page_buff, row_count,
+ empty_space, &real_row_count, &free_count))
+ goto err;
+ full_dir= (row_count == MAX_ROWS_PER_PAGE &&
+ page_buff[DIR_FREE_OFFSET] == END_OF_DIR_FREE_LIST);
+ break;
+ case TAIL_PAGE:
+ row_count= ((uchar*) page_buff)[DIR_COUNT_OFFSET];
+ empty_space= uint2korr(page_buff + EMPTY_SPACE_OFFSET);
+ param->used+= block_size - empty_space;
+ param->link_used+= (PAGE_HEADER_SIZE + PAGE_SUFFIX_SIZE +
+ row_count * DIR_ENTRY_SIZE);
+ if (empty_space < share->bitmap.sizes[6])
+ param->lost+= empty_space;
+ if (check_page_layout(param, info, pos, page_buff, row_count,
+ empty_space, &real_row_count, &free_count))
+ goto err;
+ full_dir= (row_count - free_count >= MAX_ROWS_PER_PAGE -
+ share->base.blobs);
+ break;
+ case BLOB_PAGE:
+ full_page_count++;
+ full_dir= 0;
+ empty_space= block_size; /* for error reporting */
+ param->link_used+= (LSN_SIZE + PAGE_TYPE_SIZE);
+ param->used+= block_size;
+ break;
+ }
+ if (_ma_check_bitmap_data(info, page_type, page,
+ full_dir ? 0 : empty_space,
+ &bitmap_pattern))
+ {
+ if (bitmap_pattern == ~(uint) 0)
+ _ma_check_print_error(param,
+ "Page %9s: Wrong bitmap for data on page",
+ llstr(page, llbuff));
+ else
+ _ma_check_print_error(param,
+ "Page %9s: Wrong data in bitmap. Page_type: %d empty_space: %u Bitmap-bits: %d",
+ llstr(page, llbuff), page_type,
+ empty_space, bitmap_pattern);
+ if (param->err_count++ > MAXERR || !(param->testflag & T_VERBOSE))
+ goto err;
+ }
+ if ((enum en_page_type) page_type == BLOB_PAGE)
+ continue;
+ param->empty+= empty_space;
+ if ((enum en_page_type) page_type == TAIL_PAGE)
+ {
+ tail_count+= real_row_count;
+ continue;
+ }
+ if (check_head_page(param, info, record, extend, pos, page_buff,
+ row_count))
+ goto err;
+ }
+
+ /* Verify that rest of bitmap is zero */
+
+ if (page % share->bitmap.pages_covered)
+ {
+ /* Not at end of bitmap */
+ uint bitmap_pattern;
+ offset_page= (uint) ((page % share->bitmap.pages_covered) -1) * 3;
+ offset= offset_page & 7;
+ data= bitmap_buff + offset_page / 8;
+ bitmap_pattern= uint2korr(data);
+ if (((bitmap_pattern >> offset)) ||
+ (data + 2 < bitmap_buff + share->bitmap.total_size &&
+ _ma_check_if_zero(data+2, bitmap_buff + share->bitmap.total_size -
+ data - 2)))
+ {
+ ulonglong bitmap_page;
+ bitmap_page= page / share->bitmap.pages_covered;
+ bitmap_page*= share->bitmap.pages_covered;
+
+ _ma_check_print_error(param,
+ "Bitmap at page %s has pages reserved outside of "
+ "data file length",
+ llstr(bitmap_page, llbuff));
+ DBUG_EXECUTE("bitmap", _ma_print_bitmap(&share->bitmap, bitmap_buff,
+ bitmap_page););
+ }
+ }
+
+ _ma_scan_end_block_record(info);
+
+ if (full_page_count != param->full_page_count)
+ _ma_check_print_error(param, "Full page count read through records was %s but we found %s pages while scanning table",
+ llstr(param->full_page_count, llbuff),
+ llstr(full_page_count, llbuff2));
+ if (tail_count != param->tail_count)
+ _ma_check_print_error(param, "Tail count read through records was %s but we found %s tails while scanning table",
+ llstr(param->tail_count, llbuff),
+ llstr(tail_count, llbuff2));
+
+ return param->error_printed != 0;
+
+err:
+ _ma_scan_end_block_record(info);
+ return 1;
+}
+
+
+/* Check that record-link is ok */
+
+int maria_chk_data_link(HA_CHECK *param, MARIA_HA *info, my_bool extend)
+{
+ MARIA_SHARE *share= info->s;
+ int error;
+ uchar *record;
+ char llbuff[22],llbuff2[22],llbuff3[22];
+ DBUG_ENTER("maria_chk_data_link");
+
+ if (!(param->testflag & T_SILENT))
+ {
+ if (extend)
+ puts("- check records and index references");
+ else
+ puts("- check record links");
+ }
+
+ if (!(record= (uchar*) my_malloc(share->base.default_rec_buff_size, MYF(0))))
+ {
+ _ma_check_print_error(param,"Not enough memory for record");
+ DBUG_RETURN(-1);
+ }
+ param->records= param->del_blocks= 0;
+ param->used= param->link_used= param->splits= param->del_length= 0;
+ param->lost= 0;
+ param->tmp_record_checksum= param->glob_crc= 0;
+ param->err_count= 0;
+
+ error= 0;
+ param->empty= share->pack.header_length;
+
+ bzero((char*) param->tmp_key_crc,
+ share->base.keys * sizeof(param->tmp_key_crc[0]));
+
+ switch (share->data_file_type) {
+ case BLOCK_RECORD:
+ error= check_block_record(param, info, extend, record);
+ break;
+ case STATIC_RECORD:
+ error= check_static_record(param, info, extend, record);
+ break;
+ case DYNAMIC_RECORD:
+ error= check_dynamic_record(param, info, extend, record);
+ break;
+ case COMPRESSED_RECORD:
+ error= check_compressed_record(param, info, extend, record);
+ break;
+ } /* switch */
+
+ if (error)
+ goto err;
+
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ if (param->records != share->state.state.records)
+ {
+ _ma_check_print_error(param,
+ "Record-count is not ok; found %-10s Should be: %s",
+ llstr(param->records,llbuff),
+ llstr(share->state.state.records,llbuff2));
+ error=1;
+ }
+ else if (param->record_checksum &&
+ param->record_checksum != param->tmp_record_checksum)
+ {
+ _ma_check_print_error(param,
+ "Key pointers and record positions doesn't match");
+ error=1;
+ }
+ else if (param->glob_crc != share->state.state.checksum &&
+ (share->options &
+ (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
+ {
+ _ma_check_print_warning(param,
+ "Record checksum is not the same as checksum stored in the index file");
+ error=1;
+ }
+ else if (!extend)
+ {
+ uint key;
+ for (key=0 ; key < share->base.keys; key++)
+ {
+ if (param->tmp_key_crc[key] != param->key_crc[key] &&
+ !(share->keyinfo[key].flag &
+ (HA_FULLTEXT | HA_SPATIAL | HA_RTREE_INDEX)))
+ {
+ _ma_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records",
+ key+1);
+ error=1;
+ }
+ }
+ }
+
+ if (param->del_length != share->state.state.empty)
+ {
+ _ma_check_print_warning(param,
+ "Found %s deleted space. Should be %s",
+ llstr(param->del_length,llbuff2),
+ llstr(share->state.state.empty,llbuff));
+ }
+ /* Skip following checks for BLOCK RECORD as they don't make any sence */
+ if (share->data_file_type != BLOCK_RECORD)
+ {
+ if (param->used + param->empty + param->del_length !=
+ share->state.state.data_file_length)
+ {
+ _ma_check_print_warning(param,
+ "Found %s record data and %s unused data and %s deleted data",
+ llstr(param->used, llbuff),
+ llstr(param->empty,llbuff2),
+ llstr(param->del_length,llbuff3));
+ _ma_check_print_warning(param,
+ "Total %s Should be: %s",
+ llstr((param->used+param->empty +
+ param->del_length), llbuff),
+ llstr(share->state.state.data_file_length,llbuff2));
+ }
+ if (param->del_blocks != share->state.state.del)
+ {
+ _ma_check_print_warning(param,
+ "Found %10s deleted blocks. Should be: %s",
+ llstr(param->del_blocks,llbuff),
+ llstr(share->state.state.del,llbuff2));
+ }
+ if (param->splits != share->state.split)
+ {
+ _ma_check_print_warning(param,
+ "Found %10s key parts. Should be: %s",
+ llstr(param->splits, llbuff),
+ llstr(share->state.split,llbuff2));
+ }
+ }
+ if (param->testflag & T_INFO)
+ {
+ if (param->warning_printed || param->error_printed)
+ puts("");
+ if (param->used != 0 && ! param->error_printed)
+ {
+ if (param->records)
+ {
+ printf("Records:%18s M.recordlength:%9lu Packed:%14.0f%%\n",
+ llstr(param->records,llbuff),
+ (long)((param->used - param->link_used)/param->records),
+ (share->base.blobs ? 0.0 :
+ (ulonglong2double((ulonglong) share->base.reclength *
+ param->records)-
+ my_off_t2double(param->used))/
+ ulonglong2double((ulonglong) share->base.reclength *
+ param->records)*100.0));
+ printf("Recordspace used:%9.0f%% Empty space:%12d%% Blocks/Record: %6.2f\n",
+ (ulonglong2double(param->used - param->link_used)/
+ ulonglong2double(param->used-param->link_used+param->empty)*100.0),
+ (!param->records ? 100 :
+ (int) (ulonglong2double(param->del_length+param->empty)/
+ my_off_t2double(param->used)*100.0)),
+ ulonglong2double(param->splits - param->del_blocks) /
+ param->records);
+ }
+ else
+ printf("Records:%18s\n", "0");
+ }
+ printf("Record blocks:%12s Delete blocks:%10s\n",
+ llstr(param->splits - param->del_blocks, llbuff),
+ llstr(param->del_blocks, llbuff2));
+ printf("Record data: %12s Deleted data: %10s\n",
+ llstr(param->used - param->link_used,llbuff),
+ llstr(param->del_length, llbuff2));
+ printf("Empty space: %12s Linkdata: %10s\n",
+ llstr(param->empty, llbuff),llstr(param->link_used, llbuff2));
+ if (param->lost)
+ printf("Lost space: %12s", llstr(param->lost, llbuff));
+ if (param->max_found_trid)
+ {
+ printf("Max trans. id: %11s\n",
+ llstr(param->max_found_trid, llbuff));
+ }
+ }
+ my_free((uchar*) record,MYF(0));
+ DBUG_RETURN (error);
+
+err:
+ my_free((uchar*) record,MYF(0));
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ DBUG_RETURN(1);
+} /* maria_chk_data_link */
+
+
+/**
+ Prepares a table for a repair or index sort: flushes pages, records durably
+ in the table that it is undergoing the operation (if that op crashes, that
+ info will serve for Recovery and the user).
+
+ If we start overwriting the index file, and crash then, old REDOs will
+ be tried and fail. To prevent that, we bump skip_redo_lsn, and thus we have
+ to flush and sync pages so that old REDOs can be skipped.
+ If this is not a bulk insert, which Recovery can handle gracefully (by
+ truncating files, see UNDO_BULK_INSERT) we also mark the table
+ crashed-on-repair, so that user knows it has to re-repair. If bulk insert we
+ shouldn't mark it crashed-on-repair, because if we did this, the UNDO phase
+ would skip the table (UNDO_BULK_INSERT would not be applied),
+ and maria_chk would not improve that.
+ If this is an OPTIMIZE which merely sorts index, we need to do the same
+ too: old REDOs should not apply to the new index file.
+ Only the flush is needed when in maria_chk which is not crash-safe.
+
+ @param info table
+ @param param repair parameters
+ @param discard_index if index pages can be thrown away
+*/
+
+static my_bool protect_against_repair_crash(MARIA_HA *info,
+ const HA_CHECK *param,
+ my_bool discard_index)
+{
+ MARIA_SHARE *share= info->s;
+
+ /*
+ There are other than recovery-related reasons to do the writes below:
+ - the physical size of the data file is sometimes used during repair: we
+ need to flush to have it exact
+ - we flush the state because maria_open(HA_OPEN_COPY) will want to read
+ it from disk.
+ */
+ if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_FORCE_WRITE,
+ discard_index ? FLUSH_IGNORE_CHANGED :
+ FLUSH_FORCE_WRITE) ||
+ (share->changed &&
+ _ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO |
+ MA_STATE_INFO_WRITE_LOCK)))
+ return TRUE;
+ /* In maria_chk this is not needed: */
+ if (maria_multi_threaded && share->base.born_transactional)
+ {
+ if ((param->testflag & T_NO_CREATE_RENAME_LSN) == 0)
+ {
+ /* this can be true only for a transactional table */
+ maria_mark_crashed_on_repair(info);
+ if (_ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_LOCK))
+ return TRUE;
+ }
+ if (translog_status == TRANSLOG_OK &&
+ _ma_update_state_lsns(share, translog_get_horizon(),
+ share->state.create_trid, FALSE, FALSE))
+ return TRUE;
+ if (_ma_sync_table_files(info))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ @brief Initialize variables for repair
+*/
+
+static int initialize_variables_for_repair(HA_CHECK *param,
+ MARIA_SORT_INFO *sort_info,
+ MARIA_SORT_PARAM *sort_param,
+ MARIA_HA *info,
+ my_bool rep_quick)
+{
+ MARIA_SHARE *share= info->s;
+
+ /* Repair code relies on share->state.state so we have to update it here */
+ if (share->lock.update_status)
+ (*share->lock.update_status)(info);
+
+ bzero((char*) sort_info, sizeof(*sort_info));
+ bzero((char*) sort_param, sizeof(*sort_param));
+
+ param->testflag|= T_REP; /* for easy checking */
+ if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
+ param->testflag|= T_CALC_CHECKSUM;
+ param->glob_crc= 0;
+ if (rep_quick)
+ param->testflag|= T_QUICK;
+ else
+ param->testflag&= ~T_QUICK;
+ param->org_key_map= share->state.key_map;
+
+ sort_param->sort_info= sort_info;
+ sort_param->fix_datafile= ! rep_quick;
+ sort_param->calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
+ sort_info->info= sort_info->new_info= info;
+ sort_info->param= param;
+ set_data_file_type(sort_info, info->s);
+ sort_info->org_data_file_type= share->data_file_type;
+
+ bzero(&info->rec_cache, sizeof(info->rec_cache));
+ info->rec_cache.file= info->dfile.file;
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (protect_against_repair_crash(info, param, !test(param->testflag &
+ T_CREATE_MISSING_KEYS)))
+ return 1;
+
+ /* calculate max_records */
+ sort_info->filelength= my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0));
+ if ((param->testflag & T_CREATE_MISSING_KEYS) ||
+ sort_info->org_data_file_type == COMPRESSED_RECORD)
+ sort_info->max_records= share->state.state.records;
+ else
+ {
+ ulong rec_length;
+ rec_length= max(share->base.min_pack_length,
+ share->base.min_block_length);
+ sort_info->max_records= (ha_rows) (sort_info->filelength / rec_length);
+ }
+
+ /* Set up transaction handler so that we can see all rows */
+ if (!ma_control_file_inited())
+ param->max_trid= 0; /* Give warning for first trid found */
+ else
+ param->max_trid= max_trid_in_system();
+
+ maria_ignore_trids(info);
+ /* Don't write transid's during repair */
+ maria_versioning(info, 0);
+ return 0;
+}
+
+
+/**
+ @brief Drop all indexes
+
+ @param[in] param check parameters
+ @param[in] info MARIA_HA handle
+ @param[in] force if to force drop all indexes
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error
+
+ @note
+ Once allocated, index blocks remain part of the key file forever.
+ When indexes are disabled, no block is freed. When enabling indexes,
+ no block is freed either. The new indexes are create from new
+ blocks. (Bug #4692)
+
+ Before recreating formerly disabled indexes, the unused blocks
+ must be freed. There are two options to do this:
+ - Follow the tree of disabled indexes, add all blocks to the
+ deleted blocks chain. Would require a lot of random I/O.
+ - Drop all blocks by clearing all index root pointers and all
+ delete chain pointers and resetting key_file_length to the end
+ of the index file header. This requires to recreate all indexes,
+ even those that may still be intact.
+ The second method is probably faster in most cases.
+
+ When disabling indexes, MySQL disables either all indexes or all
+ non-unique indexes. When MySQL [re-]enables disabled indexes
+ (T_CREATE_MISSING_KEYS), then we either have "lost" blocks in the
+ index file, or there are no non-unique indexes. In the latter case,
+ maria_repair*() would not be called as there would be no disabled
+ indexes.
+
+ If there would be more unique indexes than disabled (non-unique)
+ indexes, we could do the first method. But this is not implemented
+ yet. By now we drop and recreate all indexes when repair is called.
+
+ However, there is an exception. Sometimes MySQL disables non-unique
+ indexes when the table is empty (e.g. when copying a table in
+ mysql_alter_table()). When enabling the non-unique indexes, they
+ are still empty. So there is no index block that can be lost. This
+ optimization is implemented in this function.
+
+ Note that in normal repair (T_CREATE_MISSING_KEYS not set) we
+ recreate all enabled indexes unconditonally. We do not change the
+ key_map. Otherwise we invert the key map temporarily (outside of
+ this function) and recreate the then "seemingly" enabled indexes.
+ When we cannot use the optimization, and drop all indexes, we
+ pretend that all indexes were disabled. By the inversion, we will
+ then recrate all indexes.
+*/
+
+static int maria_drop_all_indexes(HA_CHECK *param, MARIA_HA *info,
+ my_bool force)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_STATE_INFO *state= &share->state;
+ uint i;
+ DBUG_ENTER("maria_drop_all_indexes");
+
+ /*
+ If any of the disabled indexes has a key block assigned, we must
+ drop and recreate all indexes to avoid losing index blocks.
+
+ If we want to recreate disabled indexes only _and_ all of these
+ indexes are empty, we don't need to recreate the existing indexes.
+ */
+ if (!force && (param->testflag & T_CREATE_MISSING_KEYS))
+ {
+ DBUG_PRINT("repair", ("creating missing indexes"));
+ for (i= 0; i < share->base.keys; i++)
+ {
+ DBUG_PRINT("repair", ("index #: %u key_root: 0x%lx active: %d",
+ i, (long) state->key_root[i],
+ maria_is_key_active(state->key_map, i)));
+ if ((state->key_root[i] != HA_OFFSET_ERROR) &&
+ !maria_is_key_active(state->key_map, i))
+ {
+ /*
+ This index has at least one key block and it is disabled.
+ We would lose its block(s) if would just recreate it.
+ So we need to drop and recreate all indexes.
+ */
+ DBUG_PRINT("repair", ("nonempty and disabled: recreate all"));
+ break;
+ }
+ }
+ if (i >= share->base.keys)
+ goto end;
+
+ /*
+ We do now drop all indexes and declare them disabled. With the
+ T_CREATE_MISSING_KEYS flag, maria_repair*() will recreate all
+ disabled indexes and enable them.
+ */
+ maria_clear_all_keys_active(state->key_map);
+ DBUG_PRINT("repair", ("declared all indexes disabled"));
+ }
+
+ /* Clear index root block pointers. */
+ for (i= 0; i < share->base.keys; i++)
+ state->key_root[i]= HA_OFFSET_ERROR;
+
+ /* Drop the delete chain. */
+ share->state.key_del= HA_OFFSET_ERROR;
+
+ /* Reset index file length to end of index file header. */
+ share->state.state.key_file_length= share->base.keystart;
+
+end:
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Recover old table by reading each record and writing all keys
+
+ NOTES
+ Save new datafile-name in temp_filename.
+ We overwrite the index file as we go (writekeys() for example), so if we
+ crash during this the table is unusable and user (or Recovery in the
+ future) must repeat the REPAIR/OPTIMIZE operation. We could use a
+ temporary index file in the future (drawback: more disk space).
+
+ IMPLEMENTATION (for hard repair with block format)
+ - Create new, unrelated MARIA_HA of the table
+ - Create new datafile and associate it with new handler
+ - Reset all statistic information in new handler
+ - Copy all data to new handler with normal write operations
+ - Move state of new handler to old handler
+ - Close new handler
+ - Close data file in old handler
+ - Rename old data file to new data file.
+ - Reopen data file in old handler
+*/
+
+int maria_repair(HA_CHECK *param, register MARIA_HA *info,
+ char *name, my_bool rep_quick)
+{
+ int error, got_error;
+ ha_rows start_records,new_header_length;
+ my_off_t del;
+ File new_file;
+ MARIA_SHARE *share= info->s;
+ char llbuff[22],llbuff2[22];
+ MARIA_SORT_INFO sort_info;
+ MARIA_SORT_PARAM sort_param;
+ my_bool block_record, scan_inited= 0,
+ reenable_logging= share->now_transactional;
+ enum data_file_type org_data_file_type= share->data_file_type;
+ myf sync_dir= ((share->now_transactional && !share->temporary) ?
+ MY_SYNC_DIR : 0);
+ DBUG_ENTER("maria_repair");
+
+ got_error= 1;
+ new_file= -1;
+ start_records= share->state.state.records;
+ if (!(param->testflag & T_SILENT))
+ {
+ printf("- recovering (with keycache) MARIA-table '%s'\n",name);
+ printf("Data records: %s\n", llstr(start_records, llbuff));
+ }
+
+ if (initialize_variables_for_repair(param, &sort_info, &sort_param, info,
+ rep_quick))
+ goto err;
+
+ if (reenable_logging)
+ _ma_tmp_disable_logging_for_table(info, 0);
+
+ sort_param.current_filepos= sort_param.filepos= new_header_length=
+ ((param->testflag & T_UNPACK) ? 0L : share->pack.header_length);
+
+ if (!rep_quick)
+ {
+ /* Get real path for data file */
+ if ((new_file= my_create(fn_format(param->temp_filename,
+ share->data_file_name.str, "",
+ DATA_TMP_EXT, 2+4),
+ 0,param->tmpfile_createflag,
+ MYF(0))) < 0)
+ {
+ _ma_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ goto err;
+ }
+ if (new_header_length &&
+ maria_filecopy(param, new_file, info->dfile.file, 0L,
+ new_header_length, "datafile-header"))
+ goto err;
+ share->state.dellink= HA_OFFSET_ERROR;
+ info->rec_cache.file= new_file; /* For sort_delete_record */
+ if (share->data_file_type == BLOCK_RECORD ||
+ (param->testflag & T_UNPACK))
+ {
+ if (create_new_data_handle(&sort_param, new_file))
+ goto err;
+ sort_info.new_info->rec_cache.file= new_file;
+ }
+ }
+
+ block_record= sort_info.new_info->s->data_file_type == BLOCK_RECORD;
+
+ if (org_data_file_type != BLOCK_RECORD)
+ {
+ /* We need a read buffer to read rows in big blocks */
+ if (init_io_cache(&param->read_cache, info->dfile.file,
+ (uint) param->read_buffer_length,
+ READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)))
+ goto err;
+ }
+ if (sort_info.new_info->s->data_file_type != BLOCK_RECORD)
+ {
+ /* When writing to not block records, we need a write buffer */
+ if (!rep_quick)
+ {
+ if (init_io_cache(&sort_info.new_info->rec_cache, new_file,
+ (uint) param->write_buffer_length,
+ WRITE_CACHE, new_header_length, 1,
+ MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw))
+ goto err;
+ sort_info.new_info->opt_flag|=WRITE_CACHE_USED;
+ }
+ }
+ else if (block_record)
+ {
+ scan_inited= 1;
+ if (maria_scan_init(sort_info.info))
+ goto err;
+ }
+
+ if (!(sort_param.record=
+ (uchar *) my_malloc((uint)
+ share->base.default_rec_buff_size, MYF(0))) ||
+ _ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
+ share->base.default_rec_buff_size))
+ {
+ _ma_check_print_error(param, "Not enough memory for extra record");
+ goto err;
+ }
+
+ sort_param.read_cache=param->read_cache;
+ sort_param.pos=sort_param.max_pos=share->pack.header_length;
+ param->read_cache.end_of_file= sort_info.filelength;
+ sort_param.master=1;
+ sort_info.max_records= ~(ha_rows) 0;
+
+ del= share->state.state.del;
+ share->state.state.records= share->state.state.del= share->state.split= 0;
+ share->state.state.empty= 0;
+
+ if (param->testflag & T_CREATE_MISSING_KEYS)
+ maria_set_all_keys_active(share->state.key_map, share->base.keys);
+ maria_drop_all_indexes(param, info, TRUE);
+
+ maria_lock_memory(param); /* Everything is alloced */
+
+ /* Re-create all keys, which are set in key_map. */
+ while (!(error=sort_get_next_record(&sort_param)))
+ {
+ if (block_record && _ma_sort_write_record(&sort_param))
+ goto err;
+
+ if (writekeys(&sort_param))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY)
+ goto err;
+ DBUG_DUMP("record", (uchar*) sort_param.record,
+ share->base.default_rec_buff_size);
+ _ma_check_print_warning(param,
+ "Duplicate key %2d for record at %10s against new record at %10s",
+ info->errkey+1,
+ llstr(sort_param.current_filepos, llbuff),
+ llstr(info->dup_key_pos,llbuff2));
+ if (param->testflag & T_VERBOSE)
+ {
+ MARIA_KEY tmp_key;
+ MARIA_KEYDEF *keyinfo= share->keyinfo + info->errkey;
+ (*keyinfo->make_key)(info, &tmp_key, (uint) info->errkey,
+ info->lastkey_buff,
+ sort_param.record, 0L, 0);
+ _ma_print_key(stdout, &tmp_key);
+ }
+ sort_info.dupp++;
+ if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
+ {
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ param->error_printed=1;
+ goto err;
+ }
+ /* purecov: begin tested */
+ if (block_record)
+ {
+ sort_info.new_info->s->state.state.records--;
+ if ((*sort_info.new_info->s->write_record_abort)(sort_info.new_info))
+ {
+ _ma_check_print_error(param,"Couldn't delete duplicate row");
+ goto err;
+ }
+ }
+ /* purecov: end */
+ continue;
+ }
+ if (!block_record)
+ {
+ if (_ma_sort_write_record(&sort_param))
+ goto err;
+ /* Filepos is pointer to where next row will be stored */
+ sort_param.current_filepos= sort_param.filepos;
+ }
+ }
+ if (error > 0 || maria_write_data_suffix(&sort_info, !rep_quick) ||
+ flush_io_cache(&sort_info.new_info->rec_cache) ||
+ param->read_cache.error < 0)
+ goto err;
+
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
+ {
+ _ma_check_print_warning(param,
+ "Can't change size of indexfile, error: %d",
+ my_errno);
+ goto err;
+ }
+
+ if (rep_quick && del+sort_info.dupp != share->state.state.del)
+ {
+ _ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
+ _ma_check_print_error(param,"Run recovery again without -q");
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ goto err;
+ }
+
+ if (param->testflag & T_SAFE_REPAIR)
+ {
+ /* Don't repair if we loosed more than one row */
+ if (sort_info.new_info->s->state.state.records+1 < start_records)
+ {
+ share->state.state.records= start_records;
+ goto err;
+ }
+ }
+
+ VOID(end_io_cache(&sort_info.new_info->rec_cache));
+ info->opt_flag&= ~WRITE_CACHE_USED;
+
+ /*
+ As we have read the data file (sort_get_next_record()) we may have
+ cached, non-changed blocks of it in the page cache. We must throw them
+ away as we are going to close their descriptor ('new_file'). We also want
+ to flush any index block, so that it is ready for the upcoming sync.
+ */
+ if (_ma_flush_table_files_before_swap(param, info))
+ goto err;
+
+ if (!rep_quick)
+ {
+ sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
+ if (sort_info.new_info != sort_info.info)
+ {
+ MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
+ if (maria_close(sort_info.new_info))
+ {
+ _ma_check_print_error(param, "Got error %d on close", my_errno);
+ goto err;
+ }
+ copy_data_file_state(&share->state, &save_state);
+ new_file= -1;
+ sort_info.new_info= info;
+ }
+ share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
+
+ /* Replace the actual file with the temporary file */
+ if (new_file >= 0)
+ my_close(new_file, MYF(MY_WME));
+ new_file= -1;
+ change_data_file_descriptor(info, -1);
+ if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
+ DATA_TMP_EXT,
+ (param->testflag & T_BACKUP_DATA ?
+ MYF(MY_REDEL_MAKE_BACKUP): MYF(0)) |
+ sync_dir) ||
+ _ma_open_datafile(info, share, NullS, -1))
+ {
+ goto err;
+ }
+ }
+ else
+ {
+ share->state.state.data_file_length= sort_param.max_pos;
+ }
+ if (param->testflag & T_CALC_CHECKSUM)
+ share->state.state.checksum= param->glob_crc;
+
+ if (!(param->testflag & T_SILENT))
+ {
+ if (start_records != share->state.state.records)
+ printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
+ }
+ if (sort_info.dupp)
+ _ma_check_print_warning(param,
+ "%s records have been removed",
+ llstr(sort_info.dupp,llbuff));
+
+ got_error= 0;
+ /* If invoked by external program that uses thr_lock */
+ if (&share->state.state != info->state)
+ *info->state= *info->state_start= share->state.state;
+
+err:
+ if (scan_inited)
+ maria_scan_end(sort_info.info);
+ _ma_reset_state(info);
+
+ VOID(end_io_cache(&param->read_cache));
+ VOID(end_io_cache(&sort_info.new_info->rec_cache));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ /* this below could fail, shouldn't we detect error? */
+ if (got_error)
+ {
+ if (! param->error_printed)
+ _ma_check_print_error(param,"%d for record at pos %s",my_errno,
+ llstr(sort_param.start_recpos,llbuff));
+ (void)_ma_flush_table_files_before_swap(param, info);
+ if (sort_info.new_info && sort_info.new_info != sort_info.info)
+ {
+ unuse_data_file_descriptor(sort_info.new_info);
+ maria_close(sort_info.new_info);
+ }
+ if (new_file >= 0)
+ {
+ VOID(my_close(new_file,MYF(0)));
+ VOID(my_delete(param->temp_filename, MYF(MY_WME)));
+ }
+ maria_mark_crashed_on_repair(info);
+ }
+ /* If caller had disabled logging it's not up to us to re-enable it */
+ if (reenable_logging)
+ _ma_reenable_logging_for_table(info, FALSE);
+
+ my_free(sort_param.rec_buff, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
+ if (!got_error && (param->testflag & T_UNPACK))
+ restore_data_file_type(share);
+ share->state.changed|= (STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES |
+ STATE_NOT_ANALYZED | STATE_NOT_ZEROFILLED);
+ if (!rep_quick)
+ share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_MOVABLE);
+ DBUG_RETURN(got_error);
+}
+
+
+/* Uppdate keyfile when doing repair */
+
+static int writekeys(MARIA_SORT_PARAM *sort_param)
+{
+ uint i;
+ MARIA_HA *info= sort_param->sort_info->info;
+ MARIA_SHARE *share= info->s;
+ uchar *record= sort_param->record;
+ uchar *key_buff;
+ my_off_t filepos= sort_param->current_filepos;
+ MARIA_KEY key;
+ DBUG_ENTER("writekeys");
+
+ key_buff= info->lastkey_buff+share->base.max_key_length;
+
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ if (maria_is_key_active(share->state.key_map, i))
+ {
+ if (share->keyinfo[i].flag & HA_FULLTEXT )
+ {
+ if (_ma_ft_add(info, i, key_buff, record, filepos))
+ goto err;
+ }
+ else
+ {
+ if (!(*share->keyinfo[i].make_key)(info, &key, i, key_buff, record,
+ filepos, 0))
+ goto err;
+ if ((*share->keyinfo[i].ck_insert)(info, &key))
+ goto err;
+ }
+ }
+ }
+ DBUG_RETURN(0);
+
+ err:
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY)
+ {
+ info->errkey=(int) i; /* This key was found */
+ while ( i-- > 0 )
+ {
+ if (maria_is_key_active(share->state.key_map, i))
+ {
+ if (share->keyinfo[i].flag & HA_FULLTEXT)
+ {
+ if (_ma_ft_del(info,i,key_buff,record,filepos))
+ break;
+ }
+ else
+ {
+ (*share->keyinfo[i].make_key)(info, &key, i, key_buff, record,
+ filepos, 0);
+ if (_ma_ck_delete(info, &key))
+ break;
+ }
+ }
+ }
+ }
+ /* Remove checksum that was added to glob_crc in sort_get_next_record */
+ if (sort_param->calc_checksum)
+ sort_param->sort_info->param->glob_crc-= info->cur_row.checksum;
+ DBUG_PRINT("error",("errno: %d",my_errno));
+ DBUG_RETURN(-1);
+} /* writekeys */
+
+
+ /* Change all key-pointers that points to a records */
+
+int maria_movepoint(register MARIA_HA *info, uchar *record,
+ MARIA_RECORD_POS oldpos, MARIA_RECORD_POS newpos,
+ uint prot_key)
+{
+ uint i;
+ uchar *key_buff;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_movepoint");
+
+ key_buff= info->lastkey_buff + share->base.max_key_length;
+ for (i=0 ; i < share->base.keys; i++)
+ {
+ if (i != prot_key && maria_is_key_active(share->state.key_map, i))
+ {
+ MARIA_KEY key;
+ (*share->keyinfo[i].make_key)(info, &key, i, key_buff, record, oldpos,
+ 0);
+ if (key.keyinfo->flag & HA_NOSAME)
+ { /* Change pointer direct */
+ uint nod_flag;
+ MARIA_KEYDEF *keyinfo;
+ keyinfo=share->keyinfo+i;
+ if (_ma_search(info, &key, (uint32) (SEARCH_SAME | SEARCH_SAVE_BUFF),
+ share->state.key_root[i]))
+ DBUG_RETURN(-1);
+ nod_flag= _ma_test_if_nod(share, info->buff);
+ _ma_dpointer(share, info->int_keypos - nod_flag -
+ share->rec_reflength,newpos);
+ if (_ma_write_keypage(info, keyinfo, info->last_keypage,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS,
+ info->buff))
+ DBUG_RETURN(-1);
+ }
+ else
+ { /* Change old key to new */
+ if (_ma_ck_delete(info, &key))
+ DBUG_RETURN(-1);
+ (*share->keyinfo[i].make_key)(info, &key, i, key_buff, record, newpos,
+ 0);
+ if (_ma_ck_write(info, &key))
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+} /* maria_movepoint */
+
+
+ /* Tell system that we want all memory for our cache */
+
+void maria_lock_memory(HA_CHECK *param __attribute__((unused)))
+{
+#ifdef SUN_OS /* Key-cacheing thrases on sun 4.1 */
+ if (param->opt_maria_lock_memory)
+ {
+ int success = mlockall(MCL_CURRENT); /* or plock(DATLOCK); */
+ if (geteuid() == 0 && success != 0)
+ _ma_check_print_warning(param,
+ "Failed to lock memory. errno %d",my_errno);
+ }
+#endif
+} /* maria_lock_memory */
+
+
+/**
+ Flush all changed blocks to disk.
+
+ We release blocks as it's unlikely that they would all be needed soon.
+ This function needs to be called before swapping data or index files or
+ syncing them.
+
+ @param param description of the repair operation
+ @param info table
+*/
+
+static my_bool _ma_flush_table_files_before_swap(HA_CHECK *param,
+ MARIA_HA *info)
+{
+ DBUG_ENTER("_ma_flush_table_files_before_swap");
+ if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_RELEASE, FLUSH_RELEASE))
+ {
+ _ma_check_print_error(param, "%d when trying to write buffers", my_errno);
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+ /* Sort index for more efficent reads */
+
+int maria_sort_index(HA_CHECK *param, register MARIA_HA *info, char *name)
+{
+ reg2 uint key;
+ reg1 MARIA_KEYDEF *keyinfo;
+ File new_file;
+ my_off_t index_pos[HA_MAX_POSSIBLE_KEY];
+ uint r_locks,w_locks;
+ int old_lock;
+ MARIA_SHARE *share= info->s;
+ MARIA_STATE_INFO old_state;
+ myf sync_dir= ((share->now_transactional && !share->temporary) ?
+ MY_SYNC_DIR : 0);
+ DBUG_ENTER("maria_sort_index");
+
+ /* cannot sort index files with R-tree indexes */
+ for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
+ key++,keyinfo++)
+ if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
+ DBUG_RETURN(0);
+
+ if (!(param->testflag & T_SILENT))
+ printf("- Sorting index for MARIA-table '%s'\n",name);
+
+ if (protect_against_repair_crash(info, param, FALSE))
+ DBUG_RETURN(1);
+
+ /* Get real path for index file */
+ fn_format(param->temp_filename,name,"", MARIA_NAME_IEXT,2+4+32);
+ if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename,
+ "", INDEX_TMP_EXT,2+4),
+ 0,param->tmpfile_createflag,MYF(0))) <= 0)
+ {
+ _ma_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ DBUG_RETURN(-1);
+ }
+ if (maria_filecopy(param, new_file, share->kfile.file, 0L,
+ (ulong) share->base.keystart, "headerblock"))
+ goto err;
+
+ param->new_file_pos=share->base.keystart;
+ for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
+ key++,keyinfo++)
+ {
+ if (! maria_is_key_active(share->state.key_map, key))
+ continue;
+
+ if (share->state.key_root[key] != HA_OFFSET_ERROR)
+ {
+ index_pos[key]=param->new_file_pos; /* Write first block here */
+ if (sort_one_index(param,info,keyinfo,share->state.key_root[key],
+ new_file))
+ goto err;
+ }
+ else
+ index_pos[key]= HA_OFFSET_ERROR; /* No blocks */
+ }
+
+ /* Flush key cache for this file if we are calling this outside maria_chk */
+ flush_pagecache_blocks(share->pagecache, &share->kfile,
+ FLUSH_IGNORE_CHANGED);
+
+ share->state.version=(ulong) time((time_t*) 0);
+ old_state= share->state; /* save state if not stored */
+ r_locks= share->r_locks;
+ w_locks= share->w_locks;
+ old_lock= info->lock_type;
+
+ /* Put same locks as old file */
+ share->r_locks= share->w_locks= share->tot_locks= 0;
+ (void) _ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
+ pthread_mutex_lock(&share->intern_lock);
+ VOID(my_close(share->kfile.file, MYF(MY_WME)));
+ share->kfile.file = -1;
+ pthread_mutex_unlock(&share->intern_lock);
+ VOID(my_close(new_file,MYF(MY_WME)));
+ if (maria_change_to_newfile(share->index_file_name.str, MARIA_NAME_IEXT,
+ INDEX_TMP_EXT, sync_dir) ||
+ _ma_open_keyfile(share))
+ goto err2;
+ info->lock_type= F_UNLCK; /* Force maria_readinfo to lock */
+ _ma_readinfo(info,F_WRLCK,0); /* Will lock the table */
+ info->lock_type= old_lock;
+ share->r_locks= r_locks;
+ share->w_locks= w_locks;
+ share->tot_locks= r_locks+w_locks;
+ share->state= old_state; /* Restore old state */
+
+ share->state.state.key_file_length=param->new_file_pos;
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ for (key=0 ; key < share->base.keys ; key++)
+ share->state.key_root[key]=index_pos[key];
+ share->state.key_del= HA_OFFSET_ERROR;
+
+ share->state.changed&= ~STATE_NOT_SORTED_PAGES;
+ DBUG_EXECUTE_IF("maria_flush_whole_log",
+ {
+ DBUG_PRINT("maria_flush_whole_log", ("now"));
+ translog_flush(translog_get_horizon());
+ });
+ DBUG_EXECUTE_IF("maria_crash_sort_index",
+ {
+ DBUG_PRINT("maria_crash_sort_index", ("now"));
+ DBUG_ABORT();
+ });
+ DBUG_RETURN(0);
+
+err:
+ VOID(my_close(new_file,MYF(MY_WME)));
+err2:
+ VOID(my_delete(param->temp_filename,MYF(MY_WME)));
+ DBUG_RETURN(-1);
+} /* maria_sort_index */
+
+
+/**
+ @brief put CRC on the page
+
+ @param buff reference on the page buffer.
+ @param pos position of the page in the file.
+ @param length length of the page
+*/
+
+static void put_crc(uchar *buff, my_off_t pos, MARIA_SHARE *share)
+{
+ maria_page_crc_set_index(buff, (pgcache_page_no_t) (pos / share->block_size),
+ (uchar*) share);
+}
+
+
+/* Sort index blocks recursive using one index */
+
+static int sort_one_index(HA_CHECK *param, MARIA_HA *info,
+ MARIA_KEYDEF *keyinfo,
+ my_off_t pagepos, File new_file)
+{
+ uint length,nod_flag,used_length;
+ uchar *buff,*keypos,*endpos;
+ my_off_t new_page_pos,next_page;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEY key;
+ DBUG_ENTER("sort_one_index");
+
+ /* cannot walk over R-tree indices */
+ DBUG_ASSERT(keyinfo->key_alg != HA_KEY_ALG_RTREE);
+ new_page_pos=param->new_file_pos;
+ param->new_file_pos+=keyinfo->block_length;
+ key.keyinfo= keyinfo;
+ key.data= info->lastkey_buff;
+
+ if (!(buff= (uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ _ma_check_print_error(param,"Not enough memory for key block");
+ DBUG_RETURN(-1);
+ }
+ if (!_ma_fetch_keypage(info, keyinfo, pagepos,PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, buff, 0, 0))
+ {
+ report_keypage_fault(param, info, pagepos);
+ goto err;
+ }
+ if ((nod_flag=_ma_test_if_nod(share, buff)) || keyinfo->flag & HA_FULLTEXT)
+ {
+ uint page_flag= _ma_get_keypage_flag(share, buff);
+ used_length= _ma_get_page_used(share, buff);
+ keypos=buff + share->keypage_header + nod_flag;
+ endpos=buff + used_length;
+
+ for ( ;; )
+ {
+ if (nod_flag)
+ {
+ next_page= _ma_kpos(nod_flag,keypos);
+ /* Save new pos */
+ _ma_kpointer(info,keypos-nod_flag,param->new_file_pos);
+ if (sort_one_index(param,info,keyinfo,next_page,new_file))
+ {
+ DBUG_PRINT("error",
+ ("From page: %ld, keyoffset: %lu used_length: %d",
+ (ulong) pagepos, (ulong) (keypos - buff),
+ (int) used_length));
+ DBUG_DUMP("buff",(uchar*) buff,used_length);
+ goto err;
+ }
+ }
+ if (keypos >= endpos ||
+ !(*keyinfo->get_key)(&key, page_flag, nod_flag, &keypos))
+ break;
+ DBUG_ASSERT(keypos <= endpos);
+ if (keyinfo->flag & HA_FULLTEXT)
+ {
+ uint off;
+ int subkeys;
+ get_key_full_length_rdonly(off, key.data);
+ subkeys= ft_sintXkorr(key.data + off);
+ if (subkeys < 0)
+ {
+ next_page= _ma_row_pos_from_key(&key);
+ _ma_dpointer(share, keypos - nod_flag - share->rec_reflength,
+ param->new_file_pos); /* Save new pos */
+ if (sort_one_index(param,info,&share->ft2_keyinfo,
+ next_page,new_file))
+ goto err;
+ }
+ }
+ }
+ }
+
+ /* Fill block with zero and write it to the new index file */
+ length= _ma_get_page_used(share, buff);
+ bzero((uchar*) buff+length,keyinfo->block_length-length);
+ put_crc(buff, new_page_pos, share);
+ if (my_pwrite(new_file,(uchar*) buff,(uint) keyinfo->block_length,
+ new_page_pos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ _ma_check_print_error(param,"Can't write indexblock, error: %d",my_errno);
+ goto err;
+ }
+ my_afree((uchar*) buff);
+ DBUG_RETURN(0);
+err:
+ my_afree((uchar*) buff);
+ DBUG_RETURN(1);
+} /* sort_one_index */
+
+
+/**
+ @brief Fill empty space in index file with zeroes
+
+ @return
+ @retval 0 Ok
+ @retval 1 Error
+*/
+
+static my_bool maria_zerofill_index(HA_CHECK *param, MARIA_HA *info,
+ const char *name)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_PINNED_PAGE page_link;
+ char llbuff[21];
+ uchar *buff;
+ pgcache_page_no_t page;
+ my_off_t pos;
+ my_off_t key_file_length= share->state.state.key_file_length;
+ uint block_size= share->block_size;
+ my_bool zero_lsn= (share->base.born_transactional &&
+ !(param->testflag & T_ZEROFILL_KEEP_LSN));
+ DBUG_ENTER("maria_zerofill_index");
+
+ if (!(param->testflag & T_SILENT))
+ printf("- Zerofilling index for MARIA-table '%s'\n",name);
+
+ /* Go through the index file */
+ for (pos= share->base.keystart, page= (ulonglong) (pos / block_size);
+ pos < key_file_length;
+ pos+= block_size, page++)
+ {
+ uint length;
+ if (!(buff= pagecache_read(share->pagecache,
+ &share->kfile, page,
+ DFLT_INIT_HITS, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
+ {
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ _ma_check_print_error(param,
+ "Page %9s: Got error %d when reading index file",
+ llstr(pos, llbuff), my_errno);
+ DBUG_RETURN(1);
+ }
+ if (zero_lsn)
+ bzero(buff, LSN_SIZE);
+
+ if (share->base.born_transactional)
+ {
+ uint keynr= _ma_get_keynr(share, buff);
+ if (keynr != MARIA_DELETE_KEY_NR)
+ {
+ DBUG_ASSERT(keynr < share->base.keys);
+ if (_ma_compact_keypage(info, share->keyinfo + keynr, pos,
+ buff, ~(TrID) 0))
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Got error %d when reading index "
+ "file",
+ llstr(pos, llbuff), my_errno);
+ DBUG_RETURN(1);
+ }
+ }
+ }
+
+ length= _ma_get_page_used(share, buff);
+ DBUG_ASSERT(length <= block_size);
+ if (length < block_size)
+ bzero(buff + length, block_size - length);
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 1, FALSE);
+ }
+ if (flush_pagecache_blocks(share->pagecache, &share->kfile,
+ FLUSH_FORCE_WRITE))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Fill empty space in data file with zeroes
+
+ @todo
+ Zerofill all pages marked in bitmap as empty and change them to
+ be of type UNALLOCATED_PAGE
+
+ @return
+ @retval 0 Ok
+ @retval 1 Error
+*/
+
+static my_bool maria_zerofill_data(HA_CHECK *param, MARIA_HA *info,
+ const char *name)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_PINNED_PAGE page_link;
+ char llbuff[21];
+ my_off_t pos;
+ pgcache_page_no_t page;
+ uint block_size= share->block_size;
+ MARIA_FILE_BITMAP *bitmap= &share->bitmap;
+ my_bool zero_lsn= !(param->testflag & T_ZEROFILL_KEEP_LSN), error;
+ DBUG_ENTER("maria_zerofill_data");
+
+ /* This works only with BLOCK_RECORD files */
+ if (share->data_file_type != BLOCK_RECORD)
+ DBUG_RETURN(0);
+
+ if (!(param->testflag & T_SILENT))
+ printf("- Zerofilling data for MARIA-table '%s'\n",name);
+
+ /* Go through the record file */
+ for (page= 1, pos= block_size;
+ pos < share->state.state.data_file_length;
+ pos+= block_size, page++)
+ {
+ uchar *buff;
+ enum en_page_type page_type;
+
+ /* Ignore bitmap pages */
+ if ((page % share->bitmap.pages_covered) == 0)
+ continue;
+ if (!(buff= pagecache_read(share->pagecache,
+ &info->dfile,
+ page, 1, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
+ {
+ _ma_check_print_error(param,
+ "Page %9s: Got error: %d when reading datafile",
+ llstr(pos, llbuff), my_errno);
+ goto err;
+ }
+ page_type= (enum en_page_type) (buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK);
+ switch (page_type) {
+ case UNALLOCATED_PAGE:
+ if (zero_lsn)
+ bzero(buff, block_size);
+ else
+ bzero(buff + LSN_SIZE, block_size - LSN_SIZE);
+ break;
+ case BLOB_PAGE:
+ if (_ma_bitmap_get_page_bits(info, bitmap, page) == 0)
+ {
+ /* Unallocated page */
+ if (zero_lsn)
+ bzero(buff, block_size);
+ else
+ bzero(buff + LSN_SIZE, block_size - LSN_SIZE);
+ }
+ else
+ if (zero_lsn)
+ bzero(buff, LSN_SIZE);
+ break;
+ case HEAD_PAGE:
+ case TAIL_PAGE:
+ {
+ uint max_entry= (uint) buff[DIR_COUNT_OFFSET];
+ uint offset, dir_start;
+ uchar *dir;
+
+ if (zero_lsn)
+ bzero(buff, LSN_SIZE);
+ if (max_entry != 0)
+ {
+ my_bool is_head_page= (page_type == HEAD_PAGE);
+ dir= dir_entry_pos(buff, block_size, max_entry - 1);
+ _ma_compact_block_page(buff, block_size, max_entry -1, 0,
+ is_head_page ? ~(TrID) 0 : 0,
+ is_head_page ?
+ share->base.min_block_length : 0);
+ /* compactation may have increased free space */
+ if (_ma_bitmap_set(info, page, is_head_page,
+ uint2korr(buff + EMPTY_SPACE_OFFSET)))
+ goto err;
+
+ /* Zerofill the not used part */
+ offset= uint2korr(dir) + uint2korr(dir+2);
+ dir_start= (uint) (dir - buff);
+ DBUG_ASSERT(dir_start >= offset);
+ if (dir_start > offset)
+ bzero(buff + offset, dir_start - offset);
+ }
+ break;
+ }
+ default:
+ _ma_check_print_error(param,
+ "Page %9s: Found unrecognizable block of type %d",
+ llstr(pos, llbuff), page_type);
+ goto err;
+ }
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 1, FALSE);
+ }
+ error= _ma_bitmap_flush(share);
+ if (flush_pagecache_blocks(share->pagecache, &info->dfile,
+ FLUSH_FORCE_WRITE))
+ error= 1;
+ DBUG_RETURN(error);
+
+err:
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ /* flush what was changed so far */
+ (void) _ma_bitmap_flush(share);
+ (void) flush_pagecache_blocks(share->pagecache, &info->dfile,
+ FLUSH_FORCE_WRITE);
+
+ DBUG_RETURN(1);
+}
+
+
+/**
+ @brief Fill empty space in index and data files with zeroes
+
+ @return
+ @retval 0 Ok
+ @retval 1 Error
+*/
+
+int maria_zerofill(HA_CHECK *param, MARIA_HA *info, const char *name)
+{
+ my_bool error, reenable_logging,
+ zero_lsn= !(param->testflag & T_ZEROFILL_KEEP_LSN);
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_zerofill");
+ if ((reenable_logging= share->now_transactional))
+ _ma_tmp_disable_logging_for_table(info, 0);
+ if (!(error= (maria_zerofill_index(param, info, name) ||
+ maria_zerofill_data(param, info, name) ||
+ _ma_set_uuid(info, 0))))
+ {
+ /*
+ Mark that we have done zerofill of data and index. If we zeroed pages'
+ LSN, table is movable.
+ */
+ share->state.changed&= ~STATE_NOT_ZEROFILLED;
+ if (zero_lsn)
+ {
+ share->state.changed&= ~(STATE_NOT_MOVABLE | STATE_MOVED);
+ /* Table should get new LSNs */
+ share->state.create_rename_lsn= share->state.is_of_horizon=
+ share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS;
+ }
+ /* Ensure state is later flushed to disk, if within maria_chk */
+ info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ /* Reset create_trid to make file comparable */
+ share->state.create_trid= 0;
+ }
+ if (reenable_logging)
+ _ma_reenable_logging_for_table(info, FALSE);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Let temporary file replace old file.
+ This assumes that the new file was created in the same
+ directory as given by realpath(filename).
+ This will ensure that any symlinks that are used will still work.
+ Copy stats from old file to new file, deletes orignal and
+ changes new file name to old file name
+*/
+
+int maria_change_to_newfile(const char * filename, const char * old_ext,
+ const char * new_ext, myf MyFlags)
+{
+ char old_filename[FN_REFLEN],new_filename[FN_REFLEN];
+#ifdef USE_RAID
+ if (raid_chunks)
+ return my_raid_redel(fn_format(old_filename,filename,"",old_ext,2+4),
+ fn_format(new_filename,filename,"",new_ext,2+4),
+ raid_chunks,
+ MYF(MY_WME | MY_LINK_WARNING | MyFlags));
+#endif
+ /* Get real path to filename */
+ (void) fn_format(old_filename,filename,"",old_ext,2+4+32);
+ return my_redel(old_filename,
+ fn_format(new_filename,old_filename,"",new_ext,2+4),
+ MYF(MY_WME | MY_LINK_WARNING | MyFlags));
+} /* maria_change_to_newfile */
+
+
+/* Copy a block between two files */
+
+int maria_filecopy(HA_CHECK *param, File to,File from,my_off_t start,
+ my_off_t length, const char *type)
+{
+ char tmp_buff[IO_SIZE],*buff;
+ ulong buff_length;
+ DBUG_ENTER("maria_filecopy");
+
+ buff_length=(ulong) min(param->write_buffer_length,length);
+ if (!(buff=my_malloc(buff_length,MYF(0))))
+ {
+ buff=tmp_buff; buff_length=IO_SIZE;
+ }
+
+ VOID(my_seek(from,start,MY_SEEK_SET,MYF(0)));
+ while (length > buff_length)
+ {
+ if (my_read(from,(uchar*) buff,buff_length,MYF(MY_NABP)) ||
+ my_write(to,(uchar*) buff,buff_length,param->myf_rw))
+ goto err;
+ length-= buff_length;
+ }
+ if (my_read(from,(uchar*) buff,(uint) length,MYF(MY_NABP)) ||
+ my_write(to,(uchar*) buff,(uint) length,param->myf_rw))
+ goto err;
+ if (buff != tmp_buff)
+ my_free(buff,MYF(0));
+ DBUG_RETURN(0);
+err:
+ if (buff != tmp_buff)
+ my_free(buff,MYF(0));
+ _ma_check_print_error(param,"Can't copy %s to tempfile, error %d",
+ type,my_errno);
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Repair table or given index using sorting
+
+ SYNOPSIS
+ maria_repair_by_sort()
+ param Repair parameters
+ info MARIA handler to repair
+ name Name of table (for warnings)
+ rep_quick set to <> 0 if we should not change data file
+
+ RESULT
+ 0 ok
+ <>0 Error
+*/
+
+int maria_repair_by_sort(HA_CHECK *param, register MARIA_HA *info,
+ const char * name, my_bool rep_quick)
+{
+ int got_error;
+ uint i;
+ ha_rows start_records;
+ my_off_t new_header_length, org_header_length, del;
+ File new_file;
+ MARIA_SORT_PARAM sort_param;
+ MARIA_SHARE *share= info->s;
+ HA_KEYSEG *keyseg;
+ double *rec_per_key_part;
+ char llbuff[22];
+ MARIA_SORT_INFO sort_info;
+ ulonglong key_map;
+ myf sync_dir= ((share->now_transactional && !share->temporary) ?
+ MY_SYNC_DIR : 0);
+ my_bool scan_inited= 0;
+ DBUG_ENTER("maria_repair_by_sort");
+ LINT_INIT(key_map);
+
+ got_error= 1;
+ new_file= -1;
+ start_records= share->state.state.records;
+ if (!(param->testflag & T_SILENT))
+ {
+ printf("- recovering (with sort) MARIA-table '%s'\n",name);
+ printf("Data records: %s\n", llstr(start_records,llbuff));
+ }
+
+ if (initialize_variables_for_repair(param, &sort_info, &sort_param, info,
+ rep_quick))
+ goto err;
+
+ org_header_length= share->pack.header_length;
+ new_header_length= (param->testflag & T_UNPACK) ? 0 : org_header_length;
+ sort_param.filepos= new_header_length;
+
+ if (!rep_quick)
+ {
+ /* Get real path for data file */
+ if ((new_file=my_create(fn_format(param->temp_filename,
+ share->data_file_name.str, "",
+ DATA_TMP_EXT, 2+4),
+ 0,param->tmpfile_createflag,
+ MYF(0))) < 0)
+ {
+ _ma_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ goto err;
+ }
+ if (new_header_length &&
+ maria_filecopy(param, new_file, info->dfile.file, 0L,
+ new_header_length, "datafile-header"))
+ goto err;
+
+ share->state.dellink= HA_OFFSET_ERROR;
+ info->rec_cache.file= new_file; /* For sort_delete_record */
+ if (share->data_file_type == BLOCK_RECORD ||
+ (param->testflag & T_UNPACK))
+ {
+ if (create_new_data_handle(&sort_param, new_file))
+ goto err;
+ sort_info.new_info->rec_cache.file= new_file;
+ }
+ }
+
+ if (!(sort_info.key_block=
+ alloc_key_blocks(param,
+ (uint) param->sort_key_blocks,
+ share->base.max_key_block_length)))
+ goto err;
+ sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
+
+ if (share->data_file_type != BLOCK_RECORD)
+ {
+ /* We need a read buffer to read rows in big blocks */
+ if (init_io_cache(&param->read_cache, info->dfile.file,
+ (uint) param->read_buffer_length,
+ READ_CACHE, org_header_length, 1, MYF(MY_WME)))
+ goto err;
+ }
+ if (sort_info.new_info->s->data_file_type != BLOCK_RECORD)
+ {
+ /* When writing to not block records, we need a write buffer */
+ if (!rep_quick)
+ {
+ if (init_io_cache(&sort_info.new_info->rec_cache, new_file,
+ (uint) param->write_buffer_length,
+ WRITE_CACHE, new_header_length, 1,
+ MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw))
+ goto err;
+ sort_info.new_info->opt_flag|= WRITE_CACHE_USED;
+ }
+ }
+
+ if (!(sort_param.record=
+ (uchar*) my_malloc((size_t) share->base.default_rec_buff_size,
+ MYF(0))) ||
+ _ma_alloc_buffer(&sort_param.rec_buff, &sort_param.rec_buff_size,
+ share->base.default_rec_buff_size))
+ {
+ _ma_check_print_error(param, "Not enough memory for extra record");
+ goto err;
+ }
+
+ /* Optionally drop indexes and optionally modify the key_map */
+ maria_drop_all_indexes(param, info, FALSE);
+ key_map= share->state.key_map;
+ if (param->testflag & T_CREATE_MISSING_KEYS)
+ {
+ /* Invert the copied key_map to recreate all disabled indexes. */
+ key_map= ~key_map;
+ }
+
+ param->read_cache.end_of_file= sort_info.filelength;
+ sort_param.wordlist=NULL;
+ init_alloc_root(&sort_param.wordroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
+
+ sort_param.key_cmp=sort_key_cmp;
+ sort_param.lock_in_memory=maria_lock_memory;
+ sort_param.tmpdir=param->tmpdir;
+ sort_param.master =1;
+
+ del=share->state.state.del;
+
+ rec_per_key_part= param->new_rec_per_key_part;
+ for (sort_param.key=0 ; sort_param.key < share->base.keys ;
+ rec_per_key_part+=sort_param.keyinfo->keysegs, sort_param.key++)
+ {
+ sort_param.keyinfo=share->keyinfo+sort_param.key;
+ /*
+ Skip this index if it is marked disabled in the copied
+ (and possibly inverted) key_map.
+ */
+ if (! maria_is_key_active(key_map, sort_param.key))
+ {
+ /* Remember old statistics for key */
+ memcpy((char*) rec_per_key_part,
+ (char*) (share->state.rec_per_key_part +
+ (uint) (rec_per_key_part - param->new_rec_per_key_part)),
+ sort_param.keyinfo->keysegs*sizeof(*rec_per_key_part));
+ DBUG_PRINT("repair", ("skipping seemingly disabled index #: %u",
+ sort_param.key));
+ continue;
+ }
+
+ if ((!(param->testflag & T_SILENT)))
+ printf ("- Fixing index %d\n",sort_param.key+1);
+
+ sort_param.read_cache=param->read_cache;
+ sort_param.seg=sort_param.keyinfo->seg;
+ sort_param.max_pos= sort_param.pos= org_header_length;
+ keyseg=sort_param.seg;
+ bzero((char*) sort_param.unique,sizeof(sort_param.unique));
+ sort_param.key_length=share->rec_reflength;
+ for (i=0 ; keyseg[i].type != HA_KEYTYPE_END; i++)
+ {
+ sort_param.key_length+=keyseg[i].length;
+ if (keyseg[i].flag & HA_SPACE_PACK)
+ sort_param.key_length+=get_pack_length(keyseg[i].length);
+ if (keyseg[i].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
+ sort_param.key_length+=2 + test(keyseg[i].length >= 127);
+ if (keyseg[i].flag & HA_NULL_PART)
+ sort_param.key_length++;
+ }
+ share->state.state.records=share->state.state.del=share->state.split=0;
+ share->state.state.empty=0;
+
+ if (sort_param.keyinfo->flag & HA_FULLTEXT)
+ {
+ uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
+ sort_param.keyinfo->seg->charset->mbmaxlen;
+ sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
+ /*
+ fulltext indexes may have much more entries than the
+ number of rows in the table. We estimate the number here.
+
+ Note, built-in parser is always nr. 0 - see ftparser_call_initializer()
+ */
+ if (sort_param.keyinfo->ftparser_nr == 0)
+ {
+ /*
+ for built-in parser the number of generated index entries
+ cannot be larger than the size of the data file divided
+ by the minimal word's length
+ */
+ sort_info.max_records=
+ (ha_rows) (sort_info.filelength/ft_min_word_len+1);
+ }
+ else
+ {
+ /*
+ for external plugin parser we cannot tell anything at all :(
+ so, we'll use all the sort memory and start from ~10 buffpeks.
+ (see _ma_create_index_by_sort)
+ */
+ sort_info.max_records=
+ 10*param->sort_buffer_length/sort_param.key_length;
+ }
+
+ sort_param.key_read= sort_maria_ft_key_read;
+ sort_param.key_write= sort_maria_ft_key_write;
+ }
+ else
+ {
+ sort_param.key_read= sort_key_read;
+ sort_param.key_write= sort_key_write;
+ }
+
+ if (sort_info.new_info->s->data_file_type == BLOCK_RECORD)
+ {
+ scan_inited= 1;
+ if (maria_scan_init(sort_info.info))
+ goto err;
+ }
+ if (_ma_create_index_by_sort(&sort_param,
+ (my_bool) (!(param->testflag & T_VERBOSE)),
+ (size_t) param->sort_buffer_length))
+ {
+ param->retry_repair=1;
+ _ma_check_print_error(param, "Create index by sort failed");
+ goto err;
+ }
+ DBUG_EXECUTE_IF("maria_flush_whole_log",
+ {
+ DBUG_PRINT("maria_flush_whole_log", ("now"));
+ translog_flush(translog_get_horizon());
+ });
+ DBUG_EXECUTE_IF("maria_crash_create_index_by_sort",
+ {
+ DBUG_PRINT("maria_crash_create_index_by_sort", ("now"));
+ DBUG_ABORT();
+ });
+ if (scan_inited)
+ {
+ scan_inited= 0;
+ maria_scan_end(sort_info.info);
+ }
+
+ /* No need to calculate checksum again. */
+ sort_param.calc_checksum= 0;
+ free_root(&sort_param.wordroot, MYF(0));
+
+ /* Set for next loop */
+ sort_info.max_records= (ha_rows) sort_info.new_info->s->state.state.records;
+ if (param->testflag & T_STATISTICS)
+ maria_update_key_parts(sort_param.keyinfo, rec_per_key_part,
+ sort_param.unique,
+ (param->stats_method ==
+ MI_STATS_METHOD_IGNORE_NULLS ?
+ sort_param.notnull : NULL),
+ (ulonglong) share->state.state.records);
+ maria_set_key_active(share->state.key_map, sort_param.key);
+ DBUG_PRINT("repair", ("set enabled index #: %u", sort_param.key));
+
+ if (_ma_flush_table_files_before_swap(param, info))
+ goto err;
+
+ if (sort_param.fix_datafile)
+ {
+ param->read_cache.end_of_file=sort_param.filepos;
+ if (maria_write_data_suffix(&sort_info,1) ||
+ end_io_cache(&sort_info.new_info->rec_cache))
+ {
+ _ma_check_print_error(param, "Got error when flushing row cache");
+ goto err;
+ }
+ sort_info.new_info->opt_flag&= ~WRITE_CACHE_USED;
+
+ if (param->testflag & T_SAFE_REPAIR)
+ {
+ /* Don't repair if we loosed more than one row */
+ if (share->state.state.records+1 < start_records)
+ {
+ _ma_check_print_error(param,
+ "Rows lost; Aborting because safe repair was "
+ "requested");
+ share->state.state.records=start_records;
+ goto err;
+ }
+ }
+
+ sort_info.new_info->s->state.state.data_file_length= sort_param.filepos;
+ if (sort_info.new_info != sort_info.info)
+ {
+ MARIA_STATE_INFO save_state= sort_info.new_info->s->state;
+ if (maria_close(sort_info.new_info))
+ {
+ _ma_check_print_error(param, "Got error %d on close", my_errno);
+ goto err;
+ }
+ copy_data_file_state(&share->state, &save_state);
+ new_file= -1;
+ sort_info.new_info= info;
+ info->rec_cache.file= info->dfile.file;
+ }
+
+ share->state.version=(ulong) time((time_t*) 0); /* Force reopen */
+
+ /* Replace the actual file with the temporary file */
+ if (new_file >= 0)
+ {
+ my_close(new_file, MYF(MY_WME));
+ new_file= -1;
+ }
+ change_data_file_descriptor(info, -1);
+ if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
+ DATA_TMP_EXT,
+ (param->testflag & T_BACKUP_DATA ?
+ MYF(MY_REDEL_MAKE_BACKUP): MYF(0)) |
+ sync_dir) ||
+ _ma_open_datafile(info, share, NullS, -1))
+ {
+ _ma_check_print_error(param, "Couldn't change to new data file");
+ goto err;
+ }
+ if (param->testflag & T_UNPACK)
+ restore_data_file_type(share);
+
+ org_header_length= share->pack.header_length;
+ sort_info.org_data_file_type= share->data_file_type;
+ sort_info.filelength= share->state.state.data_file_length;
+ sort_param.fix_datafile=0;
+ }
+ else
+ share->state.state.data_file_length=sort_param.max_pos;
+
+ param->read_cache.file= info->dfile.file; /* re-init read cache */
+ reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
+ 1,1);
+ }
+
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+
+ if (rep_quick && del+sort_info.dupp != share->state.state.del)
+ {
+ _ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
+ _ma_check_print_error(param,"Run recovery again without -q");
+ got_error=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ goto err;
+ }
+
+ if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
+ {
+ my_off_t skr= (share->state.state.data_file_length +
+ (sort_info.org_data_file_type == COMPRESSED_RECORD) ?
+ MEMMAP_EXTRA_MARGIN : 0);
+#ifdef USE_RELOC
+ if (sort_info.org_data_file_type == STATIC_RECORD &&
+ skr < share->base.reloc*share->base.min_pack_length)
+ skr=share->base.reloc*share->base.min_pack_length;
+#endif
+ if (skr != sort_info.filelength)
+ if (my_chsize(info->dfile.file, skr, 0, MYF(0)))
+ _ma_check_print_warning(param,
+ "Can't change size of datafile, error: %d",
+ my_errno);
+ }
+
+ if (param->testflag & T_CALC_CHECKSUM)
+ share->state.state.checksum=param->glob_crc;
+
+ if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
+ _ma_check_print_warning(param,
+ "Can't change size of indexfile, error: %d",
+ my_errno);
+
+ if (!(param->testflag & T_SILENT))
+ {
+ if (start_records != share->state.state.records)
+ printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
+ }
+ if (sort_info.dupp)
+ _ma_check_print_warning(param,
+ "%s records have been removed",
+ llstr(sort_info.dupp,llbuff));
+ got_error=0;
+ /* If invoked by external program that uses thr_lock */
+ if (&share->state.state != info->state)
+ *info->state= *info->state_start= share->state.state;
+
+err:
+ if (scan_inited)
+ maria_scan_end(sort_info.info);
+ _ma_reset_state(info);
+
+ VOID(end_io_cache(&sort_info.new_info->rec_cache));
+ VOID(end_io_cache(&param->read_cache));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ if (got_error)
+ {
+ if (! param->error_printed)
+ _ma_check_print_error(param,"%d when fixing table",my_errno);
+ (void)_ma_flush_table_files_before_swap(param, info);
+ if (sort_info.new_info && sort_info.new_info != sort_info.info)
+ {
+ unuse_data_file_descriptor(sort_info.new_info);
+ maria_close(sort_info.new_info);
+ }
+ if (new_file >= 0)
+ {
+ VOID(my_close(new_file,MYF(0)));
+ VOID(my_delete(param->temp_filename, MYF(MY_WME)));
+ }
+ maria_mark_crashed_on_repair(info);
+ }
+ else
+ {
+ if (key_map == share->state.key_map)
+ share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
+ /*
+ Now that we have flushed and forced everything, we can bump
+ create_rename_lsn:
+ */
+ DBUG_EXECUTE_IF("maria_flush_whole_log",
+ {
+ DBUG_PRINT("maria_flush_whole_log", ("now"));
+ translog_flush(translog_get_horizon());
+ });
+ DBUG_EXECUTE_IF("maria_crash_repair",
+ {
+ DBUG_PRINT("maria_crash_repair", ("now"));
+ DBUG_ABORT();
+ });
+ }
+ share->state.changed|= STATE_NOT_SORTED_PAGES;
+ if (!rep_quick)
+ share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ my_free(sort_param.rec_buff, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(got_error);
+}
+
+
+/*
+ Threaded repair of table using sorting
+
+ SYNOPSIS
+ maria_repair_parallel()
+ param Repair parameters
+ info MARIA handler to repair
+ name Name of table (for warnings)
+ rep_quick set to <> 0 if we should not change data file
+
+ DESCRIPTION
+ Same as maria_repair_by_sort but do it multithreaded
+ Each key is handled by a separate thread.
+ TODO: make a number of threads a parameter
+
+ In parallel repair we use one thread per index. There are two modes:
+
+ Quick
+
+ Only the indexes are rebuilt. All threads share a read buffer.
+ Every thread that needs fresh data in the buffer enters the shared
+ cache lock. The last thread joining the lock reads the buffer from
+ the data file and wakes all other threads.
+
+ Non-quick
+
+ The data file is rebuilt and all indexes are rebuilt to point to
+ the new record positions. One thread is the master thread. It
+ reads from the old data file and writes to the new data file. It
+ also creates one of the indexes. The other threads read from a
+ buffer which is filled by the master. If they need fresh data,
+ they enter the shared cache lock. If the masters write buffer is
+ full, it flushes it to the new data file and enters the shared
+ cache lock too. When all threads joined in the lock, the master
+ copies its write buffer to the read buffer for the other threads
+ and wakes them.
+
+ RESULT
+ 0 ok
+ <>0 Error
+*/
+
+int maria_repair_parallel(HA_CHECK *param, register MARIA_HA *info,
+ const char * name, my_bool rep_quick)
+{
+#ifndef THREAD
+ return maria_repair_by_sort(param, info, name, rep_quick);
+#else
+ int got_error;
+ uint i,key, total_key_length, istep;
+ ha_rows start_records;
+ my_off_t new_header_length,del;
+ File new_file;
+ MARIA_SORT_PARAM *sort_param=0, tmp_sort_param;
+ MARIA_SHARE *share= info->s;
+ double *rec_per_key_part;
+ HA_KEYSEG *keyseg;
+ char llbuff[22];
+ IO_CACHE new_data_cache; /* For non-quick repair. */
+ IO_CACHE_SHARE io_share;
+ MARIA_SORT_INFO sort_info;
+ ulonglong key_map;
+ pthread_attr_t thr_attr;
+ myf sync_dir= ((share->now_transactional && !share->temporary) ?
+ MY_SYNC_DIR : 0);
+ DBUG_ENTER("maria_repair_parallel");
+ LINT_INIT(key_map);
+
+ got_error= 1;
+ new_file= -1;
+ start_records= share->state.state.records;
+ if (!(param->testflag & T_SILENT))
+ {
+ printf("- parallel recovering (with sort) MARIA-table '%s'\n",name);
+ printf("Data records: %s\n", llstr(start_records, llbuff));
+ }
+
+ if (initialize_variables_for_repair(param, &sort_info, &tmp_sort_param, info,
+ rep_quick))
+ goto err;
+
+ new_header_length= ((param->testflag & T_UNPACK) ? 0 :
+ share->pack.header_length);
+
+ /*
+ Quick repair (not touching data file, rebuilding indexes):
+ {
+ Read cache is (HA_CHECK *param)->read_cache using info->dfile.file.
+ }
+
+ Non-quick repair (rebuilding data file and indexes):
+ {
+ Master thread:
+
+ Read cache is (HA_CHECK *param)->read_cache using info->dfile.file.
+ Write cache is (MARIA_INFO *info)->rec_cache using new_file.
+
+ Slave threads:
+
+ Read cache is new_data_cache synced to master rec_cache.
+
+ The final assignment of the filedescriptor for rec_cache is done
+ after the cache creation.
+
+ Don't check file size on new_data_cache, as the resulting file size
+ is not known yet.
+
+ As rec_cache and new_data_cache are synced, write_buffer_length is
+ used for the read cache 'new_data_cache'. Both start at the same
+ position 'new_header_length'.
+ }
+ */
+ DBUG_PRINT("info", ("is quick repair: %d", (int) rep_quick));
+
+ /* Initialize pthread structures before goto err. */
+ pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&sort_info.cond, 0);
+
+ if (!(sort_info.key_block=
+ alloc_key_blocks(param, (uint) param->sort_key_blocks,
+ share->base.max_key_block_length)) ||
+ init_io_cache(&param->read_cache, info->dfile.file,
+ (uint) param->read_buffer_length,
+ READ_CACHE, share->pack.header_length, 1, MYF(MY_WME)) ||
+ (!rep_quick &&
+ (init_io_cache(&info->rec_cache, info->dfile.file,
+ (uint) param->write_buffer_length,
+ WRITE_CACHE, new_header_length, 1,
+ MYF(MY_WME | MY_WAIT_IF_FULL) & param->myf_rw) ||
+ init_io_cache(&new_data_cache, -1,
+ (uint) param->write_buffer_length,
+ READ_CACHE, new_header_length, 1,
+ MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))))
+ goto err;
+ sort_info.key_block_end=sort_info.key_block+param->sort_key_blocks;
+ info->opt_flag|=WRITE_CACHE_USED;
+ info->rec_cache.file= info->dfile.file; /* for sort_delete_record */
+
+ if (!rep_quick)
+ {
+ /* Get real path for data file */
+ if ((new_file= my_create(fn_format(param->temp_filename,
+ share->data_file_name.str, "",
+ DATA_TMP_EXT,
+ 2+4),
+ 0,param->tmpfile_createflag,
+ MYF(0))) < 0)
+ {
+ _ma_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ goto err;
+ }
+ if (new_header_length &&
+ maria_filecopy(param, new_file, info->dfile.file,0L,new_header_length,
+ "datafile-header"))
+ goto err;
+ if (param->testflag & T_UNPACK)
+ restore_data_file_type(share);
+ share->state.dellink= HA_OFFSET_ERROR;
+ info->rec_cache.file=new_file;
+ }
+
+ /* Optionally drop indexes and optionally modify the key_map. */
+ maria_drop_all_indexes(param, info, FALSE);
+ key_map= share->state.key_map;
+ if (param->testflag & T_CREATE_MISSING_KEYS)
+ {
+ /* Invert the copied key_map to recreate all disabled indexes. */
+ key_map= ~key_map;
+ }
+
+ param->read_cache.end_of_file= sort_info.filelength;
+
+ /*
+ +1 below is required hack for parallel repair mode.
+ The share->state.state.records value, that is compared later
+ to sort_info.max_records and cannot exceed it, is
+ increased in sort_key_write. In maria_repair_by_sort, sort_key_write
+ is called after sort_key_read, where the comparison is performed,
+ but in parallel mode master thread can call sort_key_write
+ before some other repair thread calls sort_key_read.
+ Furthermore I'm not even sure +1 would be enough.
+ May be sort_info.max_records shold be always set to max value in
+ parallel mode.
+ */
+ sort_info.max_records++;
+
+ del=share->state.state.del;
+
+ if (!(sort_param=(MARIA_SORT_PARAM *)
+ my_malloc((uint) share->base.keys *
+ (sizeof(MARIA_SORT_PARAM) + share->base.pack_reclength),
+ MYF(MY_ZEROFILL))))
+ {
+ _ma_check_print_error(param,"Not enough memory for key!");
+ goto err;
+ }
+ total_key_length=0;
+ rec_per_key_part= param->new_rec_per_key_part;
+ share->state.state.records=share->state.state.del=share->state.split=0;
+ share->state.state.empty=0;
+
+ for (i=key=0, istep=1 ; key < share->base.keys ;
+ rec_per_key_part+=sort_param[i].keyinfo->keysegs, i+=istep, key++)
+ {
+ sort_param[i].key=key;
+ sort_param[i].keyinfo=share->keyinfo+key;
+ sort_param[i].seg=sort_param[i].keyinfo->seg;
+ /*
+ Skip this index if it is marked disabled in the copied
+ (and possibly inverted) key_map.
+ */
+ if (! maria_is_key_active(key_map, key))
+ {
+ /* Remember old statistics for key */
+ memcpy((char*) rec_per_key_part,
+ (char*) (share->state.rec_per_key_part+
+ (uint) (rec_per_key_part - param->new_rec_per_key_part)),
+ sort_param[i].keyinfo->keysegs*sizeof(*rec_per_key_part));
+ istep=0;
+ continue;
+ }
+ istep=1;
+ if ((!(param->testflag & T_SILENT)))
+ printf ("- Fixing index %d\n",key+1);
+ if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
+ {
+ sort_param[i].key_read=sort_maria_ft_key_read;
+ sort_param[i].key_write=sort_maria_ft_key_write;
+ }
+ else
+ {
+ sort_param[i].key_read=sort_key_read;
+ sort_param[i].key_write=sort_key_write;
+ }
+ sort_param[i].key_cmp=sort_key_cmp;
+ sort_param[i].lock_in_memory=maria_lock_memory;
+ sort_param[i].tmpdir=param->tmpdir;
+ sort_param[i].sort_info=&sort_info;
+ sort_param[i].master=0;
+ sort_param[i].fix_datafile=0;
+ sort_param[i].calc_checksum= 0;
+
+ sort_param[i].filepos=new_header_length;
+ sort_param[i].max_pos=sort_param[i].pos=share->pack.header_length;
+
+ sort_param[i].record= (((uchar *)(sort_param+share->base.keys))+
+ (share->base.pack_reclength * i));
+ if (_ma_alloc_buffer(&sort_param[i].rec_buff, &sort_param[i].rec_buff_size,
+ share->base.default_rec_buff_size))
+ {
+ _ma_check_print_error(param,"Not enough memory!");
+ goto err;
+ }
+ sort_param[i].key_length=share->rec_reflength;
+ for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END;
+ keyseg++)
+ {
+ sort_param[i].key_length+=keyseg->length;
+ if (keyseg->flag & HA_SPACE_PACK)
+ sort_param[i].key_length+=get_pack_length(keyseg->length);
+ if (keyseg->flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
+ sort_param[i].key_length+=2 + test(keyseg->length >= 127);
+ if (keyseg->flag & HA_NULL_PART)
+ sort_param[i].key_length++;
+ }
+ total_key_length+=sort_param[i].key_length;
+
+ if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
+ {
+ uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
+ sort_param[i].keyinfo->seg->charset->mbmaxlen;
+ sort_param[i].key_length+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
+ init_alloc_root(&sort_param[i].wordroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
+ }
+ }
+ sort_info.total_keys=i;
+ sort_param[0].master= 1;
+ sort_param[0].fix_datafile= ! rep_quick;
+ sort_param[0].calc_checksum= test(param->testflag & T_CALC_CHECKSUM);
+
+ sort_info.got_error=0;
+ pthread_mutex_lock(&sort_info.mutex);
+
+ /*
+ Initialize the I/O cache share for use with the read caches and, in
+ case of non-quick repair, the write cache. When all threads join on
+ the cache lock, the writer copies the write cache contents to the
+ read caches.
+ */
+ if (i > 1)
+ {
+ if (rep_quick)
+ init_io_cache_share(&param->read_cache, &io_share, NULL, i);
+ else
+ init_io_cache_share(&new_data_cache, &io_share, &info->rec_cache, i);
+ }
+ else
+ io_share.total_threads= 0; /* share not used */
+
+ (void) pthread_attr_init(&thr_attr);
+ (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+
+ for (i=0 ; i < sort_info.total_keys ; i++)
+ {
+ /*
+ Copy the properly initialized IO_CACHE structure so that every
+ thread has its own copy. In quick mode param->read_cache is shared
+ for use by all threads. In non-quick mode all threads but the
+ first copy the shared new_data_cache, which is synchronized to the
+ write cache of the first thread. The first thread copies
+ param->read_cache, which is not shared.
+ */
+ sort_param[i].read_cache= ((rep_quick || !i) ? param->read_cache :
+ new_data_cache);
+ DBUG_PRINT("io_cache_share", ("thread: %u read_cache: 0x%lx",
+ i, (long) &sort_param[i].read_cache));
+
+ /*
+ two approaches: the same amount of memory for each thread
+ or the memory for the same number of keys for each thread...
+ In the second one all the threads will fill their sort_buffers
+ (and call write_keys) at the same time, putting more stress on i/o.
+ */
+ sort_param[i].sortbuff_size=
+#ifndef USING_SECOND_APPROACH
+ param->sort_buffer_length/sort_info.total_keys;
+#else
+ param->sort_buffer_length*sort_param[i].key_length/total_key_length;
+#endif
+ if (pthread_create(&sort_param[i].thr, &thr_attr,
+ _ma_thr_find_all_keys,
+ (void *) (sort_param+i)))
+ {
+ _ma_check_print_error(param,"Cannot start a repair thread");
+ /* Cleanup: Detach from the share. Avoid others to be blocked. */
+ if (io_share.total_threads)
+ remove_io_thread(&sort_param[i].read_cache);
+ DBUG_PRINT("error", ("Cannot start a repair thread"));
+ sort_info.got_error=1;
+ }
+ else
+ sort_info.threads_running++;
+ }
+ (void) pthread_attr_destroy(&thr_attr);
+
+ /* waiting for all threads to finish */
+ while (sort_info.threads_running)
+ pthread_cond_wait(&sort_info.cond, &sort_info.mutex);
+ pthread_mutex_unlock(&sort_info.mutex);
+
+ if ((got_error= _ma_thr_write_keys(sort_param)))
+ {
+ param->retry_repair=1;
+ goto err;
+ }
+ got_error=1; /* Assume the following may go wrong */
+
+ if (_ma_flush_table_files_before_swap(param, info))
+ goto err;
+
+ if (sort_param[0].fix_datafile)
+ {
+ /*
+ Append some nulls to the end of a memory mapped file. Destroy the
+ write cache. The master thread did already detach from the share
+ by remove_io_thread() in sort.c:thr_find_all_keys().
+ */
+ if (maria_write_data_suffix(&sort_info,1) ||
+ end_io_cache(&info->rec_cache))
+ goto err;
+ if (param->testflag & T_SAFE_REPAIR)
+ {
+ /* Don't repair if we loosed more than one row */
+ if (share->state.state.records+1 < start_records)
+ {
+ share->state.state.records=start_records;
+ goto err;
+ }
+ }
+ share->state.state.data_file_length= share->state.state.data_file_length=
+ sort_param->filepos;
+ /* Only whole records */
+ share->state.version= (ulong) time((time_t*) 0);
+ /*
+ Exchange the data file descriptor of the table, so that we use the
+ new file from now on.
+ */
+ my_close(info->dfile.file, MYF(0));
+ info->dfile.file= new_file;
+ share->pack.header_length=(ulong) new_header_length;
+ }
+ else
+ share->state.state.data_file_length=sort_param->max_pos;
+
+ if (rep_quick && del+sort_info.dupp != share->state.state.del)
+ {
+ _ma_check_print_error(param,"Couldn't fix table with quick recovery: Found wrong number of deleted records");
+ _ma_check_print_error(param,"Run recovery again without -q");
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ goto err;
+ }
+
+ if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
+ {
+ my_off_t skr= (share->state.state.data_file_length +
+ (sort_info.org_data_file_type == COMPRESSED_RECORD) ?
+ MEMMAP_EXTRA_MARGIN : 0);
+#ifdef USE_RELOC
+ if (sort_info.org_data_file_type == STATIC_RECORD &&
+ skr < share->base.reloc*share->base.min_pack_length)
+ skr=share->base.reloc*share->base.min_pack_length;
+#endif
+ if (skr != sort_info.filelength)
+ if (my_chsize(info->dfile.file, skr, 0, MYF(0)))
+ _ma_check_print_warning(param,
+ "Can't change size of datafile, error: %d",
+ my_errno);
+ }
+ if (param->testflag & T_CALC_CHECKSUM)
+ share->state.state.checksum=param->glob_crc;
+
+ if (my_chsize(share->kfile.file, share->state.state.key_file_length, 0, MYF(0)))
+ _ma_check_print_warning(param,
+ "Can't change size of indexfile, error: %d",
+ my_errno);
+
+ if (!(param->testflag & T_SILENT))
+ {
+ if (start_records != share->state.state.records)
+ printf("Data records: %s\n", llstr(share->state.state.records,llbuff));
+ }
+ if (sort_info.dupp)
+ _ma_check_print_warning(param,
+ "%s records have been removed",
+ llstr(sort_info.dupp,llbuff));
+ got_error=0;
+ /* If invoked by external program that uses thr_lock */
+ if (&share->state.state != info->state)
+ *info->state= *info->state_start= share->state.state;
+
+err:
+ _ma_reset_state(info);
+
+ /*
+ Destroy the write cache. The master thread did already detach from
+ the share by remove_io_thread() or it was not yet started (if the
+ error happend before creating the thread).
+ */
+ VOID(end_io_cache(&sort_info.new_info->rec_cache));
+ VOID(end_io_cache(&param->read_cache));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ sort_info.new_info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ /*
+ Destroy the new data cache in case of non-quick repair. All slave
+ threads did either detach from the share by remove_io_thread()
+ already or they were not yet started (if the error happend before
+ creating the threads).
+ */
+ if (!rep_quick)
+ VOID(end_io_cache(&new_data_cache));
+ if (!got_error)
+ {
+ /* Replace the actual file with the temporary file */
+ if (new_file >= 0)
+ {
+ my_close(new_file,MYF(0));
+ info->dfile.file= new_file= -1;
+ if (maria_change_to_newfile(share->data_file_name.str, MARIA_NAME_DEXT,
+ DATA_TMP_EXT,
+ MYF((param->testflag & T_BACKUP_DATA ?
+ MY_REDEL_MAKE_BACKUP : 0) |
+ sync_dir)) ||
+ _ma_open_datafile(info,share, NullS, -1))
+ got_error=1;
+ }
+ }
+ if (got_error)
+ {
+ if (! param->error_printed)
+ _ma_check_print_error(param,"%d when fixing table",my_errno);
+ (void)_ma_flush_table_files_before_swap(param, info);
+ if (new_file >= 0)
+ {
+ VOID(my_close(new_file,MYF(0)));
+ VOID(my_delete(param->temp_filename, MYF(MY_WME)));
+ if (info->dfile.file == new_file)
+ info->dfile.file= -1;
+ }
+ maria_mark_crashed_on_repair(info);
+ }
+ else if (key_map == share->state.key_map)
+ share->state.changed&= ~STATE_NOT_OPTIMIZED_KEYS;
+ share->state.changed|= STATE_NOT_SORTED_PAGES;
+ if (!rep_quick)
+ share->state.changed&= ~(STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ pthread_cond_destroy (&sort_info.cond);
+ pthread_mutex_destroy(&sort_info.mutex);
+
+ my_free((uchar*) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar*) sort_param,MYF(MY_ALLOW_ZERO_PTR));
+ my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
+ if (!got_error && (param->testflag & T_UNPACK))
+ restore_data_file_type(share);
+ DBUG_RETURN(got_error);
+#endif /* THREAD */
+}
+
+ /* Read next record and return next key */
+
+static int sort_key_read(MARIA_SORT_PARAM *sort_param, uchar *key)
+{
+ int error;
+ MARIA_SORT_INFO *sort_info= sort_param->sort_info;
+ MARIA_HA *info= sort_info->info;
+ MARIA_KEY int_key;
+ DBUG_ENTER("sort_key_read");
+
+ if ((error=sort_get_next_record(sort_param)))
+ DBUG_RETURN(error);
+ if (info->s->state.state.records == sort_info->max_records)
+ {
+ _ma_check_print_error(sort_info->param,
+ "Key %d - Found too many records; Can't continue",
+ sort_param->key+1);
+ DBUG_RETURN(1);
+ }
+ if (_ma_sort_write_record(sort_param))
+ DBUG_RETURN(1);
+
+ (*info->s->keyinfo[sort_param->key].make_key)(info, &int_key,
+ sort_param->key, key,
+ sort_param->record,
+ sort_param->current_filepos,
+ 0);
+ sort_param->real_key_length= int_key.data_length + int_key.ref_length;
+#ifdef HAVE_purify
+ bzero(key+sort_param->real_key_length,
+ (sort_param->key_length-sort_param->real_key_length));
+#endif
+ DBUG_RETURN(0);
+} /* sort_key_read */
+
+
+static int sort_maria_ft_key_read(MARIA_SORT_PARAM *sort_param, uchar *key)
+{
+ int error;
+ MARIA_SORT_INFO *sort_info=sort_param->sort_info;
+ MARIA_HA *info=sort_info->info;
+ FT_WORD *wptr=0;
+ MARIA_KEY int_key;
+ DBUG_ENTER("sort_maria_ft_key_read");
+
+ if (!sort_param->wordlist)
+ {
+ for (;;)
+ {
+ free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
+ if ((error=sort_get_next_record(sort_param)))
+ DBUG_RETURN(error);
+ if ((error= _ma_sort_write_record(sort_param)))
+ DBUG_RETURN(error);
+ if (!(wptr= _ma_ft_parserecord(info,sort_param->key,sort_param->record,
+ &sort_param->wordroot)))
+
+ DBUG_RETURN(1);
+ if (wptr->pos)
+ break;
+ }
+ sort_param->wordptr=sort_param->wordlist=wptr;
+ }
+ else
+ {
+ error=0;
+ wptr=(FT_WORD*)(sort_param->wordptr);
+ }
+
+ _ma_ft_make_key(info, &int_key, sort_param->key, key, wptr++,
+ sort_param->current_filepos);
+ sort_param->real_key_length= int_key.data_length + int_key.ref_length;
+
+#ifdef HAVE_purify
+ if (sort_param->key_length > sort_param->real_key_length)
+ bzero(key+sort_param->real_key_length,
+ (sort_param->key_length-sort_param->real_key_length));
+#endif
+ if (!wptr->pos)
+ {
+ free_root(&sort_param->wordroot, MYF(MY_MARK_BLOCKS_FREE));
+ sort_param->wordlist=0;
+ }
+ else
+ sort_param->wordptr=(void*)wptr;
+
+ DBUG_RETURN(error);
+} /* sort_maria_ft_key_read */
+
+
+/*
+ Read next record from file using parameters in sort_info.
+
+ SYNOPSIS
+ sort_get_next_record()
+ sort_param Information about and for the sort process
+
+ NOTES
+ Dynamic Records With Non-Quick Parallel Repair
+
+ For non-quick parallel repair we use a synchronized read/write
+ cache. This means that one thread is the master who fixes the data
+ file by reading each record from the old data file and writing it
+ to the new data file. By doing this the records in the new data
+ file are written contiguously. Whenever the write buffer is full,
+ it is copied to the read buffer. The slaves read from the read
+ buffer, which is not associated with a file. Thus read_cache.file
+ is -1. When using _mi_read_cache(), the slaves must always set
+ flag to READING_NEXT so that the function never tries to read from
+ file. This is safe because the records are contiguous. There is no
+ need to read outside the cache. This condition is evaluated in the
+ variable 'parallel_flag' for quick reference. read_cache.file must
+ be >= 0 in every other case.
+
+ RETURN
+ -1 end of file
+ 0 ok
+ sort_param->current_filepos points to record position.
+ sort_param->record contains record
+ sort_param->max_pos contains position to last byte read
+ > 0 error
+*/
+
+static int sort_get_next_record(MARIA_SORT_PARAM *sort_param)
+{
+ int searching;
+ int parallel_flag;
+ uint found_record,b_type,left_length;
+ my_off_t pos;
+ MARIA_BLOCK_INFO block_info;
+ MARIA_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
+ MARIA_HA *info=sort_info->info;
+ MARIA_SHARE *share= info->s;
+ char llbuff[22],llbuff2[22];
+ DBUG_ENTER("sort_get_next_record");
+
+ if (*_ma_killed_ptr(param))
+ DBUG_RETURN(1);
+
+ switch (sort_info->org_data_file_type) {
+ case BLOCK_RECORD:
+ {
+ for (;;)
+ {
+ int flag;
+ /*
+ Assume table is transactional and it had LSN pages in the
+ cache. Repair has flushed them, left data pages stay in
+ cache, and disabled transactionality (so share's current page
+ type is PLAIN); page cache would assert if it finds a cached LSN page
+ while _ma_scan_block_record() requested a PLAIN page. So we use
+ UNKNOWN.
+ */
+ enum pagecache_page_type save_page_type= share->page_type;
+ share->page_type= PAGECACHE_READ_UNKNOWN_PAGE;
+ if (info != sort_info->new_info)
+ {
+ /* Safe scanning */
+ flag= _ma_safe_scan_block_record(sort_info, info,
+ sort_param->record);
+ }
+ else
+ {
+ /*
+ Scan on clean table.
+ It requires a reliable data_file_length so we set it.
+ */
+ share->state.state.data_file_length= sort_info->filelength;
+ info->cur_row.trid= 0;
+ flag= _ma_scan_block_record(info, sort_param->record,
+ info->cur_row.nextpos, 1);
+ set_if_bigger(param->max_found_trid, info->cur_row.trid);
+ if (info->cur_row.trid > param->max_trid)
+ {
+ _ma_check_print_not_visible_error(param, info->cur_row.trid);
+ flag= HA_ERR_ROW_NOT_VISIBLE;
+ }
+ }
+ share->page_type= save_page_type;
+ if (!flag)
+ {
+ if (sort_param->calc_checksum)
+ {
+ ha_checksum checksum;
+ checksum= (*share->calc_check_checksum)(info, sort_param->record);
+ if (share->calc_checksum &&
+ info->cur_row.checksum != (checksum & 255))
+ {
+ if (param->testflag & T_VERBOSE)
+ {
+ record_pos_to_txt(info, info->cur_row.lastpos, llbuff);
+ _ma_check_print_info(param,
+ "Found record with wrong checksum at %s",
+ llbuff);
+ }
+ continue;
+ }
+ info->cur_row.checksum= checksum;
+ param->glob_crc+= checksum;
+ }
+ sort_param->start_recpos= sort_param->current_filepos=
+ info->cur_row.lastpos;
+ DBUG_RETURN(0);
+ }
+ if (flag == HA_ERR_END_OF_FILE)
+ {
+ sort_param->max_pos= share->state.state.data_file_length;
+ DBUG_RETURN(-1);
+ }
+ /* Retry only if wrong record, not if disk error */
+ if (flag != HA_ERR_WRONG_IN_RECORD)
+ {
+ retry_if_quick(sort_param, flag);
+ DBUG_RETURN(flag);
+ }
+ }
+ break; /* Impossible */
+ }
+ case STATIC_RECORD:
+ for (;;)
+ {
+ if (my_b_read(&sort_param->read_cache,sort_param->record,
+ share->base.pack_reclength))
+ {
+ if (sort_param->read_cache.error)
+ param->out_flag |= O_DATA_LOST;
+ retry_if_quick(sort_param, my_errno);
+ DBUG_RETURN(-1);
+ }
+ sort_param->start_recpos=sort_param->pos;
+ if (!sort_param->fix_datafile)
+ {
+ sort_param->current_filepos= sort_param->pos;
+ if (sort_param->master)
+ share->state.split++;
+ }
+ sort_param->max_pos=(sort_param->pos+=share->base.pack_reclength);
+ if (*sort_param->record)
+ {
+ if (sort_param->calc_checksum)
+ param->glob_crc+= (info->cur_row.checksum=
+ _ma_static_checksum(info,sort_param->record));
+ DBUG_RETURN(0);
+ }
+ if (!sort_param->fix_datafile && sort_param->master)
+ {
+ share->state.state.del++;
+ share->state.state.empty+=share->base.pack_reclength;
+ }
+ }
+ case DYNAMIC_RECORD:
+ {
+ uchar *to;
+ ha_checksum checksum= 0;
+ LINT_INIT(to);
+
+ pos=sort_param->pos;
+ searching=(sort_param->fix_datafile && (param->testflag & T_EXTEND));
+ parallel_flag= (sort_param->read_cache.file < 0) ? READING_NEXT : 0;
+ for (;;)
+ {
+ found_record=block_info.second_read= 0;
+ left_length=1;
+ if (searching)
+ {
+ pos=MY_ALIGN(pos,MARIA_DYN_ALIGN_SIZE);
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ sort_param->start_recpos=pos;
+ }
+ do
+ {
+ if (pos > sort_param->max_pos)
+ sort_param->max_pos=pos;
+ if (pos & (MARIA_DYN_ALIGN_SIZE-1))
+ {
+ if ((param->testflag & T_VERBOSE) || searching == 0)
+ _ma_check_print_info(param,"Wrong aligned block at %s",
+ llstr(pos,llbuff));
+ if (searching)
+ goto try_next;
+ }
+ if (found_record && pos == param->search_after_block)
+ _ma_check_print_info(param,"Block: %s used by record at %s",
+ llstr(param->search_after_block,llbuff),
+ llstr(sort_param->start_recpos,llbuff2));
+ if (_ma_read_cache(&sort_param->read_cache,
+ (uchar*) block_info.header,pos,
+ MARIA_BLOCK_INFO_HEADER_LENGTH,
+ (! found_record ? READING_NEXT : 0) |
+ parallel_flag | READING_HEADER))
+ {
+ if (found_record)
+ {
+ _ma_check_print_info(param,
+ "Can't read whole record at %s (errno: %d)",
+ llstr(sort_param->start_recpos,llbuff),errno);
+ goto try_next;
+ }
+ DBUG_RETURN(-1);
+ }
+ if (searching && ! sort_param->fix_datafile)
+ {
+ param->error_printed=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ DBUG_RETURN(1); /* Something wrong with data */
+ }
+ b_type= _ma_get_block_info(&block_info,-1,pos);
+ if ((b_type & (BLOCK_ERROR | BLOCK_FATAL_ERROR)) ||
+ ((b_type & BLOCK_FIRST) &&
+ (block_info.rec_len < (uint) share->base.min_pack_length ||
+ block_info.rec_len > (uint) share->base.max_pack_length)))
+ {
+ uint i;
+ if (param->testflag & T_VERBOSE || searching == 0)
+ _ma_check_print_info(param,
+ "Wrong bytesec: %3d-%3d-%3d at %10s; Skipped",
+ block_info.header[0],block_info.header[1],
+ block_info.header[2],llstr(pos,llbuff));
+ if (found_record)
+ goto try_next;
+ block_info.second_read=0;
+ searching=1;
+ /* Search after block in read header string */
+ for (i=MARIA_DYN_ALIGN_SIZE ;
+ i < MARIA_BLOCK_INFO_HEADER_LENGTH ;
+ i+= MARIA_DYN_ALIGN_SIZE)
+ if (block_info.header[i] >= 1 &&
+ block_info.header[i] <= MARIA_MAX_DYN_HEADER_BYTE)
+ break;
+ pos+=(ulong) i;
+ sort_param->start_recpos=pos;
+ continue;
+ }
+ if (b_type & BLOCK_DELETED)
+ {
+ my_bool error=0;
+ if (block_info.block_len+ (uint) (block_info.filepos-pos) <
+ share->base.min_block_length)
+ {
+ if (!searching)
+ _ma_check_print_info(param,
+ "Deleted block with impossible length %lu "
+ "at %s",
+ block_info.block_len,llstr(pos,llbuff));
+ error=1;
+ }
+ else
+ {
+ if ((block_info.next_filepos != HA_OFFSET_ERROR &&
+ block_info.next_filepos >=
+ share->state.state.data_file_length) ||
+ (block_info.prev_filepos != HA_OFFSET_ERROR &&
+ block_info.prev_filepos >= share->state.state.data_file_length))
+ {
+ if (!searching)
+ _ma_check_print_info(param,
+ "Delete link points outside datafile at %s",
+ llstr(pos,llbuff));
+ error=1;
+ }
+ }
+ if (error)
+ {
+ if (found_record)
+ goto try_next;
+ searching=1;
+ pos+= MARIA_DYN_ALIGN_SIZE;
+ sort_param->start_recpos=pos;
+ block_info.second_read=0;
+ continue;
+ }
+ }
+ else
+ {
+ if (block_info.block_len+ (uint) (block_info.filepos-pos) <
+ share->base.min_block_length ||
+ block_info.block_len > (uint) share->base.max_pack_length+
+ MARIA_SPLIT_LENGTH)
+ {
+ if (!searching)
+ _ma_check_print_info(param,
+ "Found block with impossible length %lu "
+ "at %s; Skipped",
+ block_info.block_len+
+ (uint) (block_info.filepos-pos),
+ llstr(pos,llbuff));
+ if (found_record)
+ goto try_next;
+ searching=1;
+ pos+= MARIA_DYN_ALIGN_SIZE;
+ sort_param->start_recpos=pos;
+ block_info.second_read=0;
+ continue;
+ }
+ }
+ if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ {
+ if (!sort_param->fix_datafile && sort_param->master &&
+ (b_type & BLOCK_DELETED))
+ {
+ share->state.state.empty+=block_info.block_len;
+ share->state.state.del++;
+ share->state.split++;
+ }
+ if (found_record)
+ goto try_next;
+ if (searching)
+ {
+ pos+=MARIA_DYN_ALIGN_SIZE;
+ sort_param->start_recpos=pos;
+ }
+ else
+ pos=block_info.filepos+block_info.block_len;
+ block_info.second_read=0;
+ continue;
+ }
+
+ if (!sort_param->fix_datafile && sort_param->master)
+ share->state.split++;
+ if (! found_record++)
+ {
+ sort_param->find_length=left_length=block_info.rec_len;
+ sort_param->start_recpos=pos;
+ if (!sort_param->fix_datafile)
+ sort_param->current_filepos= sort_param->start_recpos;
+ if (sort_param->fix_datafile && (param->testflag & T_EXTEND))
+ sort_param->pos=block_info.filepos+1;
+ else
+ sort_param->pos=block_info.filepos+block_info.block_len;
+ if (share->base.blobs)
+ {
+ if (_ma_alloc_buffer(&sort_param->rec_buff,
+ &sort_param->rec_buff_size,
+ block_info.rec_len +
+ share->base.extra_rec_buff_size))
+
+ {
+ if (param->max_record_length >= block_info.rec_len)
+ {
+ _ma_check_print_error(param,"Not enough memory for blob at %s (need %lu)",
+ llstr(sort_param->start_recpos,llbuff),
+ (ulong) block_info.rec_len);
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ _ma_check_print_info(param,"Not enough memory for blob at %s (need %lu); Row skipped",
+ llstr(sort_param->start_recpos,llbuff),
+ (ulong) block_info.rec_len);
+ goto try_next;
+ }
+ }
+ }
+ to= sort_param->rec_buff;
+ }
+ if (left_length < block_info.data_len || ! block_info.data_len)
+ {
+ _ma_check_print_info(param,
+ "Found block with too small length at %s; "
+ "Skipped",
+ llstr(sort_param->start_recpos,llbuff));
+ goto try_next;
+ }
+ if (block_info.filepos + block_info.data_len >
+ sort_param->read_cache.end_of_file)
+ {
+ _ma_check_print_info(param,
+ "Found block that points outside data file "
+ "at %s",
+ llstr(sort_param->start_recpos,llbuff));
+ goto try_next;
+ }
+ /*
+ Copy information that is already read. Avoid accessing data
+ below the cache start. This could happen if the header
+ streched over the end of the previous buffer contents.
+ */
+ {
+ uint header_len= (uint) (block_info.filepos - pos);
+ uint prefetch_len= (MARIA_BLOCK_INFO_HEADER_LENGTH - header_len);
+
+ if (prefetch_len > block_info.data_len)
+ prefetch_len= block_info.data_len;
+ if (prefetch_len)
+ {
+ memcpy(to, block_info.header + header_len, prefetch_len);
+ block_info.filepos+= prefetch_len;
+ block_info.data_len-= prefetch_len;
+ left_length-= prefetch_len;
+ to+= prefetch_len;
+ }
+ }
+ if (block_info.data_len &&
+ _ma_read_cache(&sort_param->read_cache,to,block_info.filepos,
+ block_info.data_len,
+ (found_record == 1 ? READING_NEXT : 0) |
+ parallel_flag))
+ {
+ _ma_check_print_info(param,
+ "Read error for block at: %s (error: %d); Skipped",
+ llstr(block_info.filepos,llbuff),my_errno);
+ goto try_next;
+ }
+ left_length-=block_info.data_len;
+ to+=block_info.data_len;
+ pos=block_info.next_filepos;
+ if (pos == HA_OFFSET_ERROR && left_length)
+ {
+ _ma_check_print_info(param,"Wrong block with wrong total length starting at %s",
+ llstr(sort_param->start_recpos,llbuff));
+ goto try_next;
+ }
+ if (pos + MARIA_BLOCK_INFO_HEADER_LENGTH > sort_param->read_cache.end_of_file)
+ {
+ _ma_check_print_info(param,"Found link that points at %s (outside data file) at %s",
+ llstr(pos,llbuff2),
+ llstr(sort_param->start_recpos,llbuff));
+ goto try_next;
+ }
+ } while (left_length);
+
+ if (_ma_rec_unpack(info,sort_param->record,sort_param->rec_buff,
+ sort_param->find_length) != MY_FILE_ERROR)
+ {
+ if (sort_param->read_cache.error < 0)
+ DBUG_RETURN(1);
+ if (sort_param->calc_checksum)
+ checksum= (share->calc_check_checksum)(info, sort_param->record);
+ if ((param->testflag & (T_EXTEND | T_REP)) || searching)
+ {
+ if (_ma_rec_check(info, sort_param->record, sort_param->rec_buff,
+ sort_param->find_length,
+ (param->testflag & T_QUICK) &&
+ sort_param->calc_checksum &&
+ test(share->calc_checksum), checksum))
+ {
+ _ma_check_print_info(param,"Found wrong packed record at %s",
+ llstr(sort_param->start_recpos,llbuff));
+ goto try_next;
+ }
+ }
+ if (sort_param->calc_checksum)
+ param->glob_crc+= checksum;
+ DBUG_RETURN(0);
+ }
+ if (!searching)
+ _ma_check_print_info(param,"Key %d - Found wrong stored record at %s",
+ sort_param->key+1,
+ llstr(sort_param->start_recpos,llbuff));
+ try_next:
+ pos=(sort_param->start_recpos+=MARIA_DYN_ALIGN_SIZE);
+ searching=1;
+ }
+ }
+ case COMPRESSED_RECORD:
+ for (searching=0 ;; searching=1, sort_param->pos++)
+ {
+ if (_ma_read_cache(&sort_param->read_cache,(uchar*) block_info.header,
+ sort_param->pos,
+ share->pack.ref_length,READING_NEXT))
+ DBUG_RETURN(-1);
+ if (searching && ! sort_param->fix_datafile)
+ {
+ param->error_printed=1;
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ DBUG_RETURN(1); /* Something wrong with data */
+ }
+ sort_param->start_recpos=sort_param->pos;
+ if (_ma_pack_get_block_info(info, &sort_param->bit_buff, &block_info,
+ &sort_param->rec_buff,
+ &sort_param->rec_buff_size, -1,
+ sort_param->pos))
+ DBUG_RETURN(-1);
+ if (!block_info.rec_len &&
+ sort_param->pos + MEMMAP_EXTRA_MARGIN ==
+ sort_param->read_cache.end_of_file)
+ DBUG_RETURN(-1);
+ if (block_info.rec_len < (uint) share->min_pack_length ||
+ block_info.rec_len > (uint) share->max_pack_length)
+ {
+ if (! searching)
+ _ma_check_print_info(param,
+ "Found block with wrong recordlength: %lu "
+ "at %s\n",
+ block_info.rec_len,
+ llstr(sort_param->pos,llbuff));
+ continue;
+ }
+ if (_ma_read_cache(&sort_param->read_cache,(uchar*) sort_param->rec_buff,
+ block_info.filepos, block_info.rec_len,
+ READING_NEXT))
+ {
+ if (! searching)
+ _ma_check_print_info(param,"Couldn't read whole record from %s",
+ llstr(sort_param->pos,llbuff));
+ continue;
+ }
+#ifdef HAVE_purify
+ bzero(sort_param->rec_buff + block_info.rec_len,
+ share->base.extra_rec_buff_size);
+#endif
+ if (_ma_pack_rec_unpack(info, &sort_param->bit_buff, sort_param->record,
+ sort_param->rec_buff, block_info.rec_len))
+ {
+ if (! searching)
+ _ma_check_print_info(param,"Found wrong record at %s",
+ llstr(sort_param->pos,llbuff));
+ continue;
+ }
+ if (!sort_param->fix_datafile)
+ {
+ sort_param->current_filepos= sort_param->pos;
+ if (sort_param->master)
+ share->state.split++;
+ }
+ sort_param->max_pos= (sort_param->pos=block_info.filepos+
+ block_info.rec_len);
+ info->packed_length=block_info.rec_len;
+
+ if (sort_param->calc_checksum)
+ {
+ info->cur_row.checksum= (*share->calc_check_checksum)(info,
+ sort_param->
+ record);
+ param->glob_crc+= info->cur_row.checksum;
+ }
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1); /* Impossible */
+}
+
+
+/**
+ @brief Write record to new file.
+
+ @fn _ma_sort_write_record()
+ @param sort_param Sort parameters.
+
+ @note
+ This is only called by a master thread if parallel repair is used.
+
+ @return
+ @retval 0 OK
+ sort_param->current_filepos points to inserted record for
+ block_records and to the place for the next record for
+ other row types.
+ sort_param->filepos points to end of file
+ @retval 1 Error
+*/
+
+int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param)
+{
+ int flag;
+ uint length;
+ ulong block_length,reclength;
+ uchar *from;
+ uchar block_buff[8];
+ MARIA_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param= sort_info->param;
+ MARIA_HA *info= sort_info->new_info;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_sort_write_record");
+
+ if (sort_param->fix_datafile)
+ {
+ sort_param->current_filepos= sort_param->filepos;
+ switch (sort_info->new_data_file_type) {
+ case BLOCK_RECORD:
+ if ((sort_param->current_filepos=
+ (*share->write_record_init)(info, sort_param->record)) ==
+ HA_OFFSET_ERROR)
+ DBUG_RETURN(1);
+ /* Pointer to end of file */
+ sort_param->filepos= share->state.state.data_file_length;
+ break;
+ case STATIC_RECORD:
+ if (my_b_write(&info->rec_cache,sort_param->record,
+ share->base.pack_reclength))
+ {
+ _ma_check_print_error(param,"%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_param->filepos+=share->base.pack_reclength;
+ share->state.split++;
+ break;
+ case DYNAMIC_RECORD:
+ if (! info->blobs)
+ from=sort_param->rec_buff;
+ else
+ {
+ /* must be sure that local buffer is big enough */
+ reclength=share->base.pack_reclength+
+ _ma_calc_total_blob_length(info,sort_param->record)+
+ ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
+ MARIA_DYN_DELETE_BLOCK_HEADER;
+ if (sort_info->buff_length < reclength)
+ {
+ if (!(sort_info->buff=my_realloc(sort_info->buff, (uint) reclength,
+ MYF(MY_FREE_ON_ERROR |
+ MY_ALLOW_ZERO_PTR))))
+ DBUG_RETURN(1);
+ sort_info->buff_length=reclength;
+ }
+ from= (uchar *) sort_info->buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER);
+ }
+ /* We can use info->checksum here as only one thread calls this */
+ info->cur_row.checksum= (*share->calc_check_checksum)(info,
+ sort_param->
+ record);
+ reclength= _ma_rec_pack(info,from,sort_param->record);
+ flag=0;
+
+ do
+ {
+ block_length=reclength+ 3 + test(reclength >= (65520-3));
+ if (block_length < share->base.min_block_length)
+ block_length=share->base.min_block_length;
+ info->update|=HA_STATE_WRITE_AT_END;
+ block_length=MY_ALIGN(block_length,MARIA_DYN_ALIGN_SIZE);
+ if (block_length > MARIA_MAX_BLOCK_LENGTH)
+ block_length=MARIA_MAX_BLOCK_LENGTH;
+ if (_ma_write_part_record(info,0L,block_length,
+ sort_param->filepos+block_length,
+ &from,&reclength,&flag))
+ {
+ _ma_check_print_error(param,"%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_param->filepos+=block_length;
+ share->state.split++;
+ } while (reclength);
+ break;
+ case COMPRESSED_RECORD:
+ reclength=info->packed_length;
+ length= _ma_save_pack_length((uint) share->pack.version, block_buff,
+ reclength);
+ if (share->base.blobs)
+ length+= _ma_save_pack_length((uint) share->pack.version,
+ block_buff + length, info->blob_length);
+ if (my_b_write(&info->rec_cache,block_buff,length) ||
+ my_b_write(&info->rec_cache,(uchar*) sort_param->rec_buff,reclength))
+ {
+ _ma_check_print_error(param,"%d when writing to datafile",my_errno);
+ DBUG_RETURN(1);
+ }
+ sort_param->filepos+=reclength+length;
+ share->state.split++;
+ break;
+ }
+ }
+ if (sort_param->master)
+ {
+ share->state.state.records++;
+ if ((param->testflag & T_WRITE_LOOP) &&
+ (share->state.state.records % WRITE_COUNT) == 0)
+ {
+ char llbuff[22];
+ printf("%s\r", llstr(share->state.state.records,llbuff));
+ VOID(fflush(stdout));
+ }
+ }
+ DBUG_RETURN(0);
+} /* _ma_sort_write_record */
+
+
+/* Compare two keys from _ma_create_index_by_sort */
+
+static int sort_key_cmp(MARIA_SORT_PARAM *sort_param, const void *a,
+ const void *b)
+{
+ uint not_used[2];
+ return (ha_key_cmp(sort_param->seg, *((uchar* const *) a),
+ *((uchar* const *) b),
+ USE_WHOLE_KEY, SEARCH_SAME, not_used));
+} /* sort_key_cmp */
+
+
+static int sort_key_write(MARIA_SORT_PARAM *sort_param, const uchar *a)
+{
+ uint diff_pos[2];
+ char llbuff[22],llbuff2[22];
+ MARIA_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param= sort_info->param;
+ int cmp;
+
+ if (sort_info->key_block->inited)
+ {
+ cmp= ha_key_cmp(sort_param->seg, (uchar*) sort_info->key_block->lastkey,
+ a, USE_WHOLE_KEY,
+ SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT,
+ diff_pos);
+ if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
+ ha_key_cmp(sort_param->seg, (uchar*) sort_info->key_block->lastkey,
+ a, USE_WHOLE_KEY,
+ SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos);
+ else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
+ {
+ diff_pos[0]= maria_collect_stats_nonulls_next(sort_param->seg,
+ sort_param->notnull,
+ sort_info->key_block->lastkey,
+ a);
+ }
+ sort_param->unique[diff_pos[0]-1]++;
+ }
+ else
+ {
+ cmp= -1;
+ if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
+ maria_collect_stats_nonulls_first(sort_param->seg, sort_param->notnull,
+ a);
+ }
+ if ((sort_param->keyinfo->flag & HA_NOSAME) && cmp == 0)
+ {
+ sort_info->dupp++;
+ sort_info->info->cur_row.lastpos= get_record_for_key(sort_param->keyinfo,
+ a);
+ _ma_check_print_warning(param,
+ "Duplicate key %2u for record at %10s against record at %10s",
+ sort_param->key + 1,
+ llstr(sort_info->info->cur_row.lastpos, llbuff),
+ llstr(get_record_for_key(sort_param->keyinfo,
+ sort_info->key_block->
+ lastkey),
+ llbuff2));
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ if (sort_info->param->testflag & T_VERBOSE)
+ _ma_print_keydata(stdout,sort_param->seg, a, USE_WHOLE_KEY);
+ return (sort_delete_record(sort_param));
+ }
+#ifndef DBUG_OFF
+ if (cmp > 0)
+ {
+ _ma_check_print_error(param,
+ "Internal error: Keys are not in order from sort");
+ return(1);
+ }
+#endif
+ return (sort_insert_key(sort_param, sort_info->key_block,
+ a, HA_OFFSET_ERROR));
+} /* sort_key_write */
+
+
+int _ma_sort_ft_buf_flush(MARIA_SORT_PARAM *sort_param)
+{
+ MARIA_SORT_INFO *sort_info=sort_param->sort_info;
+ SORT_KEY_BLOCKS *key_block=sort_info->key_block;
+ MARIA_SHARE *share=sort_info->info->s;
+ uint val_off, val_len;
+ int error;
+ SORT_FT_BUF *maria_ft_buf=sort_info->ft_buf;
+ uchar *from, *to;
+
+ val_len=share->ft2_keyinfo.keylength;
+ get_key_full_length_rdonly(val_off, maria_ft_buf->lastkey);
+ to= maria_ft_buf->lastkey+val_off;
+
+ if (maria_ft_buf->buf)
+ {
+ /* flushing first-level tree */
+ error= sort_insert_key(sort_param,key_block,maria_ft_buf->lastkey,
+ HA_OFFSET_ERROR);
+ for (from=to+val_len;
+ !error && from < maria_ft_buf->buf;
+ from+= val_len)
+ {
+ memcpy(to, from, val_len);
+ error= sort_insert_key(sort_param,key_block,maria_ft_buf->lastkey,
+ HA_OFFSET_ERROR);
+ }
+ return error;
+ }
+ /* flushing second-level tree keyblocks */
+ error=_ma_flush_pending_blocks(sort_param);
+ /* updating lastkey with second-level tree info */
+ ft_intXstore(maria_ft_buf->lastkey+val_off, -maria_ft_buf->count);
+ _ma_dpointer(sort_info->info->s, maria_ft_buf->lastkey+val_off+HA_FT_WLEN,
+ share->state.key_root[sort_param->key]);
+ /* restoring first level tree data in sort_info/sort_param */
+ sort_info->key_block=sort_info->key_block_end- sort_info->param->sort_key_blocks;
+ sort_param->keyinfo=share->keyinfo+sort_param->key;
+ share->state.key_root[sort_param->key]=HA_OFFSET_ERROR;
+ /* writing lastkey in first-level tree */
+ return error ? error :
+ sort_insert_key(sort_param,sort_info->key_block,
+ maria_ft_buf->lastkey,HA_OFFSET_ERROR);
+}
+
+
+static int sort_maria_ft_key_write(MARIA_SORT_PARAM *sort_param,
+ const uchar *a)
+{
+ uint a_len, val_off, val_len, error;
+ MARIA_SORT_INFO *sort_info= sort_param->sort_info;
+ SORT_FT_BUF *ft_buf= sort_info->ft_buf;
+ SORT_KEY_BLOCKS *key_block= sort_info->key_block;
+ MARIA_SHARE *share= sort_info->info->s;
+
+ val_len=HA_FT_WLEN+share->base.rec_reflength;
+ get_key_full_length_rdonly(a_len, a);
+
+ if (!ft_buf)
+ {
+ /*
+ use two-level tree only if key_reflength fits in rec_reflength place
+ and row format is NOT static - for _ma_dpointer not to garble offsets
+ */
+ if ((share->base.key_reflength <=
+ share->base.rec_reflength) &&
+ (share->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)))
+ ft_buf= (SORT_FT_BUF *)my_malloc(sort_param->keyinfo->block_length +
+ sizeof(SORT_FT_BUF), MYF(MY_WME));
+
+ if (!ft_buf)
+ {
+ sort_param->key_write=sort_key_write;
+ return sort_key_write(sort_param, a);
+ }
+ sort_info->ft_buf= ft_buf;
+ goto word_init_ft_buf; /* no need to duplicate the code */
+ }
+ get_key_full_length_rdonly(val_off, ft_buf->lastkey);
+
+ if (ha_compare_text(sort_param->seg->charset,
+ a+1,a_len-1,
+ (uchar*) ft_buf->lastkey+1,val_off-1, 0, 0)==0)
+ {
+ uchar *p;
+ if (!ft_buf->buf) /* store in second-level tree */
+ {
+ ft_buf->count++;
+ return sort_insert_key(sort_param,key_block,
+ a + a_len, HA_OFFSET_ERROR);
+ }
+
+ /* storing the key in the buffer. */
+ memcpy (ft_buf->buf, (const char *)a+a_len, val_len);
+ ft_buf->buf+=val_len;
+ if (ft_buf->buf < ft_buf->end)
+ return 0;
+
+ /* converting to two-level tree */
+ p=ft_buf->lastkey+val_off;
+
+ while (key_block->inited)
+ key_block++;
+ sort_info->key_block=key_block;
+ sort_param->keyinfo= &share->ft2_keyinfo;
+ ft_buf->count=(ft_buf->buf - p)/val_len;
+
+ /* flushing buffer to second-level tree */
+ for (error=0; !error && p < ft_buf->buf; p+= val_len)
+ error=sort_insert_key(sort_param,key_block,p,HA_OFFSET_ERROR);
+ ft_buf->buf=0;
+ return error;
+ }
+
+ /* flushing buffer */
+ if ((error=_ma_sort_ft_buf_flush(sort_param)))
+ return error;
+
+word_init_ft_buf:
+ a_len+=val_len;
+ memcpy(ft_buf->lastkey, a, a_len);
+ ft_buf->buf=ft_buf->lastkey+a_len;
+ /*
+ 32 is just a safety margin here
+ (at least max(val_len, sizeof(nod_flag)) should be there).
+ May be better performance could be achieved if we'd put
+ (sort_info->keyinfo->block_length-32)/XXX
+ instead.
+ TODO: benchmark the best value for XXX.
+ */
+ ft_buf->end= ft_buf->lastkey+ (sort_param->keyinfo->block_length-32);
+ return 0;
+} /* sort_maria_ft_key_write */
+
+
+/* get pointer to record from a key */
+
+static my_off_t get_record_for_key(MARIA_KEYDEF *keyinfo,
+ const uchar *key_data)
+{
+ MARIA_KEY key;
+ key.keyinfo= keyinfo;
+ key.data= (uchar*) key_data;
+ key.data_length= _ma_keylength(keyinfo, key_data);
+ return _ma_row_pos_from_key(&key);
+} /* get_record_for_key */
+
+
+ /* Insert a key in sort-key-blocks */
+
+static int sort_insert_key(MARIA_SORT_PARAM *sort_param,
+ register SORT_KEY_BLOCKS *key_block,
+ const uchar *key,
+ my_off_t prev_block)
+{
+ uint a_length,t_length,nod_flag;
+ my_off_t filepos,key_file_length;
+ uchar *anc_buff,*lastkey;
+ MARIA_KEY_PARAM s_temp;
+ MARIA_KEYDEF *keyinfo=sort_param->keyinfo;
+ MARIA_SORT_INFO *sort_info= sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
+ MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
+ MARIA_KEY tmp_key;
+ MARIA_HA *info= sort_info->info;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("sort_insert_key");
+
+ anc_buff= key_block->buff;
+ lastkey=key_block->lastkey;
+ nod_flag= (key_block == sort_info->key_block ? 0 :
+ share->base.key_reflength);
+
+ if (!key_block->inited)
+ {
+ key_block->inited=1;
+ if (key_block == sort_info->key_block_end)
+ {
+ _ma_check_print_error(param,"To many key-block-levels; Try increasing sort_key_blocks");
+ DBUG_RETURN(1);
+ }
+ a_length= share->keypage_header + nod_flag;
+ key_block->end_pos= anc_buff + share->keypage_header;
+ bzero(anc_buff, share->keypage_header);
+ _ma_store_keynr(share, anc_buff, (uint) (sort_param->keyinfo -
+ share->keyinfo));
+ lastkey=0; /* No previous key in block */
+ }
+ else
+ a_length= _ma_get_page_used(share, anc_buff);
+
+ /* Save pointer to previous block */
+ if (nod_flag)
+ {
+ _ma_store_keypage_flag(share, anc_buff, KEYPAGE_FLAG_ISNOD);
+ _ma_kpointer(info,key_block->end_pos,prev_block);
+ }
+
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= (uchar*) key;
+ tmp_key.data_length= _ma_keylength(keyinfo, key) - share->base.rec_reflength;
+ tmp_key.ref_length= share->base.rec_reflength;
+
+ t_length= (*keyinfo->pack_key)(&tmp_key, nod_flag,
+ (uchar*) 0, lastkey, lastkey, &s_temp);
+ (*keyinfo->store_key)(keyinfo, key_block->end_pos+nod_flag,&s_temp);
+ a_length+=t_length;
+ _ma_store_page_used(share, anc_buff, a_length);
+ key_block->end_pos+=t_length;
+ if (a_length <= (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
+ {
+ MARIA_KEY tmp_key2;
+ tmp_key2.data= key_block->lastkey;
+ _ma_copy_key(&tmp_key2, &tmp_key);
+ key_block->last_length=a_length-t_length;
+ DBUG_RETURN(0);
+ }
+
+ /* Fill block with end-zero and write filled block */
+ _ma_store_page_used(share, anc_buff, key_block->last_length);
+ bzero(anc_buff+key_block->last_length,
+ keyinfo->block_length- key_block->last_length);
+ key_file_length=share->state.state.key_file_length;
+ if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) == HA_OFFSET_ERROR)
+ DBUG_RETURN(1);
+ _ma_fast_unlock_key_del(info);
+
+ /* If we read the page from the key cache, we have to write it back to it */
+ if (page_link->changed)
+ {
+ pop_dynamic(&info->pinned_pages);
+ if (_ma_write_keypage(info, keyinfo, filepos,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ DFLT_INIT_HITS, anc_buff))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ put_crc(anc_buff, filepos, share);
+ if (my_pwrite(share->kfile.file, anc_buff,
+ (uint) keyinfo->block_length, filepos, param->myf_rw))
+ DBUG_RETURN(1);
+ }
+ DBUG_DUMP("buff", anc_buff, _ma_get_page_used(share, anc_buff));
+
+ /* Write separator-key to block in next level */
+ if (sort_insert_key(sort_param,key_block+1,key_block->lastkey,filepos))
+ DBUG_RETURN(1);
+
+ /* clear old block and write new key in it */
+ key_block->inited=0;
+ DBUG_RETURN(sort_insert_key(sort_param, key_block,key,prev_block));
+} /* sort_insert_key */
+
+
+/* Delete record when we found a duplicated key */
+
+static int sort_delete_record(MARIA_SORT_PARAM *sort_param)
+{
+ uint i;
+ int old_file,error;
+ uchar *key;
+ MARIA_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
+ MARIA_HA *row_info= sort_info->new_info, *key_info= sort_info->info;
+ DBUG_ENTER("sort_delete_record");
+
+ if ((param->testflag & (T_FORCE_UNIQUENESS|T_QUICK)) == T_QUICK)
+ {
+ _ma_check_print_error(param,
+ "Quick-recover aborted; Run recovery without switch -q or with "
+ "switch -qq");
+ DBUG_RETURN(1);
+ }
+ if (key_info->s->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ _ma_check_print_error(param,
+ "Recover aborted; Can't run standard recovery on "
+ "compressed tables with errors in data-file. "
+ "Use 'maria_chk --safe-recover' to fix it");
+ DBUG_RETURN(1);
+ }
+
+ old_file= row_info->dfile.file;
+ /* This only affects static and dynamic row formats */
+ row_info->dfile.file= row_info->rec_cache.file;
+ if (flush_io_cache(&row_info->rec_cache))
+ DBUG_RETURN(1);
+
+ key= key_info->lastkey_buff + key_info->s->base.max_key_length;
+ if ((error=(*row_info->s->read_record)(row_info, sort_param->record,
+ key_info->cur_row.lastpos)) &&
+ error != HA_ERR_RECORD_DELETED)
+ {
+ _ma_check_print_error(param,"Can't read record to be removed");
+ row_info->dfile.file= old_file;
+ DBUG_RETURN(1);
+ }
+ row_info->cur_row.lastpos= key_info->cur_row.lastpos;
+
+ for (i=0 ; i < sort_info->current_key ; i++)
+ {
+ MARIA_KEY tmp_key;
+ (*key_info->s->keyinfo[i].make_key)(key_info, &tmp_key, i, key,
+ sort_param->record,
+ key_info->cur_row.lastpos, 0);
+ if (_ma_ck_delete(key_info, &tmp_key))
+ {
+ _ma_check_print_error(param,
+ "Can't delete key %d from record to be removed",
+ i+1);
+ row_info->dfile.file= old_file;
+ DBUG_RETURN(1);
+ }
+ }
+ if (sort_param->calc_checksum)
+ param->glob_crc-=(*key_info->s->calc_check_checksum)(key_info,
+ sort_param->record);
+ error= (*row_info->s->delete_record)(row_info, sort_param->record);
+ if (error)
+ _ma_check_print_error(param,"Got error %d when deleting record",
+ my_errno);
+ row_info->dfile.file= old_file; /* restore actual value */
+ row_info->s->state.state.records--;
+ DBUG_RETURN(error);
+} /* sort_delete_record */
+
+
+/* Fix all pending blocks and flush everything to disk */
+
+int _ma_flush_pending_blocks(MARIA_SORT_PARAM *sort_param)
+{
+ uint nod_flag,length;
+ my_off_t filepos,key_file_length;
+ SORT_KEY_BLOCKS *key_block;
+ MARIA_SORT_INFO *sort_info= sort_param->sort_info;
+ myf myf_rw=sort_info->param->myf_rw;
+ MARIA_HA *info=sort_info->info;
+ MARIA_KEYDEF *keyinfo=sort_param->keyinfo;
+ MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
+ DBUG_ENTER("_ma_flush_pending_blocks");
+
+ filepos= HA_OFFSET_ERROR; /* if empty file */
+ nod_flag=0;
+ for (key_block=sort_info->key_block ; key_block->inited ; key_block++)
+ {
+ key_block->inited=0;
+ length= _ma_get_page_used(info->s, key_block->buff);
+ if (nod_flag)
+ _ma_kpointer(info,key_block->end_pos,filepos);
+ key_file_length= info->s->state.state.key_file_length;
+ bzero(key_block->buff+length, keyinfo->block_length-length);
+ if ((filepos= _ma_new(info, DFLT_INIT_HITS, &page_link)) ==
+ HA_OFFSET_ERROR)
+ goto err;
+
+ /* If we read the page from the key cache, we have to write it back */
+ if (page_link->changed)
+ {
+ pop_dynamic(&info->pinned_pages);
+ if (_ma_write_keypage(info, keyinfo, filepos,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ DFLT_INIT_HITS, key_block->buff))
+ goto err;
+ }
+ else
+ {
+ put_crc(key_block->buff, filepos, info->s);
+ if (my_pwrite(info->s->kfile.file, key_block->buff,
+ (uint) keyinfo->block_length,filepos, myf_rw))
+ goto err;
+ }
+ DBUG_DUMP("buff",key_block->buff,length);
+ nod_flag=1;
+ }
+ info->s->state.key_root[sort_param->key]=filepos; /* Last is root for tree */
+ _ma_fast_unlock_key_del(info);
+ DBUG_RETURN(0);
+
+err:
+ _ma_fast_unlock_key_del(info);
+ DBUG_RETURN(1);
+} /* _ma_flush_pending_blocks */
+
+ /* alloc space and pointers for key_blocks */
+
+static SORT_KEY_BLOCKS *alloc_key_blocks(HA_CHECK *param, uint blocks,
+ uint buffer_length)
+{
+ reg1 uint i;
+ SORT_KEY_BLOCKS *block;
+ DBUG_ENTER("alloc_key_blocks");
+
+ if (!(block= (SORT_KEY_BLOCKS*) my_malloc((sizeof(SORT_KEY_BLOCKS)+
+ buffer_length+IO_SIZE)*blocks,
+ MYF(0))))
+ {
+ _ma_check_print_error(param,"Not enough memory for sort-key-blocks");
+ return(0);
+ }
+ for (i=0 ; i < blocks ; i++)
+ {
+ block[i].inited=0;
+ block[i].buff= (uchar*) (block+blocks)+(buffer_length+IO_SIZE)*i;
+ }
+ DBUG_RETURN(block);
+} /* alloc_key_blocks */
+
+
+ /* Check if file is almost full */
+
+int maria_test_if_almost_full(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ return 0;
+ return my_seek(share->kfile.file, 0L, MY_SEEK_END,
+ MYF(MY_THREADSAFE))/10*9 >
+ (my_off_t) share->base.max_key_file_length ||
+ my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0)) / 10 * 9 >
+ (my_off_t) share->base.max_data_file_length;
+}
+
+
+/* Recreate table with bigger more alloced record-data */
+
+int maria_recreate_table(HA_CHECK *param, MARIA_HA **org_info, char *filename)
+{
+ int error;
+ MARIA_HA info;
+ MARIA_SHARE share;
+ MARIA_KEYDEF *keyinfo,*key,*key_end;
+ HA_KEYSEG *keysegs,*keyseg;
+ MARIA_COLUMNDEF *columndef,*column,*end;
+ MARIA_UNIQUEDEF *uniquedef,*u_ptr,*u_end;
+ MARIA_STATUS_INFO status_info;
+ uint unpack,key_parts;
+ ha_rows max_records;
+ ulonglong file_length,tmp_length;
+ MARIA_CREATE_INFO create_info;
+ DBUG_ENTER("maria_recreate_table");
+
+ error=1; /* Default error */
+ info= **org_info;
+ status_info= (*org_info)->state[0];
+ info.state= &status_info;
+ share= *(*org_info)->s;
+ unpack= ((share.data_file_type == COMPRESSED_RECORD) &&
+ (param->testflag & T_UNPACK));
+ if (!(keyinfo=(MARIA_KEYDEF*) my_alloca(sizeof(MARIA_KEYDEF) *
+ share.base.keys)))
+ DBUG_RETURN(0);
+ memcpy((uchar*) keyinfo,(uchar*) share.keyinfo,
+ (size_t) (sizeof(MARIA_KEYDEF)*share.base.keys));
+
+ key_parts= share.base.all_key_parts;
+ if (!(keysegs=(HA_KEYSEG*) my_alloca(sizeof(HA_KEYSEG)*
+ (key_parts+share.base.keys))))
+ {
+ my_afree((uchar*) keyinfo);
+ DBUG_RETURN(1);
+ }
+ if (!(columndef=(MARIA_COLUMNDEF*)
+ my_alloca(sizeof(MARIA_COLUMNDEF)*(share.base.fields+1))))
+ {
+ my_afree((uchar*) keyinfo);
+ my_afree((uchar*) keysegs);
+ DBUG_RETURN(1);
+ }
+ if (!(uniquedef=(MARIA_UNIQUEDEF*)
+ my_alloca(sizeof(MARIA_UNIQUEDEF)*(share.state.header.uniques+1))))
+ {
+ my_afree((uchar*) columndef);
+ my_afree((uchar*) keyinfo);
+ my_afree((uchar*) keysegs);
+ DBUG_RETURN(1);
+ }
+
+ /* Copy the column definitions in their original order */
+ for (column= share.columndef, end= share.columndef+share.base.fields;
+ column != end ;
+ column++)
+ columndef[column->column_nr]= *column;
+
+ /* Change the new key to point at the saved key segments */
+ memcpy((uchar*) keysegs,(uchar*) share.keyparts,
+ (size_t) (sizeof(HA_KEYSEG)*(key_parts+share.base.keys+
+ share.state.header.uniques)));
+ keyseg=keysegs;
+ for (key=keyinfo,key_end=keyinfo+share.base.keys; key != key_end ; key++)
+ {
+ key->seg=keyseg;
+ for (; keyseg->type ; keyseg++)
+ {
+ if (param->language)
+ keyseg->language=param->language; /* change language */
+ }
+ keyseg++; /* Skip end pointer */
+ }
+
+ /*
+ Copy the unique definitions and change them to point at the new key
+ segments
+ */
+ memcpy((uchar*) uniquedef,(uchar*) share.uniqueinfo,
+ (size_t) (sizeof(MARIA_UNIQUEDEF)*(share.state.header.uniques)));
+ for (u_ptr=uniquedef,u_end=uniquedef+share.state.header.uniques;
+ u_ptr != u_end ; u_ptr++)
+ {
+ u_ptr->seg=keyseg;
+ keyseg+=u_ptr->keysegs+1;
+ }
+
+ file_length=(ulonglong) my_seek(info.dfile.file, 0L, MY_SEEK_END, MYF(0));
+ if (share.options & HA_OPTION_COMPRESS_RECORD)
+ share.base.records=max_records=info.state->records;
+ else if (share.base.min_pack_length)
+ max_records=(ha_rows) (file_length / share.base.min_pack_length);
+ else
+ max_records=0;
+ share.options&= ~HA_OPTION_TEMP_COMPRESS_RECORD;
+
+ tmp_length= file_length+file_length/10;
+ set_if_bigger(file_length,param->max_data_file_length);
+ set_if_bigger(file_length,tmp_length);
+ set_if_bigger(file_length,(ulonglong) share.base.max_data_file_length);
+
+ VOID(maria_close(*org_info));
+
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.max_rows=max(max_records,share.base.records);
+ create_info.reloc_rows=share.base.reloc;
+ create_info.old_options=(share.options |
+ (unpack ? HA_OPTION_TEMP_COMPRESS_RECORD : 0));
+
+ create_info.data_file_length=file_length;
+ create_info.auto_increment=share.state.auto_increment;
+ create_info.language = (param->language ? param->language :
+ share.state.header.language);
+ create_info.key_file_length= status_info.key_file_length;
+ create_info.org_data_file_type= ((enum data_file_type)
+ share.state.header.org_data_file_type);
+
+ /*
+ Allow for creating an auto_increment key. This has an effect only if
+ an auto_increment key exists in the original table.
+ */
+ create_info.with_auto_increment= TRUE;
+ create_info.null_bytes= share.base.null_bytes;
+ create_info.transactional= share.base.born_transactional;
+
+ /*
+ We don't have to handle symlinks here because we are using
+ HA_DONT_TOUCH_DATA
+ */
+ if (maria_create(filename, share.data_file_type,
+ share.base.keys - share.state.header.uniques,
+ keyinfo, share.base.fields, columndef,
+ share.state.header.uniques, uniquedef,
+ &create_info,
+ HA_DONT_TOUCH_DATA))
+ {
+ _ma_check_print_error(param,
+ "Got error %d when trying to recreate indexfile",
+ my_errno);
+ goto end;
+ }
+ *org_info= maria_open(filename,O_RDWR,
+ (HA_OPEN_FOR_REPAIR |
+ ((param->testflag & T_WAIT_FOREVER) ?
+ HA_OPEN_WAIT_IF_LOCKED :
+ (param->testflag & T_DESCRIPT) ?
+ HA_OPEN_IGNORE_IF_LOCKED :
+ HA_OPEN_ABORT_IF_LOCKED)));
+ if (!*org_info)
+ {
+ _ma_check_print_error(param,
+ "Got error %d when trying to open re-created indexfile",
+ my_errno);
+ goto end;
+ }
+ /* We are modifing */
+ (*org_info)->s->options&= ~HA_OPTION_READ_ONLY_DATA;
+ VOID(_ma_readinfo(*org_info,F_WRLCK,0));
+ (*org_info)->s->state.state.records= info.state->records;
+ if (share.state.create_time)
+ (*org_info)->s->state.create_time=share.state.create_time;
+#ifdef EXTERNAL_LOCKING
+ (*org_info)->s->state.unique= (*org_info)->this_unique= share.state.unique;
+#endif
+ (*org_info)->s->state.state.checksum= info.state->checksum;
+ (*org_info)->s->state.state.del= info.state->del;
+ (*org_info)->s->state.dellink= share.state.dellink;
+ (*org_info)->s->state.state.empty= info.state->empty;
+ (*org_info)->s->state.state.data_file_length= info.state->data_file_length;
+ *(*org_info)->state= (*org_info)->s->state.state;
+ if (maria_update_state_info(param,*org_info,UPDATE_TIME | UPDATE_STAT |
+ UPDATE_OPEN_COUNT))
+ goto end;
+ error=0;
+end:
+ my_afree((uchar*) uniquedef);
+ my_afree((uchar*) keyinfo);
+ my_afree((uchar*) columndef);
+ my_afree((uchar*) keysegs);
+ DBUG_RETURN(error);
+}
+
+
+ /* write suffix to data file if neaded */
+
+int maria_write_data_suffix(MARIA_SORT_INFO *sort_info, my_bool fix_datafile)
+{
+ MARIA_HA *info=sort_info->new_info;
+
+ if (info->s->data_file_type == COMPRESSED_RECORD && fix_datafile)
+ {
+ uchar buff[MEMMAP_EXTRA_MARGIN];
+ bzero(buff,sizeof(buff));
+ if (my_b_write(&info->rec_cache,buff,sizeof(buff)))
+ {
+ _ma_check_print_error(sort_info->param,
+ "%d when writing to datafile",my_errno);
+ return 1;
+ }
+ sort_info->param->read_cache.end_of_file+=sizeof(buff);
+ }
+ return 0;
+}
+
+
+/* Update state and maria_chk time of indexfile */
+
+int maria_update_state_info(HA_CHECK *param, MARIA_HA *info,uint update)
+{
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_update_state_info");
+
+ if (update & UPDATE_OPEN_COUNT)
+ {
+ share->state.open_count=0;
+ share->global_changed=0;
+ }
+ if (update & UPDATE_STAT)
+ {
+ uint i, key_parts= mi_uint2korr(share->state.header.key_parts);
+ share->state.records_at_analyze= share->state.state.records;
+ share->state.changed&= ~STATE_NOT_ANALYZED;
+ if (share->state.state.records)
+ {
+ for (i=0; i<key_parts; i++)
+ {
+ if (!(share->state.rec_per_key_part[i]=param->new_rec_per_key_part[i]))
+ share->state.changed|= STATE_NOT_ANALYZED;
+ }
+ }
+ }
+ if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME | UPDATE_AUTO_INC))
+ {
+ if (update & UPDATE_TIME)
+ {
+ share->state.check_time= (long) time((time_t*) 0);
+ if (!share->state.create_time)
+ share->state.create_time= share->state.check_time;
+ }
+ if (_ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO))
+ goto err;
+ share->changed=0;
+ }
+ { /* Force update of status */
+ int error;
+ uint r_locks=share->r_locks,w_locks=share->w_locks;
+ share->r_locks= share->w_locks= share->tot_locks= 0;
+ error= _ma_writeinfo(info,WRITEINFO_NO_UNLOCK);
+ share->r_locks=r_locks;
+ share->w_locks=w_locks;
+ share->tot_locks=r_locks+w_locks;
+ if (!error)
+ DBUG_RETURN(0);
+ }
+err:
+ _ma_check_print_error(param,"%d when updating keyfile",my_errno);
+ DBUG_RETURN(1);
+}
+
+/*
+ Update auto increment value for a table
+ When setting the 'repair_only' flag we only want to change the
+ old auto_increment value if its wrong (smaller than some given key).
+ The reason is that we shouldn't change the auto_increment value
+ for a table without good reason when only doing a repair; If the
+ user have inserted and deleted rows, the auto_increment value
+ may be bigger than the biggest current row and this is ok.
+
+ If repair_only is not set, we will update the flag to the value in
+ param->auto_increment is bigger than the biggest key.
+*/
+
+void _ma_update_auto_increment_key(HA_CHECK *param, MARIA_HA *info,
+ my_bool repair_only)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *record;
+ DBUG_ENTER("update_auto_increment_key");
+
+ if (!share->base.auto_key ||
+ ! maria_is_key_active(share->state.key_map, share->base.auto_key - 1))
+ {
+ if (!(param->testflag & T_VERY_SILENT))
+ _ma_check_print_info(param,
+ "Table: %s doesn't have an auto increment key\n",
+ param->isam_file_name);
+ DBUG_VOID_RETURN;
+ }
+ if (!(param->testflag & T_SILENT) &&
+ !(param->testflag & T_REP))
+ printf("Updating MARIA file: %s\n", param->isam_file_name);
+ /*
+ We have to use an allocated buffer instead of info->rec_buff as
+ _ma_put_key_in_record() may use info->rec_buff
+ */
+ if (!(record= (uchar*) my_malloc((size_t) share->base.default_rec_buff_size,
+ MYF(0))))
+ {
+ _ma_check_print_error(param,"Not enough memory for extra record");
+ DBUG_VOID_RETURN;
+ }
+
+ maria_extra(info,HA_EXTRA_KEYREAD,0);
+ if (maria_rlast(info, record, share->base.auto_key-1))
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ maria_extra(info,HA_EXTRA_NO_KEYREAD,0);
+ my_free((char*) record, MYF(0));
+ _ma_check_print_error(param,"%d when reading last record",my_errno);
+ DBUG_VOID_RETURN;
+ }
+ if (!repair_only)
+ share->state.auto_increment=param->auto_increment_value;
+ }
+ else
+ {
+ const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
+ ulonglong auto_increment=
+ ma_retrieve_auto_increment(record + keyseg->start, keyseg->type);
+ set_if_bigger(share->state.auto_increment,auto_increment);
+ if (!repair_only)
+ set_if_bigger(share->state.auto_increment, param->auto_increment_value);
+ }
+ maria_extra(info,HA_EXTRA_NO_KEYREAD,0);
+ my_free((char*) record, MYF(0));
+ maria_update_state_info(param, info, UPDATE_AUTO_INC);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Update statistics for each part of an index
+
+ SYNOPSIS
+ maria_update_key_parts()
+ keyinfo IN Index information (only key->keysegs used)
+ rec_per_key_part OUT Store statistics here
+ unique IN Array of (#distinct tuples)
+ notnull_tuples IN Array of (#tuples), or NULL
+ records Number of records in the table
+
+ DESCRIPTION
+ This function is called produce index statistics values from unique and
+ notnull_tuples arrays after these arrays were produced with sequential
+ index scan (the scan is done in two places: chk_index() and
+ sort_key_write()).
+
+ This function handles all 3 index statistics collection methods.
+
+ Unique is an array:
+ unique[0]= (#different values of {keypart1}) - 1
+ unique[1]= (#different values of {keypart1,keypart2} tuple)-unique[0]-1
+ ...
+
+ For MI_STATS_METHOD_IGNORE_NULLS method, notnull_tuples is an array too:
+ notnull_tuples[0]= (#of {keypart1} tuples such that keypart1 is not NULL)
+ notnull_tuples[1]= (#of {keypart1,keypart2} tuples such that all
+ keypart{i} are not NULL)
+ ...
+ For all other statistics collection methods notnull_tuples==NULL.
+
+ Output is an array:
+ rec_per_key_part[k] =
+ = E(#records in the table such that keypart_1=c_1 AND ... AND
+ keypart_k=c_k for arbitrary constants c_1 ... c_k)
+
+ = {assuming that values have uniform distribution and index contains all
+ tuples from the domain (or that {c_1, ..., c_k} tuple is choosen from
+ index tuples}
+
+ = #tuples-in-the-index / #distinct-tuples-in-the-index.
+
+ The #tuples-in-the-index and #distinct-tuples-in-the-index have different
+ meaning depending on which statistics collection method is used:
+
+ MI_STATS_METHOD_* how are nulls compared? which tuples are counted?
+ NULLS_EQUAL NULL == NULL all tuples in table
+ NULLS_NOT_EQUAL NULL != NULL all tuples in table
+ IGNORE_NULLS n/a tuples that don't have NULLs
+*/
+
+void maria_update_key_parts(MARIA_KEYDEF *keyinfo, double *rec_per_key_part,
+ ulonglong *unique, ulonglong *notnull,
+ ulonglong records)
+{
+ ulonglong count=0, unique_tuples;
+ ulonglong tuples= records;
+ uint parts;
+ double tmp;
+ for (parts=0 ; parts < keyinfo->keysegs ; parts++)
+ {
+ count+=unique[parts];
+ unique_tuples= count + 1;
+ if (notnull)
+ {
+ tuples= notnull[parts];
+ /*
+ #(unique_tuples not counting tuples with NULLs) =
+ #(unique_tuples counting tuples with NULLs as different) -
+ #(tuples with NULLs)
+ */
+ unique_tuples -= (records - notnull[parts]);
+ }
+
+ if (unique_tuples == 0)
+ tmp= 1;
+ else if (count == 0)
+ tmp= ulonglong2double(tuples); /* 1 unique tuple */
+ else
+ tmp= ulonglong2double(tuples) / ulonglong2double(unique_tuples);
+
+ /*
+ for some weird keys (e.g. FULLTEXT) tmp can be <1 here.
+ let's ensure it is not
+ */
+ set_if_bigger(tmp,1);
+
+ *rec_per_key_part++= tmp;
+ }
+}
+
+
+static ha_checksum maria_byte_checksum(const uchar *buf, uint length)
+{
+ ha_checksum crc;
+ const uchar *end=buf+length;
+ for (crc=0; buf != end; buf++)
+ crc=((crc << 1) + *buf) +
+ test(crc & (((ha_checksum) 1) << (8*sizeof(ha_checksum)-1)));
+ return crc;
+}
+
+static my_bool maria_too_big_key_for_sort(MARIA_KEYDEF *key, ha_rows rows)
+{
+ uint key_maxlength=key->maxlength;
+ if (key->flag & HA_FULLTEXT)
+ {
+ uint ft_max_word_len_for_sort=FT_MAX_WORD_LEN_FOR_SORT*
+ key->seg->charset->mbmaxlen;
+ key_maxlength+=ft_max_word_len_for_sort-HA_FT_MAXBYTELEN;
+ }
+ return (key->flag & HA_SPATIAL) ||
+ (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY | HA_FULLTEXT) &&
+ ((ulonglong) rows * key_maxlength >
+ (ulonglong) maria_max_temp_length));
+}
+
+/*
+ Deactivate all not unique index that can be recreated fast
+ These include packed keys on which sorting will use more temporary
+ space than the max allowed file length or for which the unpacked keys
+ will take much more space than packed keys.
+ Note that 'rows' may be zero for the case when we don't know how many
+ rows we will put into the file.
+ */
+
+void maria_disable_non_unique_index(MARIA_HA *info, ha_rows rows)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *key=share->keyinfo;
+ uint i;
+
+ DBUG_ASSERT(share->state.state.records == 0 &&
+ (!rows || rows >= MARIA_MIN_ROWS_TO_DISABLE_INDEXES));
+ for (i=0 ; i < share->base.keys ; i++,key++)
+ {
+ if (!(key->flag &
+ (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY | HA_RTREE_INDEX)) &&
+ ! maria_too_big_key_for_sort(key,rows) && share->base.auto_key != i+1)
+ {
+ maria_clear_key_active(share->state.key_map, i);
+ info->update|= HA_STATE_CHANGED;
+ }
+ }
+}
+
+
+/*
+ Return TRUE if we can use repair by sorting
+ One can set the force argument to force to use sorting
+ even if the temporary file would be quite big!
+*/
+
+my_bool maria_test_if_sort_rep(MARIA_HA *info, ha_rows rows,
+ ulonglong key_map, my_bool force)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *key=share->keyinfo;
+ uint i;
+
+ /*
+ maria_repair_by_sort only works if we have at least one key. If we don't
+ have any keys, we should use the normal repair.
+ */
+ if (! maria_is_any_key_active(key_map))
+ return FALSE; /* Can't use sort */
+ for (i=0 ; i < share->base.keys ; i++,key++)
+ {
+ if (!force && maria_too_big_key_for_sort(key,rows))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ @brief Create a new handle for manipulation the new record file
+
+ @note
+ It's ok for Recovery to have two MARIA_SHARE on the same index file
+ because the one we create here is not transactional
+*/
+
+static my_bool create_new_data_handle(MARIA_SORT_PARAM *param, File new_file)
+{
+
+ MARIA_SORT_INFO *sort_info= param->sort_info;
+ MARIA_HA *info= sort_info->info;
+ MARIA_HA *new_info;
+ DBUG_ENTER("create_new_data_handle");
+
+ if (!(sort_info->new_info= maria_open(info->s->open_file_name.str, O_RDWR,
+ HA_OPEN_COPY | HA_OPEN_FOR_REPAIR)))
+ DBUG_RETURN(1);
+
+ new_info= sort_info->new_info;
+ _ma_bitmap_set_pagecache_callbacks(&new_info->s->bitmap.file,
+ new_info->s);
+ _ma_set_data_pagecache_callbacks(&new_info->dfile, new_info->s);
+ change_data_file_descriptor(new_info, new_file);
+ maria_lock_database(new_info, F_EXTRA_LCK);
+ if ((sort_info->param->testflag & T_UNPACK) &&
+ info->s->data_file_type == COMPRESSED_RECORD)
+ {
+ (*new_info->s->once_end)(new_info->s);
+ (*new_info->s->end)(new_info);
+ restore_data_file_type(new_info->s);
+ _ma_setup_functions(new_info->s);
+ if ((*new_info->s->once_init)(new_info->s, new_file) ||
+ (*new_info->s->init)(new_info))
+ DBUG_RETURN(1);
+ }
+ _ma_reset_status(new_info);
+ if (_ma_initialize_data_file(new_info->s, new_file))
+ DBUG_RETURN(1);
+
+ /* Take into account any bitmap page created above: */
+ param->filepos= new_info->s->state.state.data_file_length;
+
+ /* Use new virtual functions for key generation */
+ info->s->keypos_to_recpos= new_info->s->keypos_to_recpos;
+ info->s->recpos_to_keypos= new_info->s->recpos_to_keypos;
+ DBUG_RETURN(0);
+}
+
+
+static void
+set_data_file_type(MARIA_SORT_INFO *sort_info, MARIA_SHARE *share)
+{
+ if ((sort_info->new_data_file_type=share->data_file_type) ==
+ COMPRESSED_RECORD && sort_info->param->testflag & T_UNPACK)
+ {
+ MARIA_SHARE tmp;
+ sort_info->new_data_file_type= share->state.header.org_data_file_type;
+ /* Set delete_function for sort_delete_record() */
+ tmp= *share;
+ tmp.state.header.data_file_type= tmp.state.header.org_data_file_type;
+ tmp.options= ~HA_OPTION_COMPRESS_RECORD;
+ _ma_setup_functions(&tmp);
+ share->delete_record=tmp.delete_record;
+ }
+}
+
+static void restore_data_file_type(MARIA_SHARE *share)
+{
+ MARIA_SHARE tmp_share;
+ share->options&= ~HA_OPTION_COMPRESS_RECORD;
+ mi_int2store(share->state.header.options,share->options);
+ share->state.header.data_file_type=
+ share->state.header.org_data_file_type;
+ share->data_file_type= share->state.header.data_file_type;
+ share->pack.header_length= 0;
+
+ /* Use new virtual functions for key generation */
+ tmp_share= *share;
+ _ma_setup_functions(&tmp_share);
+ share->keypos_to_recpos= tmp_share.keypos_to_recpos;
+ share->recpos_to_keypos= tmp_share.recpos_to_keypos;
+}
+
+
+static void change_data_file_descriptor(MARIA_HA *info, File new_file)
+{
+ my_close(info->dfile.file, MYF(MY_WME));
+ info->dfile.file= info->s->bitmap.file.file= new_file;
+ _ma_bitmap_reset_cache(info->s);
+}
+
+
+/**
+ @brief Mark the data file to not be used
+
+ @note
+ This is used in repair when we want to ensure the handler will not
+ write anything to the data file anymore
+*/
+
+static void unuse_data_file_descriptor(MARIA_HA *info)
+{
+ info->dfile.file= info->s->bitmap.file.file= -1;
+ _ma_bitmap_reset_cache(info->s);
+}
+
+
+/*
+ Copy all states that has to do with the data file
+
+ NOTES
+ This is done to copy the state from the data file generated from
+ repair to the original handler
+*/
+
+static void copy_data_file_state(MARIA_STATE_INFO *to,
+ MARIA_STATE_INFO *from)
+{
+ to->state.records= from->state.records;
+ to->state.del= from->state.del;
+ to->state.empty= from->state.empty;
+ to->state.data_file_length= from->state.data_file_length;
+ to->split= from->split;
+ to->dellink= from->dellink;
+ to->first_bitmap_with_space= from->first_bitmap_with_space;
+}
+
+
+/*
+ Read 'safely' next record while scanning table.
+
+ SYNOPSIS
+ _ma_safe_scan_block_record()
+ info Maria handler
+ record Store found here
+
+ NOTES
+ - One must have called mi_scan() before this
+
+ Differences compared to _ma_scan_block_records() are:
+ - We read all blocks, not only blocks marked by the bitmap to be safe
+ - In case of errors, next read will read next record.
+ - More sanity checks
+
+ RETURN
+ 0 ok
+ HA_ERR_END_OF_FILE End of file
+ # error number
+*/
+
+
+static int _ma_safe_scan_block_record(MARIA_SORT_INFO *sort_info,
+ MARIA_HA *info, uchar *record)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_RECORD_POS record_pos= info->cur_row.nextpos;
+ pgcache_page_no_t page= sort_info->page;
+ DBUG_ENTER("_ma_safe_scan_block_record");
+
+ for (;;)
+ {
+ /* Find next row in current page */
+ if (likely(record_pos < info->scan.number_of_rows))
+ {
+ uint length, offset;
+ uchar *data, *end_of_data;
+ char llbuff[22];
+
+ while (!(offset= uint2korr(info->scan.dir)))
+ {
+ info->scan.dir-= DIR_ENTRY_SIZE;
+ record_pos++;
+ if (info->scan.dir < info->scan.dir_end)
+ {
+ _ma_check_print_info(sort_info->param,
+ "Wrong directory on page %s",
+ llstr(page, llbuff));
+ goto read_next_page;
+ }
+ }
+ /* found row */
+ info->cur_row.lastpos= info->scan.row_base_page + record_pos;
+ info->cur_row.nextpos= record_pos + 1;
+ data= info->scan.page_buff + offset;
+ length= uint2korr(info->scan.dir + 2);
+ end_of_data= data + length;
+ info->scan.dir-= DIR_ENTRY_SIZE; /* Point to previous row */
+
+ if (end_of_data > info->scan.dir_end ||
+ offset < PAGE_HEADER_SIZE || length < share->base.min_block_length)
+ {
+ _ma_check_print_info(sort_info->param,
+ "Wrong directory entry %3u at page %s",
+ (uint) record_pos, llstr(page, llbuff));
+ record_pos++;
+ continue;
+ }
+ else
+ {
+ DBUG_PRINT("info", ("rowid: %lu", (ulong) info->cur_row.lastpos));
+ DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data));
+ }
+ }
+
+read_next_page:
+ /* Read until we find next head page */
+ for (;;)
+ {
+ uint page_type;
+ char llbuff[22];
+
+ sort_info->page++; /* In case of errors */
+ page++;
+ if (!(page % share->bitmap.pages_covered))
+ {
+ /* Skip bitmap */
+ page++;
+ sort_info->page++;
+ }
+ if ((my_off_t) (page + 1) * share->block_size > sort_info->filelength)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ if (!(pagecache_read(share->pagecache,
+ &info->dfile,
+ page, 0, info->scan.page_buff,
+ PAGECACHE_READ_UNKNOWN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ {
+ if (my_errno == HA_ERR_WRONG_CRC)
+ {
+ _ma_check_print_info(sort_info->param,
+ "Wrong CRC on datapage at %s",
+ llstr(page, llbuff));
+ continue;
+ }
+ DBUG_RETURN(my_errno);
+ }
+ page_type= (info->scan.page_buff[PAGE_TYPE_OFFSET] &
+ PAGE_TYPE_MASK);
+ if (page_type == HEAD_PAGE)
+ {
+ if ((info->scan.number_of_rows=
+ (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) != 0)
+ break;
+ _ma_check_print_info(sort_info->param,
+ "Wrong head page at page %s",
+ llstr(page, llbuff));
+ }
+ else if (page_type >= MAX_PAGE_TYPE)
+ {
+ _ma_check_print_info(sort_info->param,
+ "Found wrong page type: %d at page %s",
+ page_type, llstr(page, llbuff));
+ }
+ }
+
+ /* New head page */
+ info->scan.dir= (info->scan.page_buff + share->block_size -
+ PAGE_SUFFIX_SIZE - DIR_ENTRY_SIZE);
+ info->scan.dir_end= (info->scan.dir -
+ (info->scan.number_of_rows - 1) *
+ DIR_ENTRY_SIZE);
+ info->scan.row_base_page= ma_recordpos(page, 0);
+ record_pos= 0;
+ }
+}
+
+
+/**
+ @brief Writes a LOGREC_REPAIR_TABLE record and updates create_rename_lsn
+ if needed (so that maria_read_log does not redo the repair).
+
+ @param param description of the REPAIR operation
+ @param info table
+
+ @return Operation status
+ @retval 0 ok
+ @retval 1 error (disk problem)
+*/
+
+my_bool write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ /* in case this is maria_chk or recovery... */
+ if (translog_status == TRANSLOG_OK && !maria_in_recovery &&
+ share->base.born_transactional)
+ {
+ my_bool save_now_transactional= share->now_transactional;
+
+ /*
+ For now this record is only informative. It could serve when applying
+ logs to a backup, but that needs more thought. Assume table became
+ corrupted. It is repaired, then some writes happen to it.
+ Later we restore an old backup, and want to apply this REDO_REPAIR_TABLE
+ record. For it to give the same result as originally, the table should
+ be corrupted the same way, so applying previous REDOs should produce the
+ same corruption; that's really not guaranteed (different execution paths
+ in execution of REDOs vs runtime code so not same bugs hit, temporary
+ hardware issues not repeatable etc). Corruption may not be repeatable.
+ A reasonable solution is to execute the REDO_REPAIR_TABLE record and
+ check if the checksum of the resulting table matches what it was at the
+ end of the original repair (should be stored in log record); or execute
+ the REDO_REPAIR_TABLE if the checksum of the table-before-repair matches
+ was it was at the start of the original repair (should be stored in log
+ record).
+ */
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ uchar log_data[FILEID_STORE_SIZE + 8 + 8];
+ LSN lsn;
+
+ /*
+ testflag gives an idea of what REPAIR did (in particular T_QUICK
+ or not: did it touch the data file or not?).
+ */
+ int8store(log_data + FILEID_STORE_SIZE, param->testflag);
+ /* org_key_map is used when recreating index after a load data infile */
+ int8store(log_data + FILEID_STORE_SIZE + 8, param->org_key_map);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+
+ share->now_transactional= 1;
+ if (unlikely(translog_write_record(&lsn, LOGREC_REDO_REPAIR_TABLE,
+ &dummy_transaction_object, info,
+ (translog_size_t) sizeof(log_data),
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, log_data, NULL) ||
+ translog_flush(lsn)))
+ return TRUE;
+ /*
+ The table's existence was made durable earlier (MY_SYNC_DIR passed to
+ maria_change_to_newfile()). All pages have been flushed, state too, we
+ need to force it to disk. Old REDOs should not be applied to the table,
+ which is already enforced as skip_redos_lsn was increased in
+ protect_against_repair_crash(). But if this is an explicit repair,
+ even UNDO phase should ignore this table: create_rename_lsn should be
+ increased, and this also serves for the REDO_REPAIR to be ignored by
+ maria_read_log.
+ The fully correct order would be: sync data and index file, remove crash
+ mark and update LSNs then write state and sync index file. But at this
+ point state (without crash mark) is already written.
+ */
+ if ((!(param->testflag & T_NO_CREATE_RENAME_LSN) &&
+ _ma_update_state_lsns(share, lsn, share->state.create_trid, FALSE,
+ FALSE)) ||
+ _ma_sync_table_files(info))
+ return TRUE;
+ share->now_transactional= save_now_transactional;
+ }
+ return FALSE;
+}
+
+
+/**
+ Writes an UNDO record which if executed in UNDO phase, will empty the
+ table. Such record is thus logged only in certain cases of bulk insert
+ (table needs to be empty etc).
+*/
+my_bool write_log_record_for_bulk_insert(MARIA_HA *info)
+{
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE];
+ LSN lsn;
+ lsn_store(log_data, info->trn->undo_lsn);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ return translog_write_record(&lsn, LOGREC_UNDO_BULK_INSERT,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length,
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data + LSN_STORE_SIZE, NULL) ||
+ translog_flush(lsn); /* WAL */
+}
+
+
+/* Give error message why reading of key page failed */
+
+static void report_keypage_fault(HA_CHECK *param, MARIA_HA *info,
+ my_off_t position)
+{
+ char buff[11];
+ uint32 block_size= info->s->block_size;
+
+ if (my_errno == HA_ERR_CRASHED)
+ _ma_check_print_error(param,
+ "Wrong base information on indexpage at page: %s",
+ llstr(position / block_size, buff));
+ else
+ _ma_check_print_error(param,
+ "Can't read indexpage from page: %s, "
+ "error: %d",
+ llstr(position / block_size, buff), my_errno);
+}
+
+
+/**
+ When we want to check a table, we verify that the transaction ids of rows
+ and keys are not bigger than the biggest id generated by Maria so far, which
+ is returned by the function below.
+
+ @note If control file is not open, 0 may be returned; to not confuse
+ this with a valid max trid of 0, the caller should notice that it failed to
+ open the control file (ma_control_file_inited() can serve for that).
+*/
+
+static TrID max_trid_in_system(void)
+{
+ TrID id= trnman_get_max_trid(); /* 0 if transac manager not initialized */
+ /* 'id' may be far bigger, if last shutdown is old */
+ return max(id, max_trid_in_control_file);
+}
+
+
+static void _ma_check_print_not_visible_error(HA_CHECK *param, TrID used_trid)
+{
+ char buff[22], buff2[22];
+ if (!param->not_visible_rows_found++)
+ {
+ if (!ma_control_file_inited())
+ {
+ _ma_check_print_warning(param,
+ "Found row with transaction id %s but no maria_control_file was specified. The table may be corrupted",
+ llstr(used_trid, buff));
+ }
+ else
+ {
+ _ma_check_print_error(param,
+ "Found row with transaction id %s when max transaction id according to maria_control_file is %s",
+ llstr(used_trid, buff),
+ llstr(param->max_trid, buff2));
+ }
+ }
+}
+
+
+/**
+ Mark that we can retry normal repair if we used quick repair
+
+ We shouldn't do this in case of disk error as in this case we are likely
+ to loose much more than expected.
+*/
+
+void retry_if_quick(MARIA_SORT_PARAM *sort_param, int error)
+{
+ HA_CHECK *param=sort_param->sort_info->param;
+
+ if (!sort_param->fix_datafile && error >= HA_ERR_FIRST)
+ {
+ param->retry_repair=1;
+ param->testflag|=T_RETRY_WITHOUT_QUICK;
+ }
+}
diff --git a/storage/maria/ma_check_standalone.h b/storage/maria/ma_check_standalone.h
new file mode 100644
index 00000000000..3874d722d6c
--- /dev/null
+++ b/storage/maria/ma_check_standalone.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ All standalone programs which need to use functions from ma_check.c
+ (like maria_repair()) must define their version of _ma_killed_ptr()
+ and _ma_check_print_info|warning|error(). Indeed, linking with ma_check.o
+ brings in the dependencies of ma_check.o which are definitions of the above
+ functions; if the program does not define them then the ones of
+ ha_maria.o are used i.e. ha_maria.o is linked into the program, and this
+ brings dependencies of ha_maria.o on mysqld.o into the program's linking
+ which thus fails, as the program is not linked with mysqld.o.
+ This file contains the versions of these functions used by maria_chk and
+ maria_read_log.
+*/
+
+/*
+ Check if check/repair operation was killed by a signal
+*/
+
+static int not_killed= 0;
+
+volatile int *_ma_killed_ptr(HA_CHECK *param __attribute__((unused)))
+{
+ return &not_killed; /* always NULL */
+}
+
+ /* print warnings and errors */
+ /* VARARGS */
+
+void _ma_check_print_info(HA_CHECK *param __attribute__((unused)),
+ const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_info");
+ DBUG_PRINT("enter", ("format: %s", fmt));
+
+ va_start(args,fmt);
+ VOID(vfprintf(stdout, fmt, args));
+ VOID(fputc('\n',stdout));
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+/* VARARGS */
+
+void _ma_check_print_warning(HA_CHECK *param, const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_warning");
+ DBUG_PRINT("enter", ("format: %s", fmt));
+
+ fflush(stdout);
+ if (!param->warning_printed && !param->error_printed)
+ {
+ if (param->testflag & T_SILENT)
+ fprintf(stderr,"%s: MARIA file %s\n",my_progname_short,
+ param->isam_file_name);
+ param->out_flag|= O_DATA_LOST;
+ }
+ param->warning_printed=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: warning: ",my_progname_short);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
+
+/* VARARGS */
+
+void _ma_check_print_error(HA_CHECK *param, const char *fmt,...)
+{
+ va_list args;
+ DBUG_ENTER("_ma_check_print_error");
+ DBUG_PRINT("enter", ("format: %s", fmt));
+
+ fflush(stdout);
+ if (!param->warning_printed && !param->error_printed)
+ {
+ if (param->testflag & T_SILENT)
+ fprintf(stderr,"%s: MARIA file %s\n",my_progname_short,param->isam_file_name);
+ param->out_flag|= O_DATA_LOST;
+ }
+ param->error_printed|=1;
+ va_start(args,fmt);
+ fprintf(stderr,"%s: error: ",my_progname_short);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ DBUG_VOID_RETURN;
+}
diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c
new file mode 100644
index 00000000000..6d1a6332c54
--- /dev/null
+++ b/storage/maria/ma_checkpoint.c
@@ -0,0 +1,1235 @@
+/* Copyright (C) 2006,2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ WL#3071 Maria checkpoint
+ First version written by Guilhem Bichot on 2006-04-27.
+*/
+
+/* Here is the implementation of this module */
+
+/** @todo RECOVERY BUG this is unreviewed code */
+/*
+ Summary:
+ checkpoints are done either by a background thread (checkpoint every Nth
+ second) or by a client.
+ In ha_maria, it's not made available to clients, and will soon be done by a
+ background thread (periodically taking checkpoints and flushing dirty
+ pages).
+*/
+
+#include "maria_def.h"
+#include "ma_pagecache.h"
+#include "ma_blockrec.h"
+#include "ma_checkpoint.h"
+#include "ma_loghandler_lsn.h"
+
+
+/** @brief type of checkpoint currently running */
+static CHECKPOINT_LEVEL checkpoint_in_progress= CHECKPOINT_NONE;
+/** @brief protects checkpoint_in_progress */
+static pthread_mutex_t LOCK_checkpoint;
+/** @brief for killing the background checkpoint thread */
+static pthread_cond_t COND_checkpoint;
+/** @brief if checkpoint module was inited or not */
+static my_bool checkpoint_inited= FALSE;
+/** @brief 'kill' flag for the background checkpoint thread */
+static int checkpoint_thread_die;
+/* is ulong like pagecache->blocks_changed */
+static ulong pages_to_flush_before_next_checkpoint;
+static PAGECACHE_FILE *dfiles, /**< data files to flush in background */
+ *dfiles_end; /**< list of data files ends here */
+static PAGECACHE_FILE *kfiles, /**< index files to flush in background */
+ *kfiles_end; /**< list of index files ends here */
+/* those two statistics below could serve in SHOW GLOBAL STATUS */
+static uint checkpoints_total= 0, /**< all checkpoint requests made */
+ checkpoints_ok_total= 0; /**< all checkpoints which succeeded */
+
+struct st_filter_param
+{
+ LSN up_to_lsn; /**< only pages with rec_lsn < this LSN */
+ uint max_pages; /**< stop after flushing this number pages */
+}; /**< information to determine which dirty pages should be flushed */
+
+static enum pagecache_flush_filter_result
+filter_flush_file_medium(enum pagecache_page_type type,
+ pgcache_page_no_t page,
+ LSN rec_lsn, void *arg);
+static enum pagecache_flush_filter_result
+filter_flush_file_full(enum pagecache_page_type type,
+ pgcache_page_no_t page,
+ LSN rec_lsn, void *arg);
+static enum pagecache_flush_filter_result
+filter_flush_file_evenly(enum pagecache_page_type type,
+ pgcache_page_no_t pageno,
+ LSN rec_lsn, void *arg);
+static int really_execute_checkpoint(void);
+pthread_handler_t ma_checkpoint_background(void *arg);
+static int collect_tables(LEX_STRING *str, LSN checkpoint_start_log_horizon);
+
+/**
+ @brief Does a checkpoint
+
+ @param level what level of checkpoint to do
+ @param no_wait if another checkpoint of same or stronger level
+ is already running, consider our job done
+
+ @note In ha_maria, there can never be two threads trying a checkpoint at
+ the same time.
+
+ @return Operation status
+ @retval 0 ok
+ @retval !=0 error
+*/
+
+int ma_checkpoint_execute(CHECKPOINT_LEVEL level, my_bool no_wait)
+{
+ int result= 0;
+ DBUG_ENTER("ma_checkpoint_execute");
+
+ if (!checkpoint_inited)
+ {
+ /*
+ If ha_maria failed to start, maria_panic_hton is called, we come here.
+ */
+ DBUG_RETURN(0);
+ }
+ DBUG_ASSERT(level > CHECKPOINT_NONE);
+
+ /* look for already running checkpoints */
+ pthread_mutex_lock(&LOCK_checkpoint);
+ while (checkpoint_in_progress != CHECKPOINT_NONE)
+ {
+ if (no_wait && (checkpoint_in_progress >= level))
+ {
+ /*
+ If we are the checkpoint background thread, we don't wait (it's
+ smarter to flush pages instead of waiting here while the other thread
+ finishes its checkpoint).
+ */
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ goto end;
+ }
+ pthread_cond_wait(&COND_checkpoint, &LOCK_checkpoint);
+ }
+
+ checkpoint_in_progress= level;
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ /* from then on, we are sure to be and stay the only checkpointer */
+
+ result= really_execute_checkpoint();
+ pthread_cond_broadcast(&COND_checkpoint);
+end:
+ DBUG_RETURN(result);
+}
+
+
+/**
+ @brief Does a checkpoint, really; expects no other checkpoints
+ running.
+
+ Checkpoint level requested is read from checkpoint_in_progress.
+
+ @return Operation status
+ @retval 0 ok
+ @retval !=0 error
+*/
+
+static int really_execute_checkpoint(void)
+{
+ uint i, error= 0;
+ /** @brief checkpoint_start_log_horizon will be stored there */
+ char *ptr;
+ LEX_STRING record_pieces[4]; /**< only malloc-ed pieces */
+ LSN min_page_rec_lsn, min_trn_rec_lsn, min_first_undo_lsn;
+ TRANSLOG_ADDRESS checkpoint_start_log_horizon;
+ char checkpoint_start_log_horizon_char[LSN_STORE_SIZE];
+ DBUG_ENTER("really_execute_checkpoint");
+ DBUG_PRINT("enter", ("level: %d", checkpoint_in_progress));
+ bzero(&record_pieces, sizeof(record_pieces));
+
+ /*
+ STEP 1: record current end-of-log position using log's lock. It is
+ critical for the correctness of Checkpoint (related to memory visibility
+ rules, the log's lock is a mutex).
+ "Horizon" is a lower bound of the LSN of the next log record.
+ */
+ checkpoint_start_log_horizon= translog_get_horizon();
+ DBUG_PRINT("info",("checkpoint_start_log_horizon (%lu,0x%lx)",
+ LSN_IN_PARTS(checkpoint_start_log_horizon)));
+ lsn_store(checkpoint_start_log_horizon_char, checkpoint_start_log_horizon);
+
+ /*
+ STEP 2: fetch information about transactions.
+ We must fetch transactions before dirty pages. Indeed, a transaction
+ first sets its rec_lsn then sets the page's rec_lsn then sets its rec_lsn
+ to 0. If we fetched pages first, we may see no dirty page yet, then we
+ fetch transactions but the transaction has already reset its rec_lsn to 0
+ so we miss rec_lsn again.
+ For a similar reason (over-allocated bitmap pages) we have to fetch
+ transactions before flushing bitmap pages.
+
+ min_trn_rec_lsn will serve to lower the starting point of the REDO phase
+ (down from checkpoint_start_log_horizon).
+ */
+ if (unlikely(trnman_collect_transactions(&record_pieces[0],
+ &record_pieces[1],
+ &min_trn_rec_lsn,
+ &min_first_undo_lsn)))
+ goto err;
+
+
+ /* STEP 3: fetch information about table files */
+ if (unlikely(collect_tables(&record_pieces[2],
+ checkpoint_start_log_horizon)))
+ goto err;
+
+
+ /* STEP 4: fetch information about dirty pages */
+ /*
+ It's better to do it _after_ having flushed some data pages (which
+ collect_tables() may have done), because those are now non-dirty and so we
+ have a more up-to-date dirty pages list to put into the checkpoint record,
+ and thus we will have less work at Recovery.
+ */
+ /* Using default pagecache for now */
+ if (unlikely(pagecache_collect_changed_blocks_with_lsn(maria_pagecache,
+ &record_pieces[3],
+ &min_page_rec_lsn)))
+ goto err;
+
+
+ /* LAST STEP: now write the checkpoint log record */
+ {
+ LSN lsn;
+ translog_size_t total_rec_length;
+ /*
+ the log handler is allowed to modify "str" and "length" (but not "*str")
+ of its argument, so we must not pass it record_pieces directly,
+ otherwise we would later not know what memory pieces to my_free().
+ */
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 5];
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str=
+ (uchar*) checkpoint_start_log_horizon_char;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= total_rec_length=
+ sizeof(checkpoint_start_log_horizon_char);
+ for (i= 0; i < (sizeof(record_pieces)/sizeof(record_pieces[0])); i++)
+ {
+ log_array[TRANSLOG_INTERNAL_PARTS + 1 + i]=
+ *(LEX_CUSTRING *)&record_pieces[i];
+ total_rec_length+= (translog_size_t) record_pieces[i].length;
+ }
+ if (unlikely(translog_write_record(&lsn, LOGREC_CHECKPOINT,
+ &dummy_transaction_object, NULL,
+ total_rec_length,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL) ||
+ translog_flush(lsn)))
+ goto err;
+ translog_lock();
+ /*
+ This cannot be done as a inwrite_rec_hook of LOGREC_CHECKPOINT, because
+ such hook would be called before translog_flush (and we must be sure
+ that log was flushed before we write to the control file).
+ */
+ if (unlikely(ma_control_file_write_and_force(lsn, last_logno,
+ max_trid_in_control_file,
+ recovery_failures)))
+ {
+ translog_unlock();
+ goto err;
+ }
+ translog_unlock();
+ }
+
+ /*
+ Note that we should not alter memory structures until we have successfully
+ written the checkpoint record and control file.
+ */
+ /* checkpoint succeeded */
+ ptr= record_pieces[3].str;
+ pages_to_flush_before_next_checkpoint= uint4korr(ptr);
+ DBUG_PRINT("checkpoint",("%u pages to flush before next checkpoint",
+ (uint)pages_to_flush_before_next_checkpoint));
+
+ /* compute log's low-water mark */
+ {
+ TRANSLOG_ADDRESS log_low_water_mark= min_page_rec_lsn;
+ set_if_smaller(log_low_water_mark, min_trn_rec_lsn);
+ set_if_smaller(log_low_water_mark, min_first_undo_lsn);
+ set_if_smaller(log_low_water_mark, checkpoint_start_log_horizon);
+ /**
+ Now purge unneeded logs.
+ As some systems have an unreliable fsync (drive lying), we could try to
+ be robust against that: remember a few previous checkpoints in the
+ control file, and not purge logs immediately... Think about it.
+ */
+ if (translog_purge(log_low_water_mark))
+ ma_message_no_user(0, "log purging failed");
+ }
+
+ goto end;
+
+err:
+ error= 1;
+ ma_message_no_user(0, "checkpoint failed");
+ /* we were possibly not able to determine what pages to flush */
+ pages_to_flush_before_next_checkpoint= 0;
+
+end:
+ for (i= 0; i < (sizeof(record_pieces)/sizeof(record_pieces[0])); i++)
+ my_free(record_pieces[i].str, MYF(MY_ALLOW_ZERO_PTR));
+ pthread_mutex_lock(&LOCK_checkpoint);
+ checkpoint_in_progress= CHECKPOINT_NONE;
+ checkpoints_total++;
+ checkpoints_ok_total+= !error;
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ DBUG_RETURN(error);
+}
+
+
+/**
+ @brief Initializes the checkpoint module
+
+ @param interval If one wants the module to create a
+ thread which will periodically do
+ checkpoints, and flush dirty pages, in the
+ background, it should specify a non-zero
+ interval in seconds. The thread will then be
+ created and will take checkpoints separated by
+ approximately 'interval' second.
+
+ @note A checkpoint is taken only if there has been some significant
+ activity since the previous checkpoint. Between checkpoint N and N+1 the
+ thread flushes all dirty pages which were already dirty at the time of
+ checkpoint N.
+
+ @return Operation status
+ @retval 0 ok
+ @retval !=0 error
+*/
+
+int ma_checkpoint_init(ulong interval)
+{
+ pthread_t th;
+ int res= 0;
+ DBUG_ENTER("ma_checkpoint_init");
+ checkpoint_inited= TRUE;
+ checkpoint_thread_die= 2; /* not yet born == dead */
+ if (pthread_mutex_init(&LOCK_checkpoint, MY_MUTEX_INIT_SLOW) ||
+ pthread_cond_init(&COND_checkpoint, 0))
+ res= 1;
+ else if (interval > 0)
+ {
+ compile_time_assert(sizeof(void *) >= sizeof(ulong));
+ if (!(res= pthread_create(&th, NULL, ma_checkpoint_background,
+ (void *)interval)))
+ checkpoint_thread_die= 0; /* thread lives, will have to be killed */
+ }
+ DBUG_RETURN(res);
+}
+
+
+#ifndef DBUG_OFF
+/**
+ Function used to test recovery: flush some table pieces and then caller
+ crashes.
+
+ @param what_to_flush 0: current bitmap and all data pages
+ 1: state
+ 2: all bitmap pages
+*/
+static void flush_all_tables(int what_to_flush)
+{
+ int res= 0;
+ LIST *pos; /**< to iterate over open tables */
+ pthread_mutex_lock(&THR_LOCK_maria);
+ for (pos= maria_open_list; pos; pos= pos->next)
+ {
+ MARIA_HA *info= (MARIA_HA*)pos->data;
+ if (info->s->now_transactional)
+ {
+ switch (what_to_flush)
+ {
+ case 0:
+ res= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_KEEP, FLUSH_KEEP);
+ break;
+ case 1:
+ res= _ma_state_info_write(info->s,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET|
+ MA_STATE_INFO_WRITE_LOCK);
+ DBUG_PRINT("maria_flush_states",
+ ("is_of_horizon: LSN (%lu,0x%lx)",
+ LSN_IN_PARTS(info->s->state.is_of_horizon)));
+ break;
+ case 2:
+ res= _ma_bitmap_flush_all(info->s);
+ break;
+ }
+ }
+ DBUG_ASSERT(res == 0);
+ }
+ pthread_mutex_unlock(&THR_LOCK_maria);
+}
+#endif
+
+
+/**
+ @brief Destroys the checkpoint module
+*/
+
+void ma_checkpoint_end(void)
+{
+ DBUG_ENTER("ma_checkpoint_end");
+ /*
+ Some intentional crash methods, usually triggered by
+ SET MARIA_CHECKPOINT_INTERVAL=X
+ */
+ DBUG_EXECUTE_IF("maria_flush_bitmap",
+ {
+ DBUG_PRINT("maria_flush_bitmap", ("now"));
+ flush_all_tables(2);
+ });
+ DBUG_EXECUTE_IF("maria_flush_whole_page_cache",
+ {
+ DBUG_PRINT("maria_flush_whole_page_cache", ("now"));
+ flush_all_tables(0);
+ });
+ DBUG_EXECUTE_IF("maria_flush_whole_log",
+ {
+ DBUG_PRINT("maria_flush_whole_log", ("now"));
+ translog_flush(translog_get_horizon());
+ });
+ /*
+ Note that for WAL reasons, maria_flush_states requires
+ maria_flush_whole_log.
+ */
+ DBUG_EXECUTE_IF("maria_flush_states",
+ {
+ DBUG_PRINT("maria_flush_states", ("now"));
+ flush_all_tables(1);
+ });
+ DBUG_EXECUTE_IF("maria_crash",
+ { DBUG_PRINT("maria_crash", ("now")); DBUG_ABORT(); });
+
+ if (checkpoint_inited)
+ {
+ pthread_mutex_lock(&LOCK_checkpoint);
+ if (checkpoint_thread_die != 2) /* thread was started ok */
+ {
+ DBUG_PRINT("info",("killing Maria background checkpoint thread"));
+ checkpoint_thread_die= 1; /* kill it */
+ do /* and wait for it to be dead */
+ {
+ /* wake it up if it was in a sleep */
+ pthread_cond_broadcast(&COND_checkpoint);
+ DBUG_PRINT("info",("waiting for Maria background checkpoint thread"
+ " to die"));
+ pthread_cond_wait(&COND_checkpoint, &LOCK_checkpoint);
+ }
+ while (checkpoint_thread_die != 2);
+ }
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ my_free((uchar *)dfiles, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar *)kfiles, MYF(MY_ALLOW_ZERO_PTR));
+ dfiles= kfiles= NULL;
+ pthread_mutex_destroy(&LOCK_checkpoint);
+ pthread_cond_destroy(&COND_checkpoint);
+ checkpoint_inited= FALSE;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief dirty-page filtering criteria for MEDIUM checkpoint.
+
+ We flush data/index pages which have been dirty since the previous
+ checkpoint (this is the two-checkpoint rule: the REDO phase will not have
+ to start from earlier than the next-to-last checkpoint).
+ Bitmap pages are handled by _ma_bitmap_flush_all().
+
+ @param type Page's type
+ @param pageno Page's number
+ @param rec_lsn Page's rec_lsn
+ @param arg filter_param
+*/
+
+static enum pagecache_flush_filter_result
+filter_flush_file_medium(enum pagecache_page_type type,
+ pgcache_page_no_t pageno __attribute__ ((unused)),
+ LSN rec_lsn, void *arg)
+{
+ struct st_filter_param *param= (struct st_filter_param *)arg;
+ return (type == PAGECACHE_LSN_PAGE) &&
+ (cmp_translog_addr(rec_lsn, param->up_to_lsn) <= 0);
+}
+
+
+/**
+ @brief dirty-page filtering criteria for FULL checkpoint.
+
+ We flush all dirty data/index pages.
+ Bitmap pages are handled by _ma_bitmap_flush_all().
+
+ @param type Page's type
+ @param pageno Page's number
+ @param rec_lsn Page's rec_lsn
+ @param arg filter_param
+*/
+
+static enum pagecache_flush_filter_result
+filter_flush_file_full(enum pagecache_page_type type,
+ pgcache_page_no_t pageno __attribute__ ((unused)),
+ LSN rec_lsn __attribute__ ((unused)),
+ void *arg __attribute__ ((unused)))
+{
+ return (type == PAGECACHE_LSN_PAGE);
+}
+
+
+/**
+ @brief dirty-page filtering criteria for background flushing thread.
+
+ We flush data/index pages which have been dirty since the previous
+ checkpoint (this is the two-checkpoint rule: the REDO phase will not have
+ to start from earlier than the next-to-last checkpoint), and no
+ bitmap pages. But we flush no more than a certain number of pages (to have
+ an even flushing, no write burst).
+ The reason to not flush bitmap pages is that they may not be in a flushable
+ state at this moment and we don't want to wait for them.
+
+ @param type Page's type
+ @param pageno Page's number
+ @param rec_lsn Page's rec_lsn
+ @param arg filter_param
+*/
+
+static enum pagecache_flush_filter_result
+filter_flush_file_evenly(enum pagecache_page_type type,
+ pgcache_page_no_t pageno __attribute__ ((unused)),
+ LSN rec_lsn, void *arg)
+{
+ struct st_filter_param *param= (struct st_filter_param *)arg;
+ if (unlikely(param->max_pages == 0)) /* all flushed already */
+ return FLUSH_FILTER_SKIP_ALL;
+ if ((type == PAGECACHE_LSN_PAGE) &&
+ (cmp_translog_addr(rec_lsn, param->up_to_lsn) <= 0))
+ {
+ param->max_pages--;
+ return FLUSH_FILTER_OK;
+ }
+ return FLUSH_FILTER_SKIP_TRY_NEXT;
+}
+
+
+/**
+ @brief Background thread which does checkpoints and flushes periodically.
+
+ Takes a checkpoint. After this, all pages dirty at the time of that
+ checkpoint are flushed evenly until it is time to take another checkpoint.
+ This ensures that the REDO phase starts at earliest (in LSN time) at the
+ next-to-last checkpoint record ("two-checkpoint rule").
+
+ @note MikaelR questioned why the same thread does two different jobs, the
+ risk could be that while a checkpoint happens no LRD flushing happens.
+*/
+
+pthread_handler_t ma_checkpoint_background(void *arg)
+{
+ /** @brief At least this of log/page bytes written between checkpoints */
+ const uint checkpoint_min_activity= 2*1024*1024;
+ /*
+ If the interval could be changed by the user while we are in this thread,
+ it could be annoying: for example it could cause "case 2" to be executed
+ right after "case 0", thus having 'dfile' unset. So the thread cares only
+ about the interval's value when it started.
+ */
+ const ulong interval= (ulong)arg;
+ uint sleeps, sleep_time;
+ TRANSLOG_ADDRESS log_horizon_at_last_checkpoint=
+ translog_get_horizon();
+ ulonglong pagecache_flushes_at_last_checkpoint=
+ maria_pagecache->global_cache_write;
+ uint pages_bunch_size;
+ struct st_filter_param filter_param;
+ PAGECACHE_FILE *dfile; /**< data file currently being flushed */
+ PAGECACHE_FILE *kfile; /**< index file currently being flushed */
+ LINT_INIT(kfile);
+ LINT_INIT(dfile);
+ LINT_INIT(pages_bunch_size);
+
+ my_thread_init();
+ DBUG_PRINT("info",("Maria background checkpoint thread starts"));
+ DBUG_ASSERT(interval > 0);
+
+ /*
+ Recovery ended with all tables closed and a checkpoint: no need to take
+ one immediately.
+ */
+ sleeps= 1;
+ pages_to_flush_before_next_checkpoint= 0;
+
+ for(;;) /* iterations of checkpoints and dirty page flushing */
+ {
+#if 0 /* good for testing, to do a lot of checkpoints, finds a lot of bugs */
+ sleeps=0;
+#endif
+ struct timespec abstime;
+ switch (sleeps % interval)
+ {
+ case 0:
+ /*
+ With background flushing evenly distributed over the time
+ between two checkpoints, we should have only little flushing to do
+ in the checkpoint.
+ */
+ /*
+ No checkpoint if little work of interest for recovery was done
+ since last checkpoint. Such work includes log writing (lengthens
+ recovery, checkpoint would shorten it), page flushing (checkpoint
+ would decrease the amount of read pages in recovery).
+ In case of one short statement per minute (very low load), we don't
+ want to checkpoint every minute, hence the positive
+ checkpoint_min_activity.
+ */
+ if (((translog_get_horizon() - log_horizon_at_last_checkpoint) +
+ (maria_pagecache->global_cache_write -
+ pagecache_flushes_at_last_checkpoint) *
+ maria_pagecache->block_size) < checkpoint_min_activity)
+ {
+ /* don't take checkpoint, so don't know what to flush */
+ pages_to_flush_before_next_checkpoint= 0;
+ sleep_time= interval;
+ break;
+ }
+ sleep_time= 1;
+ ma_checkpoint_execute(CHECKPOINT_MEDIUM, TRUE);
+ /*
+ Snapshot this kind of "state" of the engine. Note that the value below
+ is possibly greater than last_checkpoint_lsn.
+ */
+ log_horizon_at_last_checkpoint= translog_get_horizon();
+ pagecache_flushes_at_last_checkpoint=
+ maria_pagecache->global_cache_write;
+ /*
+ If the checkpoint above succeeded it has set d|kfiles and
+ d|kfiles_end. If is has failed, it has set
+ pages_to_flush_before_next_checkpoint to 0 so we will skip flushing
+ and sleep until the next checkpoint.
+ */
+ break;
+ case 1:
+ /* set up parameters for background page flushing */
+ filter_param.up_to_lsn= last_checkpoint_lsn;
+ pages_bunch_size= pages_to_flush_before_next_checkpoint / interval;
+ dfile= dfiles;
+ kfile= kfiles;
+ /* fall through */
+ default:
+ if (pages_bunch_size > 0)
+ {
+ DBUG_PRINT("checkpoint",
+ ("Maria background checkpoint thread: %u pages",
+ pages_bunch_size));
+ /* flush a bunch of dirty pages */
+ filter_param.max_pages= pages_bunch_size;
+ while (dfile != dfiles_end)
+ {
+ /*
+ We use FLUSH_KEEP_LAZY: if a file is already in flush, it's
+ smarter to move to the next file than wait for this one to be
+ completely flushed, which may take long.
+ StaleFilePointersInFlush: notice how below we use "dfile" which
+ is an OS file descriptor plus some function and MARIA_SHARE
+ pointers; this data dates from a previous checkpoint; since then,
+ the table may have been closed (so MARIA_SHARE* became stale), and
+ the file descriptor reassigned to another table which does not
+ have the same CRC-read-set callbacks: it is thus important that
+ flush_pagecache_blocks_with_filter() does not use the pointers,
+ only the OS file descriptor.
+ */
+ int res=
+ flush_pagecache_blocks_with_filter(maria_pagecache,
+ dfile, FLUSH_KEEP_LAZY,
+ filter_flush_file_evenly,
+ &filter_param);
+ if (unlikely(res & PCFLUSH_ERROR))
+ ma_message_no_user(0, "background data page flush failed");
+ if (filter_param.max_pages == 0) /* bunch all flushed, sleep */
+ break; /* and we will continue with the same file */
+ dfile++; /* otherwise all this file is flushed, move to next file */
+ /*
+ MikaelR noted that he observed that Linux's file cache may never
+ fsync to disk until this cache is full, at which point it decides
+ to empty the cache, making the machine very slow. A solution was
+ to fsync after writing 2 MB. So we might want to fsync() here if
+ we wrote enough pages.
+ */
+ }
+ while (kfile != kfiles_end)
+ {
+ int res=
+ flush_pagecache_blocks_with_filter(maria_pagecache,
+ kfile, FLUSH_KEEP_LAZY,
+ filter_flush_file_evenly,
+ &filter_param);
+ if (unlikely(res & PCFLUSH_ERROR))
+ ma_message_no_user(0, "background index page flush failed");
+ if (filter_param.max_pages == 0) /* bunch all flushed, sleep */
+ break; /* and we will continue with the same file */
+ kfile++; /* otherwise all this file is flushed, move to next file */
+ }
+ sleep_time= 1;
+ }
+ else
+ {
+ /* Can directly sleep until the next checkpoint moment */
+ sleep_time= interval - (sleeps % interval);
+ }
+ }
+ pthread_mutex_lock(&LOCK_checkpoint);
+ if (checkpoint_thread_die == 1)
+ break;
+#if 0 /* good for testing, to do a lot of checkpoints, finds a lot of bugs */
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ my_sleep(100000); /* a tenth of a second */
+ pthread_mutex_lock(&LOCK_checkpoint);
+#else
+ /* To have a killable sleep, we use timedwait like our SQL GET_LOCK() */
+ DBUG_PRINT("info", ("sleeping %u seconds", sleep_time));
+ set_timespec(abstime, sleep_time);
+ pthread_cond_timedwait(&COND_checkpoint, &LOCK_checkpoint, &abstime);
+#endif
+ if (checkpoint_thread_die == 1)
+ break;
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ sleeps+= sleep_time;
+ }
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ DBUG_PRINT("info",("Maria background checkpoint thread ends"));
+ {
+ CHECKPOINT_LEVEL level= CHECKPOINT_FULL;
+ /*
+ That's the final one, which guarantees that a clean shutdown always ends
+ with a checkpoint.
+ */
+ DBUG_EXECUTE_IF("maria_checkpoint_indirect", level= CHECKPOINT_INDIRECT;);
+ ma_checkpoint_execute(level, FALSE);
+ }
+ pthread_mutex_lock(&LOCK_checkpoint);
+ checkpoint_thread_die= 2; /* indicate that we are dead */
+ /* wake up ma_checkpoint_end() which may be waiting for our death */
+ pthread_cond_broadcast(&COND_checkpoint);
+ /* broadcast was inside unlock because ma_checkpoint_end() destroys mutex */
+ pthread_mutex_unlock(&LOCK_checkpoint);
+ my_thread_end();
+ return 0;
+}
+
+
+/**
+ @brief Allocates buffer and stores in it some info about open tables,
+ does some flushing on those.
+
+ Does the allocation because the caller cannot know the size itself.
+ Memory freeing is to be done by the caller (if the "str" member of the
+ LEX_STRING is not NULL).
+ The caller is taking a checkpoint.
+
+ @param[out] str pointer to where the allocated buffer,
+ and its size, will be put; buffer will be filled
+ with info about open tables
+ @param checkpoint_start_log_horizon Of the in-progress checkpoint
+ record.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static int collect_tables(LEX_STRING *str, LSN checkpoint_start_log_horizon)
+{
+ MARIA_SHARE **distinct_shares= NULL;
+ char *ptr;
+ uint error= 1, sync_error= 0, nb, nb_stored, i;
+ my_bool unmark_tables= TRUE;
+ uint total_names_length;
+ LIST *pos; /**< to iterate over open tables */
+ struct st_state_copy {
+ uint index;
+ MARIA_STATE_INFO state;
+ };
+ struct st_state_copy *state_copies= NULL, /**< fixed-size cache of states */
+ *state_copies_end, /**< cache ends here */
+ *state_copy; /**< iterator in cache */
+ TRANSLOG_ADDRESS state_copies_horizon; /**< horizon of states' _copies_ */
+ struct st_filter_param filter_param;
+ PAGECACHE_FLUSH_FILTER filter;
+ DBUG_ENTER("collect_tables");
+
+ LINT_INIT(state_copies_horizon);
+ /* let's make a list of distinct shares */
+ pthread_mutex_lock(&THR_LOCK_maria);
+ for (nb= 0, pos= maria_open_list; pos; pos= pos->next)
+ {
+ MARIA_HA *info= (MARIA_HA*)pos->data;
+ MARIA_SHARE *share= info->s;
+ /* the first three variables below can never change */
+ if (share->base.born_transactional && !share->temporary &&
+ share->mode != O_RDONLY &&
+ !(share->in_checkpoint & MARIA_CHECKPOINT_SEEN_IN_LOOP))
+ {
+ /*
+ Apart from us, only maria_close() reads/sets in_checkpoint but cannot
+ run now as we hold THR_LOCK_maria.
+ */
+ /*
+ This table is relevant for checkpoint and not already seen. Mark it,
+ so that it is not seen again in the loop.
+ */
+ nb++;
+ DBUG_ASSERT(share->in_checkpoint == 0);
+ /* This flag ensures that we count only _distinct_ shares. */
+ share->in_checkpoint= MARIA_CHECKPOINT_SEEN_IN_LOOP;
+ }
+ }
+ if (unlikely((distinct_shares=
+ (MARIA_SHARE **)my_malloc(nb * sizeof(MARIA_SHARE *),
+ MYF(MY_WME))) == NULL))
+ goto err;
+ for (total_names_length= 0, i= 0, pos= maria_open_list; pos; pos= pos->next)
+ {
+ MARIA_HA *info= (MARIA_HA*)pos->data;
+ MARIA_SHARE *share= info->s;
+ if (share->in_checkpoint & MARIA_CHECKPOINT_SEEN_IN_LOOP)
+ {
+ distinct_shares[i++]= share;
+ /*
+ With this we prevent the share from going away while we later flush
+ and force it without holding THR_LOCK_maria. For example if the share
+ could be my_free()d by maria_close() we would have a problem when we
+ access it to flush the table. We "pin" the share pointer.
+ And we also take down MARIA_CHECKPOINT_SEEN_IN_LOOP, so that it is
+ not seen again in the loop.
+ */
+ share->in_checkpoint= MARIA_CHECKPOINT_LOOKS_AT_ME;
+ /** @todo avoid strlen() */
+ total_names_length+= share->open_file_name.length;
+ }
+ }
+
+ DBUG_ASSERT(i == nb);
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ DBUG_PRINT("info",("found %u table shares", nb));
+
+ str->length=
+ 4 + /* number of tables */
+ (2 + /* short id */
+ LSN_STORE_SIZE + /* first_log_write_at_lsn */
+ 1 /* end-of-name 0 */
+ ) * nb + total_names_length;
+ if (unlikely((str->str= my_malloc(str->length, MYF(MY_WME))) == NULL))
+ goto err;
+
+ ptr= str->str;
+ ptr+= 4; /* real number of stored tables is not yet know */
+
+ /* only possible checkpointer, so can do the read below without mutex */
+ filter_param.up_to_lsn= last_checkpoint_lsn;
+ switch(checkpoint_in_progress)
+ {
+ case CHECKPOINT_MEDIUM:
+ filter= &filter_flush_file_medium;
+ break;
+ case CHECKPOINT_FULL:
+ filter= &filter_flush_file_full;
+ break;
+ case CHECKPOINT_INDIRECT:
+ filter= NULL;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ goto err;
+ }
+
+ /*
+ The principle of reading/writing the state below is explained in
+ ma_recovery.c, look for "Recovery of the state".
+ */
+#define STATE_COPIES 1024
+ state_copies= (struct st_state_copy *)
+ my_malloc(STATE_COPIES * sizeof(struct st_state_copy), MYF(MY_WME));
+ dfiles= (PAGECACHE_FILE *)my_realloc((uchar *)dfiles,
+ /* avoid size of 0 for my_realloc */
+ max(1, nb) * sizeof(PAGECACHE_FILE),
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR));
+ kfiles= (PAGECACHE_FILE *)my_realloc((uchar *)kfiles,
+ /* avoid size of 0 for my_realloc */
+ max(1, nb) * sizeof(PAGECACHE_FILE),
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR));
+ if (unlikely((state_copies == NULL) ||
+ (dfiles == NULL) || (kfiles == NULL)))
+ goto err;
+ state_copy= state_copies_end= NULL;
+ dfiles_end= dfiles;
+ kfiles_end= kfiles;
+
+ for (nb_stored= 0, i= 0; i < nb; i++)
+ {
+ MARIA_SHARE *share= distinct_shares[i];
+ PAGECACHE_FILE kfile, dfile;
+ my_bool ignore_share;
+ if (!(share->in_checkpoint & MARIA_CHECKPOINT_LOOKS_AT_ME))
+ {
+ /*
+ No need for a mutex to read the above, only us can write *this* bit of
+ the in_checkpoint bitmap
+ */
+ continue;
+ }
+ /**
+ @todo We should not look at tables which didn't change since last
+ checkpoint.
+ */
+ DBUG_PRINT("info",("looking at table '%s'", share->open_file_name.str));
+ if (state_copy == state_copies_end) /* we have no more cached states */
+ {
+ /*
+ Collect and cache a bunch of states. We do this for many states at a
+ time, to not lock/unlock the log's lock too often.
+ */
+ uint j, bound= min(nb, i + STATE_COPIES);
+ state_copy= state_copies;
+ /* part of the state is protected by log's lock */
+ translog_lock();
+ state_copies_horizon= translog_get_horizon_no_lock();
+ for (j= i; j < bound; j++)
+ {
+ MARIA_SHARE *share2= distinct_shares[j];
+ if (!(share2->in_checkpoint & MARIA_CHECKPOINT_LOOKS_AT_ME))
+ continue;
+ state_copy->index= j;
+ state_copy->state= share2->state; /* we copy the state */
+ state_copy++;
+ /*
+ data_file_length is not updated under log's lock by the bitmap
+ code, but writing a wrong data_file_length is ok: a next
+ maria_close() will correct it; if we crash before, Recovery will
+ set it to the true physical size.
+ */
+ }
+ translog_unlock();
+ /**
+ We are going to flush these states.
+ Before, all records describing how to undo such state must be
+ in the log (WAL). Usually this means UNDOs. In the special case of
+ data|key_file_length, recovery just needs to open the table to fix the
+ length, so any LOGREC_FILE_ID/REDO/UNDO allowing recovery to
+ understand it must open a table, is enough; so as long as
+ data|key_file_length is updated after writing any log record it's ok:
+ if we copied new value above, it means the record was before
+ state_copies_horizon and we flush such record below.
+ Apart from data|key_file_length which are easily recoverable from the
+ real file's size, all other state members must be updated only when
+ writing the UNDO; otherwise, if updated before, if their new value is
+ flushed by a checkpoint and there is a crash before UNDO is written,
+ their REDO group will be missing or at least incomplete and skipped
+ by recovery, so bad state value will stay. For example, setting
+ key_root before writing the UNDO: the table would have old index
+ pages (they were pinned at time of crash) and a new, thus wrong,
+ key_root.
+ @todo RECOVERY BUG check that all code honours that.
+ */
+ if (translog_flush(state_copies_horizon))
+ goto err;
+ /* now we have cached states and they are WAL-safe*/
+ state_copies_end= state_copy;
+ state_copy= state_copies;
+ }
+
+ /* locate our state among these cached ones */
+ for ( ; state_copy->index != i; state_copy++)
+ DBUG_ASSERT(state_copy < state_copies_end);
+
+ /* OS file descriptors are ints which we stored in 4 bytes */
+ compile_time_assert(sizeof(int) <= 4);
+ /*
+ Protect against maria_close() (which does some memory freeing in
+ MARIA_FILE_BITMAP) with close_lock. intern_lock is not
+ sufficient as we, as well as maria_close(), are going to unlock
+ intern_lock in the middle of manipulating the table. Serializing us and
+ maria_close() should help avoid problems.
+ */
+ pthread_mutex_lock(&share->close_lock);
+ pthread_mutex_lock(&share->intern_lock);
+ /*
+ Tables in a normal state have their two file descriptors open.
+ In some rare cases like REPAIR, some descriptor may be closed or even
+ -1. If that happened, the _ma_state_info_write() may fail. This is
+ prevented by enclosing all all places which close/change kfile.file with
+ intern_lock.
+ */
+ kfile= share->kfile;
+ dfile= share->bitmap.file;
+ /*
+ Ignore table which has no logged writes (all its future log records will
+ be found naturally by Recovery). Ignore obsolete shares (_before_
+ setting themselves to last_version=0 they already did all flush and
+ sync; if we flush their state now we may be flushing an obsolete state
+ onto a newer one (assuming the table has been reopened with a different
+ share but of course same physical index file).
+ */
+ ignore_share= (share->id == 0) | (share->last_version == 0);
+ DBUG_PRINT("info", ("ignore_share: %d", ignore_share));
+ if (!ignore_share)
+ {
+ uint open_file_name_len= share->open_file_name.length + 1;
+ /* remember the descriptors for background flush */
+ *(dfiles_end++)= dfile;
+ *(kfiles_end++)= kfile;
+ /* we will store this table in the record */
+ nb_stored++;
+ int2store(ptr, share->id);
+ ptr+= 2;
+ lsn_store(ptr, share->lsn_of_file_id);
+ ptr+= LSN_STORE_SIZE;
+ /*
+ first_bitmap_with_space is not updated under log's lock, and is
+ important. We would need the bitmap's lock to get it right. Recovery
+ of this is not clear, so we just play safe: write it out as
+ unknown: if crash, _ma_bitmap_init() at next open (for example in
+ Recovery) will convert it to 0 and thus the first insertion will
+ search for free space from the file's first bitmap (0) -
+ under-optimal but safe.
+ If no crash, maria_close() will write the exact value.
+ */
+ state_copy->state.first_bitmap_with_space= ~(ulonglong)0;
+ memcpy(ptr, share->open_file_name.str, open_file_name_len);
+ ptr+= open_file_name_len;
+ if (cmp_translog_addr(share->state.is_of_horizon,
+ checkpoint_start_log_horizon) >= 0)
+ {
+ /*
+ State was flushed recently, it does not hold down the log's
+ low-water mark and will not give avoidable work to Recovery. So we
+ needn't flush it. Also, it is possible that while we copied the
+ state above (under log's lock, without intern_lock) it was being
+ modified in memory or flushed to disk (without log's lock, under
+ intern_lock, like in maria_extra()), so our copy may be incorrect
+ and we should not flush it.
+ It may also be a share which got last_version==0 since we checked
+ last_version; in this case, it flushed its state and the LSN test
+ above will catch it.
+ */
+ }
+ else
+ {
+ /*
+ We could do the state flush only if share->changed, but it's
+ tricky.
+ Consider a maria_write() which has written REDO,UNDO, and before it
+ calls _ma_writeinfo() (setting share->changed=1), checkpoint
+ happens and sees share->changed=0, does not flush state. It is
+ possible that Recovery does not start from before the REDO and thus
+ the state is not recovered. A solution may be to set
+ share->changed=1 under log mutex when writing log records.
+ But as anyway we have another problem below, this optimization would
+ be of little use.
+ */
+ /** @todo flush state only if changed since last checkpoint */
+ DBUG_ASSERT(share->last_version != 0);
+ state_copy->state.is_of_horizon= share->state.is_of_horizon=
+ state_copies_horizon;
+ if (kfile.file >= 0)
+ sync_error|=
+ _ma_state_info_write_sub(kfile.file, &state_copy->state,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET);
+ /*
+ We don't set share->changed=0 because it may interfere with a
+ concurrent _ma_writeinfo() doing share->changed=1 (cancel its
+ effect). The sad consequence is that we will flush the same state at
+ each checkpoint if the table was once written and then not anymore.
+ */
+ }
+ }
+ /*
+ _ma_bitmap_flush_all() may wait, so don't keep intern_lock as
+ otherwise this would deadlock with allocate_and_write_block_record()
+ calling _ma_set_share_data_file_length()
+ */
+ pthread_mutex_unlock(&share->intern_lock);
+
+ if (!ignore_share)
+ {
+ /*
+ share->bitmap is valid because it's destroyed under close_lock which
+ we hold.
+ */
+ if (_ma_bitmap_flush_all(share))
+ {
+ sync_error= 1;
+ /** @todo all write failures should mark table corrupted */
+ ma_message_no_user(0, "checkpoint bitmap page flush failed");
+ }
+ DBUG_ASSERT(share->pagecache == maria_pagecache);
+ }
+ /*
+ Clean up any unused states.
+ TODO: Only do this call if there has been # (10?) ended transactions
+ since last call.
+ We had to release intern_lock to respect lock order with LOCK_trn_list.
+ */
+ _ma_remove_not_visible_states_with_lock(share, FALSE);
+
+ if (share->in_checkpoint & MARIA_CHECKPOINT_SHOULD_FREE_ME)
+ {
+ /*
+ maria_close() left us free the share. When it run it set share->id
+ to 0. As it run before we locked close_lock, we should have seen this
+ and so this assertion should be true:
+ */
+ DBUG_ASSERT(ignore_share);
+ pthread_mutex_destroy(&share->intern_lock);
+ pthread_mutex_unlock(&share->close_lock);
+ pthread_mutex_destroy(&share->close_lock);
+ my_free((uchar *)share, MYF(0));
+ }
+ else
+ {
+ /* share goes back to normal state */
+ share->in_checkpoint= 0;
+ pthread_mutex_unlock(&share->close_lock);
+ }
+
+ /*
+ We do the big disk writes out of intern_lock to not block other
+ users of this table (intern_lock is taken at the start and end of
+ every statement). This means that file descriptors may be invalid
+ (files may have been closed for example by HA_EXTRA_PREPARE_FOR_*
+ under Windows, or REPAIR). This should not be a problem as we use
+ MY_IGNORE_BADFD. Descriptors may even point to other files but then
+ the old blocks (of before the close) must have been flushed for sure,
+ so our flush will flush new blocks (of after the latest open) and that
+ should do no harm.
+ */
+ /*
+ If CHECKPOINT_MEDIUM, this big flush below may result in a
+ serious write burst. Realize that all pages dirtied between the
+ last checkpoint and the one we are doing now, will be flushed at
+ next checkpoint, except those evicted by LRU eviction (depending on
+ the size of the page cache compared to the size of the working data
+ set, eviction may be rare or frequent).
+ We avoid that burst by anticipating: those pages are flushed
+ in bunches spanned regularly over the time interval between now and
+ the next checkpoint, by a background thread. Thus the next checkpoint
+ will have only little flushing to do (CHECKPOINT_MEDIUM should thus be
+ only a little slower than CHECKPOINT_INDIRECT).
+ */
+
+ /*
+ PageCacheFlushConcurrencyBugs
+ Inside the page cache, calls to flush_pagecache_blocks_int() on the same
+ file are serialized. Examples of concurrency bugs which happened when we
+ didn't have this serialization:
+ - maria_chk_size() (via CHECK TABLE) happens concurrently with
+ Checkpoint: Checkpoint is flushing a page: it pins the page and is
+ pre-empted, maria_chk_size() wants to flush this page too so gets an
+ error because Checkpoint pinned this page. Such error makes
+ maria_chk_size() mark the table as corrupted.
+ - maria_close() happens concurrently with Checkpoint:
+ Checkpoint is flushing a page: it registers a request on the page, is
+ pre-empted ; maria_close() flushes this page too with FLUSH_RELEASE:
+ FLUSH_RELEASE will cause a free_block() which assumes the page is in the
+ LRU, but it is not (as Checkpoint registered a request). Crash.
+ - one thread is evicting a page of the file out of the LRU: it marks it
+ iPC_BLOCK_IN_SWITCH and is pre-empted. Then two other threads do flushes
+ of the same file concurrently (like above). Then one flusher sees the
+ page is in switch, removes it from changed_blocks[] and puts it in its
+ first_in_switch, so the other flusher will not see the page at all and
+ return too early. If it's maria_close() which returns too early, then
+ maria_close() may close the file descriptor, and the other flusher, and
+ the evicter will fail to write their page: corruption.
+ */
+
+ if (!ignore_share)
+ {
+ if (filter != NULL)
+ {
+ if ((flush_pagecache_blocks_with_filter(maria_pagecache,
+ &dfile, FLUSH_KEEP_LAZY,
+ filter, &filter_param) &
+ PCFLUSH_ERROR))
+ ma_message_no_user(0, "checkpoint data page flush failed");
+ if ((flush_pagecache_blocks_with_filter(maria_pagecache,
+ &kfile, FLUSH_KEEP_LAZY,
+ filter, &filter_param) &
+ PCFLUSH_ERROR))
+ ma_message_no_user(0, "checkpoint index page flush failed");
+ }
+ /*
+ fsyncs the fd, that's the loooong operation (e.g. max 150 fsync
+ per second, so if you have touched 1000 files it's 7 seconds).
+ */
+ sync_error|=
+ my_sync(dfile.file, MYF(MY_WME | MY_IGNORE_BADFD)) |
+ my_sync(kfile.file, MYF(MY_WME | MY_IGNORE_BADFD));
+ /*
+ in case of error, we continue because writing other tables to disk is
+ still useful.
+ */
+ }
+ }
+
+ if (sync_error)
+ goto err;
+ /* We maybe over-estimated (due to share->id==0 or last_version==0) */
+ DBUG_ASSERT(str->length >= (uint)(ptr - str->str));
+ str->length= (uint)(ptr - str->str);
+ /*
+ As we support max 65k tables open at a time (2-byte short id), we
+ assume uint is enough for the cumulated length of table names; and
+ LEX_STRING::length is uint.
+ */
+ int4store(str->str, nb_stored);
+ error= unmark_tables= 0;
+
+err:
+ if (unlikely(unmark_tables))
+ {
+ /* maria_close() uses THR_LOCK_maria from start to end */
+ pthread_mutex_lock(&THR_LOCK_maria);
+ for (i= 0; i < nb; i++)
+ {
+ MARIA_SHARE *share= distinct_shares[i];
+ if (share->in_checkpoint & MARIA_CHECKPOINT_SHOULD_FREE_ME)
+ {
+ /* maria_close() left us to free the share */
+ pthread_mutex_destroy(&share->intern_lock);
+ my_free((uchar *)share, MYF(0));
+ }
+ else
+ {
+ /* share goes back to normal state */
+ share->in_checkpoint= 0;
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ }
+ my_free((uchar *)distinct_shares, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((uchar *)state_copies, MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(error);
+}
diff --git a/storage/maria/ma_checkpoint.h b/storage/maria/ma_checkpoint.h
new file mode 100644
index 00000000000..69645c6bcda
--- /dev/null
+++ b/storage/maria/ma_checkpoint.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2006,2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ WL#3071 Maria checkpoint
+ First version written by Guilhem Bichot on 2006-04-27.
+ Does not compile yet.
+*/
+
+/* This is the interface of this module. */
+
+typedef enum enum_ma_checkpoint_level {
+ CHECKPOINT_NONE= 0,
+ /* just write dirty_pages, transactions table and sync files */
+ CHECKPOINT_INDIRECT,
+ /* also flush all dirty pages which were already dirty at prev checkpoint */
+ CHECKPOINT_MEDIUM,
+ /* also flush all dirty pages */
+ CHECKPOINT_FULL
+} CHECKPOINT_LEVEL;
+
+C_MODE_START
+int ma_checkpoint_init(ulong interval);
+void ma_checkpoint_end(void);
+int ma_checkpoint_execute(CHECKPOINT_LEVEL level, my_bool no_wait);
+C_MODE_END
+
+/**
+ @brief reads some LSNs with special trickery
+
+ If a 64-bit variable transitions between both halves being zero to both
+ halves being non-zero, and back, this function can be used to do a read of
+ it (without mutex, without atomic load) which always produces a correct
+ (though maybe slightly old) value (even on 32-bit CPUs). The value is at
+ least as new as the latest mutex unlock done by the calling thread.
+ The assumption is that the system sets both 4-byte halves either at the
+ same time, or one after the other (in any order), but NOT some bytes of the
+ first half then some bytes of the second half then the rest of bytes of the
+ first half. With this assumption, the function can detect when it is
+ seeing an inconsistent value.
+
+ @param LSN pointer to the LSN variable to read
+
+ @return LSN part (most significant byte always 0)
+*/
+#if ( SIZEOF_CHARP >= 8 )
+/* 64-bit CPU, 64-bit reads are atomic */
+#define lsn_read_non_atomic LSN_WITH_FLAGS_TO_LSN
+#else
+static inline LSN lsn_read_non_atomic_32(const volatile LSN *x)
+{
+ /*
+ 32-bit CPU, 64-bit reads may give a mixed of old half and new half (old
+ low bits and new high bits, or the contrary).
+ */
+ for (;;) /* loop until no atomicity problems */
+ {
+ /*
+ Remove most significant byte in case this is a LSN_WITH_FLAGS object.
+ Those flags in TRN::first_undo_lsn break the condition on transitions so
+ they must be removed below.
+ */
+ LSN y= LSN_WITH_FLAGS_TO_LSN(*x);
+ if (likely((y == LSN_IMPOSSIBLE) || LSN_VALID(y)))
+ return y;
+ }
+}
+#define lsn_read_non_atomic(x) lsn_read_non_atomic_32(&x)
+#endif
+
+/**
+ prints a message from a task not connected to any user (checkpoint
+ and recovery for example).
+
+ @param level 0 if error, ME_JUST_WARNING if warning,
+ ME_JUST_INFO if info
+ @param sentence text to write
+*/
+#define ma_message_no_user(level, sentence) \
+ my_printf_error(HA_ERR_GENERIC, "Maria engine: %s", MYF(level), sentence)
diff --git a/storage/maria/ma_checksum.c b/storage/maria/ma_checksum.c
new file mode 100644
index 00000000000..61ec638053a
--- /dev/null
+++ b/storage/maria/ma_checksum.c
@@ -0,0 +1,89 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Calculate a checksum for a row */
+
+#include "maria_def.h"
+
+/**
+ Calculate a checksum for the record
+
+ _ma_checksum()
+ @param info Maria handler
+ @param record Record
+
+ @note
+ To ensure that the checksum is independent of the row format
+ we need to always calculate the checksum in the original field order.
+
+ @return checksum
+*/
+
+ha_checksum _ma_checksum(MARIA_HA *info, const uchar *record)
+{
+ ha_checksum crc=0;
+ uint i,end;
+ MARIA_COLUMNDEF *base_column= info->s->columndef;
+ uint16 *column_nr= info->s->column_nr;
+
+ if (info->s->base.null_bytes)
+ crc= my_checksum(crc, record, info->s->base.null_bytes);
+
+ for (i= 0, end= info->s->base.fields ; i < end ; i++)
+ {
+ MARIA_COLUMNDEF *column= base_column + column_nr[i];
+ const uchar *pos;
+ ulong length;
+
+ if (record[column->null_pos] & column->null_bit)
+ continue; /* Null field */
+
+ pos= record + column->offset;
+ switch (column->type) {
+ case FIELD_BLOB:
+ {
+ uint blob_size_length= column->length- portable_sizeof_char_ptr;
+ length= _ma_calc_blob_length(blob_size_length, pos);
+ if (length)
+ {
+ memcpy((char*) &pos, pos + blob_size_length, sizeof(char*));
+ crc= my_checksum(crc, pos, length);
+ }
+ continue;
+ }
+ case FIELD_VARCHAR:
+ {
+ uint pack_length= column->fill_length;
+ if (pack_length == 1)
+ length= (ulong) *pos;
+ else
+ length= uint2korr(pos);
+ pos+= pack_length; /* Skip length information */
+ break;
+ }
+ default:
+ length= column->length;
+ break;
+ }
+ crc= my_checksum(crc, pos, length);
+ }
+ return crc;
+}
+
+
+ha_checksum _ma_static_checksum(MARIA_HA *info, const uchar *pos)
+{
+ return my_checksum(0, pos, info->s->base.reclength);
+}
diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c
new file mode 100644
index 00000000000..235b37f7030
--- /dev/null
+++ b/storage/maria/ma_close.c
@@ -0,0 +1,207 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* close a isam-database */
+/*
+ TODO:
+ We need to have a separate mutex on the closed file to allow other threads
+ to open other files during the time we flush the cache and close this file
+*/
+
+#include "maria_def.h"
+
+int maria_close(register MARIA_HA *info)
+{
+ int error=0,flag;
+ my_bool share_can_be_freed= FALSE;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_close");
+ DBUG_PRINT("enter",("base: 0x%lx reopen: %u locks: %u",
+ (long) info, (uint) share->reopen,
+ (uint) share->tot_locks));
+
+ /* Check that we have unlocked key delete-links properly */
+ DBUG_ASSERT(info->key_del_used == 0);
+
+ pthread_mutex_lock(&THR_LOCK_maria);
+ if (info->lock_type == F_EXTRA_LCK)
+ info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
+
+ if (share->reopen == 1 && share->kfile.file >= 0)
+ _ma_decrement_open_count(info);
+
+ if (info->lock_type != F_UNLCK)
+ {
+ if (maria_lock_database(info,F_UNLCK))
+ error=my_errno;
+ }
+ pthread_mutex_lock(&share->close_lock);
+ pthread_mutex_lock(&share->intern_lock);
+
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ share->r_locks--;
+ share->tot_locks--;
+ }
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ if (end_io_cache(&info->rec_cache))
+ error=my_errno;
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ }
+ flag= !--share->reopen;
+ maria_open_list=list_delete(maria_open_list,&info->open_list);
+
+ my_free(info->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
+ (*share->end)(info);
+
+ if (flag)
+ {
+ /* Last close of file; Flush everything */
+
+ /* Check that we don't have any dangling pointers from the transaction */
+ DBUG_ASSERT(share->in_trans == 0);
+
+ if (share->kfile.file >= 0)
+ {
+ if ((*share->once_end)(share))
+ error= my_errno;
+ if (flush_pagecache_blocks(share->pagecache, &share->kfile,
+ (share->temporary ?
+ FLUSH_IGNORE_CHANGED :
+ FLUSH_RELEASE)))
+ error= my_errno;
+#ifdef HAVE_MMAP
+ if (share->file_map)
+ _ma_unmap_file(info);
+#endif
+ /*
+ If we are crashed, we can safely flush the current state as it will
+ not change the crashed state.
+ We can NOT write the state in other cases as other threads
+ may be using the file at this point
+ IF using --external-locking, which does not apply to Maria.
+ */
+ if (((share->changed && share->base.born_transactional) ||
+ maria_is_crashed(info)))
+ {
+ /*
+ State must be written to file as it was not done at table's
+ unlocking.
+ */
+ if (_ma_state_info_write(share, MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET))
+ error= my_errno;
+ }
+ /*
+ File must be synced as it is going out of the maria_open_list and so
+ becoming unknown to future Checkpoints.
+ */
+ if (share->now_transactional && my_sync(share->kfile.file, MYF(MY_WME)))
+ error= my_errno;
+ if (my_close(share->kfile.file, MYF(0)))
+ error= my_errno;
+ }
+#ifdef THREAD
+ thr_lock_delete(&share->lock);
+ (void) pthread_mutex_destroy(&share->key_del_lock);
+ {
+ int i,keys;
+ keys = share->state.header.keys;
+ VOID(rwlock_destroy(&share->mmap_lock));
+ for(i=0; i<keys; i++) {
+ VOID(rwlock_destroy(&share->keyinfo[i].root_lock));
+ }
+ }
+#endif
+ DBUG_ASSERT(share->now_transactional == share->base.born_transactional);
+ /*
+ We assign -1 because checkpoint does not need to flush (in case we
+ have concurrent checkpoint if no then we do not need it here also)
+ */
+ share->kfile.file= -1;
+
+ /*
+ Remember share->history for future opens
+
+ We have to unlock share->intern_lock then lock it after
+ LOCK_trn_list (trnman_lock()) to avoid dead locks.
+ */
+ pthread_mutex_unlock(&share->intern_lock);
+ _ma_remove_not_visible_states_with_lock(share, TRUE);
+ pthread_mutex_lock(&share->intern_lock);
+
+ if (share->in_checkpoint & MARIA_CHECKPOINT_LOOKS_AT_ME)
+ {
+ /* we cannot my_free() the share, Checkpoint would see a bad pointer */
+ share->in_checkpoint|= MARIA_CHECKPOINT_SHOULD_FREE_ME;
+ }
+ else
+ share_can_be_freed= TRUE;
+
+ if (share->state_history)
+ {
+ MARIA_STATE_HISTORY_CLOSED *history;
+ /*
+ Here we ignore the unlikely case that we don't have memory to
+ store the state. In the worst case what happens is that any transaction
+ that tries to access this table will get a wrong status information.
+ */
+ if ((history= (MARIA_STATE_HISTORY_CLOSED *)
+ my_malloc(sizeof(*history), MYF(MY_WME))))
+ {
+ history->create_rename_lsn= share->state.create_rename_lsn;
+ history->state_history= share->state_history;
+ if (my_hash_insert(&maria_stored_state, (uchar*) history))
+ my_free(history, MYF(0));
+ }
+ /* Marker for concurrent checkpoint */
+ share->state_history= 0;
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ pthread_mutex_unlock(&share->intern_lock);
+ pthread_mutex_unlock(&share->close_lock);
+ if (share_can_be_freed)
+ {
+ (void) pthread_mutex_destroy(&share->intern_lock);
+ (void) pthread_mutex_destroy(&share->close_lock);
+ my_free((uchar *)share, MYF(0));
+ /*
+ If share cannot be freed, it's because checkpoint has previously
+ recorded to include this share in the checkpoint and so is soon going to
+ look at some of its content (share->in_checkpoint/id/last_version).
+ */
+ }
+ my_free(info->ftparser_param, MYF(MY_ALLOW_ZERO_PTR));
+ if (info->dfile.file >= 0)
+ {
+ /*
+ This is outside of mutex so would confuse a concurrent
+ Checkpoint. Fortunately in BLOCK_RECORD we close earlier under mutex.
+ */
+ if (my_close(info->dfile.file, MYF(0)))
+ error= my_errno;
+ }
+
+ delete_dynamic(&info->pinned_pages);
+ my_free(info, MYF(0));
+
+ if (error)
+ {
+ DBUG_PRINT("error", ("Got error on close: %d", my_errno));
+ DBUG_RETURN(my_errno= error);
+ }
+ DBUG_RETURN(0);
+} /* maria_close */
diff --git a/storage/maria/ma_commit.c b/storage/maria/ma_commit.c
new file mode 100644
index 00000000000..70bc668a220
--- /dev/null
+++ b/storage/maria/ma_commit.c
@@ -0,0 +1,129 @@
+/* Copyright (C) 2007-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "trnman.h"
+
+/**
+ writes a COMMIT record to log and commits transaction in memory
+
+ @param trn transaction
+
+ @return Operation status
+ @retval 0 ok
+ @retval 1 error (disk error or out of memory)
+*/
+
+int ma_commit(TRN *trn)
+{
+ int res;
+ LSN commit_lsn;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS];
+ DBUG_ENTER("ma_commit");
+
+ DBUG_ASSERT(trn->rec_lsn == LSN_IMPOSSIBLE);
+ if (trn->undo_lsn == 0) /* no work done, rollback (cheaper than commit) */
+ DBUG_RETURN(trnman_rollback_trn(trn));
+ /*
+ - if COMMIT record is written before trnman_commit_trn():
+ if Checkpoint comes in the middle it will see trn is not committed,
+ then if crash, Recovery might roll back trn (if min(rec_lsn) is after
+ COMMIT record) and this is not an issue as
+ * transaction's updates were not made visible to other transactions
+ * "commit ok" was not sent to client
+ Alternatively, Recovery might commit trn (if min(rec_lsn) is before COMMIT
+ record), which is ok too. All in all it means that "trn committed" is not
+ 100% equal to "COMMIT record written".
+ - if COMMIT record is written after trnman_commit_trn():
+ if crash happens between the two, trn will be rolled back which is an
+ issue (transaction's updates were made visible to other transactions).
+ So we need to go the first way.
+
+ Note that we have to use | here to ensure that all calls are made.
+ */
+
+ /*
+ We do not store "thd->transaction.xid_state.xid" for now, it will be
+ needed only when we support XA.
+ */
+ res= (translog_write_record(&commit_lsn, LOGREC_COMMIT,
+ trn, NULL, 0,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL) |
+ translog_flush(commit_lsn));
+
+ DBUG_EXECUTE_IF("maria_sleep_in_commit",
+ {
+ DBUG_PRINT("info", ("maria_sleep_in_commit"));
+ sleep(3);
+ });
+ res|= trnman_commit_trn(trn);
+
+
+ /*
+ Note: if trnman_commit_trn() fails above, we have already
+ written the COMMIT record, so Checkpoint and Recovery will see the
+ transaction as committed.
+ */
+ DBUG_RETURN(res);
+}
+
+
+/**
+ Writes a COMMIT record for a transaciton associated with a file
+
+ @param info Maria handler
+
+ @return Operation status
+ @retval 0 ok
+ @retval # error (disk error or out of memory)
+*/
+
+int maria_commit(MARIA_HA *info)
+{
+ return info->s->now_transactional ? ma_commit(info->trn) : 0;
+}
+
+
+/**
+ Starts a transaction on a file handle
+
+ @param info Maria handler
+
+ @return Operation status
+ @retval 0 ok
+ @retval # Error code.
+
+ @note this can be used only in single-threaded programs (tests),
+ because we create a transaction (trnman_new_trn) with WT_THD=0.
+ XXX it needs to be fixed when we'll start using maria_begin from SQL.
+*/
+
+int maria_begin(MARIA_HA *info)
+{
+ DBUG_ENTER("maria_begin");
+
+ if (info->s->now_transactional)
+ {
+ TRN *trn= trnman_new_trn(0);
+ if (unlikely(!trn))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+ DBUG_PRINT("info", ("TRN set to 0x%lx", (ulong) trn));
+ _ma_set_trn_for_table(info, trn);
+ }
+ DBUG_RETURN(0);
+}
+
diff --git a/storage/maria/ma_commit.h b/storage/maria/ma_commit.h
new file mode 100644
index 00000000000..2c57c73fd7a
--- /dev/null
+++ b/storage/maria/ma_commit.h
@@ -0,0 +1,18 @@
+/* Copyright (C) 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+C_MODE_START
+int ma_commit(TRN *trn);
+C_MODE_END
diff --git a/storage/maria/ma_control_file.c b/storage/maria/ma_control_file.c
new file mode 100644
index 00000000000..1e1fc34c77e
--- /dev/null
+++ b/storage/maria/ma_control_file.c
@@ -0,0 +1,606 @@
+/* Copyright (C) 2007 MySQL AB & Guilhem Bichot & Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ WL#3234 Maria control file
+ First version written by Guilhem Bichot on 2006-04-27.
+*/
+
+#ifndef EXTRACT_DEFINITIONS
+#include "maria_def.h"
+#include "ma_checkpoint.h"
+#endif
+
+/*
+ A control file contains the following objects:
+
+Start of create time variables (at start of file):
+ - Magic string (including version number of Maria control file)
+ - Uuid
+ - Size of create time part
+ - Size of dynamic part
+ - Maria block size
+..... Here we can add new variables without changing format
+ - Checksum of create time part (last of block)
+
+Start of changeable part:
+ - Checksum of changeable part
+ - LSN of last checkpoint
+ - Number of last log file
+ - Max trid in control file (since Maria 1.5 May 2008)
+ - Number of consecutive recovery failures (since Maria 1.5 May 2008)
+..... Here we can add new variables without changing format
+
+The idea is that one can add new variables to the control file and still
+use it with old program versions. If one needs to do an incompatible change
+one should increment the control file version number.
+*/
+
+/* Total size should be < sector size for atomic write operation */
+#define CF_MAX_SIZE 512
+#define CF_MIN_SIZE (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + \
+ CF_CHECKSUM_SIZE * 2 + CF_LSN_SIZE + CF_FILENO_SIZE)
+
+/* Create time variables */
+#define CF_MAGIC_STRING "\xfe\xfe\xc"
+#define CF_MAGIC_STRING_OFFSET 0
+#define CF_MAGIC_STRING_SIZE (sizeof(CF_MAGIC_STRING)-1)
+#define CF_VERSION_OFFSET (CF_MAGIC_STRING_OFFSET + CF_MAGIC_STRING_SIZE)
+#define CF_VERSION_SIZE 1
+#define CF_UUID_OFFSET (CF_VERSION_OFFSET + CF_VERSION_SIZE)
+#define CF_UUID_SIZE MY_UUID_SIZE
+#define CF_CREATE_TIME_SIZE_OFFSET (CF_UUID_OFFSET + CF_UUID_SIZE)
+#define CF_SIZE_SIZE 2
+#define CF_CHANGEABLE_SIZE_OFFSET (CF_CREATE_TIME_SIZE_OFFSET + CF_SIZE_SIZE)
+#define CF_BLOCKSIZE_OFFSET (CF_CHANGEABLE_SIZE_OFFSET + CF_SIZE_SIZE)
+#define CF_BLOCKSIZE_SIZE 2
+
+#define CF_CREATE_TIME_TOTAL_SIZE (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + \
+ CF_CHECKSUM_SIZE)
+
+/*
+ Start of the part that changes during execution
+ This is stored at offset uint2korr(file[CF_CHANGEABLE_SIZE])
+*/
+#define CF_CHECKSUM_OFFSET 0
+#define CF_CHECKSUM_SIZE 4
+#define CF_LSN_OFFSET (CF_CHECKSUM_OFFSET + CF_CHECKSUM_SIZE)
+#define CF_LSN_SIZE LSN_STORE_SIZE
+#define CF_FILENO_OFFSET (CF_LSN_OFFSET + CF_LSN_SIZE)
+#define CF_FILENO_SIZE 4
+#define CF_MAX_TRID_OFFSET (CF_FILENO_OFFSET + CF_FILENO_SIZE)
+#define CF_MAX_TRID_SIZE TRANSID_SIZE
+#define CF_RECOV_FAIL_OFFSET (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE)
+#define CF_RECOV_FAIL_SIZE 1
+#define CF_CHANGEABLE_TOTAL_SIZE (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE)
+
+/*
+ The following values should not be changed, except when changing version
+ number of the maria control file. These are the minimum sizes of the
+ parts the code can handle.
+*/
+
+#define CF_MIN_CREATE_TIME_TOTAL_SIZE \
+(CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + CF_CHECKSUM_SIZE)
+#define CF_MIN_CHANGEABLE_TOTAL_SIZE \
+(CF_FILENO_OFFSET + CF_FILENO_SIZE)
+
+#ifndef EXTRACT_DEFINITIONS
+
+/* This module owns these two vars. */
+/**
+ This LSN serves for the two-checkpoint rule, and also to find the
+ checkpoint record when doing a recovery.
+*/
+LSN last_checkpoint_lsn= LSN_IMPOSSIBLE;
+uint32 last_logno= FILENO_IMPOSSIBLE;
+/**
+ The maximum transaction id given to a transaction. It is only updated at
+ clean shutdown (in case of crash, logs have better information).
+*/
+TrID max_trid_in_control_file= 0;
+
+/**
+ Number of consecutive log or recovery failures. Reset to 0 after recovery's
+ success.
+*/
+uint8 recovery_failures= 0;
+
+/**
+ @brief If log's lock should be asserted when writing to control file.
+
+ Can be re-used by any function which needs to be thread-safe except when
+ it is called at startup.
+*/
+my_bool maria_multi_threaded= FALSE;
+/** @brief if currently doing a recovery */
+my_bool maria_in_recovery= FALSE;
+
+/**
+ Control file is less then 512 bytes (a disk sector),
+ to be as atomic as possible
+*/
+static int control_file_fd= -1;
+
+static uint cf_create_time_size;
+static uint cf_changeable_size;
+
+/**
+ @brief Create Maria control file
+*/
+
+static CONTROL_FILE_ERROR create_control_file(const char *name,
+ int open_flags)
+{
+ uint32 sum;
+ uchar buffer[CF_CREATE_TIME_TOTAL_SIZE];
+ DBUG_ENTER("maria_create_control_file");
+
+ if ((control_file_fd= my_create(name, 0,
+ open_flags,
+ MYF(MY_SYNC_DIR | MY_WME))) < 0)
+ DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
+
+ /* Reset variables, as we are creating the file */
+ cf_create_time_size= CF_CREATE_TIME_TOTAL_SIZE;
+ cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE;
+
+ /* Create unique uuid for the control file */
+ my_uuid_init((ulong) &buffer, (ulong) &maria_uuid);
+ my_uuid(maria_uuid);
+
+ /* Prepare and write the file header */
+ memcpy(buffer, CF_MAGIC_STRING, CF_MAGIC_STRING_SIZE);
+ buffer[CF_VERSION_OFFSET]= CONTROL_FILE_VERSION;
+ memcpy(buffer + CF_UUID_OFFSET, maria_uuid, CF_UUID_SIZE);
+ int2store(buffer + CF_CREATE_TIME_SIZE_OFFSET, cf_create_time_size);
+ int2store(buffer + CF_CHANGEABLE_SIZE_OFFSET, cf_changeable_size);
+
+ /* Write create time variables */
+ int2store(buffer + CF_BLOCKSIZE_OFFSET, maria_block_size);
+
+ /* Store checksum for create time parts */
+ sum= (uint32) my_checksum(0, buffer, cf_create_time_size -
+ CF_CHECKSUM_SIZE);
+ int4store(buffer + cf_create_time_size - CF_CHECKSUM_SIZE, sum);
+
+ if (my_pwrite(control_file_fd, buffer, cf_create_time_size,
+ 0, MYF(MY_FNABP | MY_WME)))
+ DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
+
+ /*
+ To be safer we should make sure that there are no logs or data/index
+ files around (indeed it could be that the control file alone was deleted
+ or not restored, and we should not go on with life at this point).
+
+ Things should still be relatively safe as if someone tries to use
+ an old table with a new control file the different uuid:s between
+ the files will cause ma_open() to generate an HA_ERR_OLD_FILE
+ error. When used from mysqld this will cause the table to be open
+ in repair mode which will remove all dependencies between the
+ table and the old control file.
+
+ We could have a tool which can rebuild the control file, by reading the
+ directory of logs, finding the newest log, reading it to find last
+ checkpoint... Slow but can save your db. For this to be possible, we
+ must always write to the control file right after writing the checkpoint
+ log record, and do nothing in between (i.e. the checkpoint must be
+ usable as soon as it has been written to the log).
+ */
+
+ /* init the file with these "undefined" values */
+ DBUG_RETURN(ma_control_file_write_and_force(LSN_IMPOSSIBLE,
+ FILENO_IMPOSSIBLE, 0, 0));
+}
+
+
+/**
+ Locks control file exclusively. This is kept for the duration of the engine
+ process, to prevent another Maria instance to write to our logs or control
+ file.
+*/
+
+static int lock_control_file(const char *name)
+{
+ uint retry= 0;
+ /*
+ On Windows, my_lock() uses locking() which is mandatory locking and so
+ prevents maria-recovery.test from copying the control file. And in case of
+ crash, it may take a while for Windows to unlock file, causing downtime.
+ */
+ /**
+ @todo BUG We should explore my_sopen(_SH_DENYWRD) to open or create the
+ file under Windows.
+ */
+#ifndef __WIN__
+ /*
+ We can't here use the automatic wait in my_lock() as the alarm thread
+ may not yet exists.
+ */
+ while (my_lock(control_file_fd, F_WRLCK, 0L, F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK | MY_NO_WAIT)))
+ {
+ if (retry == 0)
+ my_printf_error(HA_ERR_INITIALIZATION,
+ "Can't lock maria control file '%s' for exclusive use, "
+ "error: %d. Will retry for %d seconds", 0,
+ name, my_errno, MARIA_MAX_CONTROL_FILE_LOCK_RETRY);
+ if (retry++ > MARIA_MAX_CONTROL_FILE_LOCK_RETRY)
+ return 1;
+ sleep(1);
+ }
+#endif
+ return 0;
+}
+
+
+/*
+ @brief Initialize control file subsystem
+
+ Looks for the control file. If none and creation is requested, creates file.
+ If present, reads it to find out last checkpoint's LSN and last log, updates
+ the last_checkpoint_lsn and last_logno global variables.
+ Called at engine's start.
+
+ @note
+ The format of the control file is defined in the comments and defines
+ at the start of this file.
+
+ @param create_if_missing create file if not found
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error (in which case the file is left closed)
+*/
+
+CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
+ my_bool print_error)
+{
+ uchar buffer[CF_MAX_SIZE];
+ char name[FN_REFLEN], errmsg_buff[256];
+ const char *errmsg, *lock_failed_errmsg= "Could not get an exclusive lock;"
+ " file is probably in use by another process";
+ uint new_cf_create_time_size, new_cf_changeable_size, new_block_size;
+ my_off_t file_size;
+ int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR;
+ int error= CONTROL_FILE_UNKNOWN_ERROR;
+ DBUG_ENTER("ma_control_file_open");
+
+ /*
+ If you change sizes in the #defines, you at least have to change the
+ "*store" and "*korr" calls in this file, and can even create backward
+ compatibility problems. Beware!
+ */
+ DBUG_ASSERT(CF_LSN_SIZE == (3+4));
+ DBUG_ASSERT(CF_FILENO_SIZE == 4);
+
+ if (control_file_fd >= 0) /* already open */
+ DBUG_RETURN(0);
+
+ if (fn_format(name, CONTROL_FILE_BASE_NAME,
+ maria_data_root, "", MYF(MY_WME)) == NullS)
+ DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
+
+ if (my_access(name,F_OK))
+ {
+ CONTROL_FILE_ERROR create_error;
+ if (!create_if_missing)
+ {
+ error= CONTROL_FILE_MISSING;
+ errmsg= "Can't find file";
+ goto err;
+ }
+ if ((create_error= create_control_file(name, open_flags)))
+ {
+ error= create_error;
+ errmsg= "Can't create file";
+ goto err;
+ }
+ if (lock_control_file(name))
+ {
+ errmsg= lock_failed_errmsg;
+ goto err;
+ }
+ goto ok;
+ }
+
+ /* Otherwise, file exists */
+
+ if ((control_file_fd= my_open(name, open_flags, MYF(MY_WME))) < 0)
+ {
+ errmsg= "Can't open file";
+ goto err;
+ }
+
+ if (lock_control_file(name)) /* lock it before reading content */
+ {
+ errmsg= lock_failed_errmsg;
+ goto err;
+ }
+
+ file_size= my_seek(control_file_fd, 0, SEEK_END, MYF(MY_WME));
+ if (file_size == MY_FILEPOS_ERROR)
+ {
+ errmsg= "Can't read size";
+ goto err;
+ }
+ if (file_size < CF_MIN_SIZE)
+ {
+ /*
+ Given that normally we write only a sector and it's atomic, the only
+ possibility for a file to be of too short size is if we crashed at the
+ very first startup, between file creation and file write. Quite unlikely
+ (and can be made even more unlikely by doing this: create a temp file,
+ write it, and then rename it to be the control file).
+ What's more likely is if someone forgot to restore the control file,
+ just did a "touch control" to try to get Maria to start, or if the
+ disk/filesystem has a problem.
+ So let's be rigid.
+ */
+ error= CONTROL_FILE_TOO_SMALL;
+ errmsg= "Size of control file is smaller than expected";
+ goto err;
+ }
+
+ /* Check if control file is unexpectedly big */
+ if (file_size > CF_MAX_SIZE)
+ {
+ error= CONTROL_FILE_TOO_BIG;
+ errmsg= "File size bigger than expected";
+ goto err;
+ }
+
+ if (my_pread(control_file_fd, buffer, (size_t)file_size, 0, MYF(MY_FNABP)))
+ {
+ errmsg= "Can't read file";
+ goto err;
+ }
+
+ if (memcmp(buffer + CF_MAGIC_STRING_OFFSET,
+ CF_MAGIC_STRING, CF_MAGIC_STRING_SIZE))
+ {
+ error= CONTROL_FILE_BAD_MAGIC_STRING;
+ errmsg= "Missing valid id at start of file. File is not a valid maria control file";
+ goto err;
+ }
+
+ if (buffer[CF_VERSION_OFFSET] > CONTROL_FILE_VERSION)
+ {
+ error= CONTROL_FILE_BAD_VERSION;
+ sprintf(errmsg_buff, "File is from a future maria system: %d. Current version is: %d",
+ (int) buffer[CF_VERSION_OFFSET], CONTROL_FILE_VERSION);
+ errmsg= errmsg_buff;
+ goto err;
+ }
+
+ new_cf_create_time_size= uint2korr(buffer + CF_CREATE_TIME_SIZE_OFFSET);
+ new_cf_changeable_size= uint2korr(buffer + CF_CHANGEABLE_SIZE_OFFSET);
+
+ if (new_cf_create_time_size < CF_MIN_CREATE_TIME_TOTAL_SIZE ||
+ new_cf_changeable_size < CF_MIN_CHANGEABLE_TOTAL_SIZE ||
+ new_cf_create_time_size + new_cf_changeable_size != file_size)
+ {
+ error= CONTROL_FILE_INCONSISTENT_INFORMATION;
+ errmsg= "Sizes stored in control file are inconsistent";
+ goto err;
+ }
+
+ new_block_size= uint2korr(buffer + CF_BLOCKSIZE_OFFSET);
+ if (new_block_size != maria_block_size)
+ {
+ error= CONTROL_FILE_WRONG_BLOCKSIZE;
+ sprintf(errmsg_buff,
+ "Block size in control file (%u) is different than given maria_block_size: %u",
+ new_block_size, (uint) maria_block_size);
+ errmsg= errmsg_buff;
+ goto err;
+ }
+
+ if (my_checksum(0, buffer, new_cf_create_time_size - CF_CHECKSUM_SIZE) !=
+ uint4korr(buffer + new_cf_create_time_size - CF_CHECKSUM_SIZE))
+ {
+ error= CONTROL_FILE_BAD_HEAD_CHECKSUM;
+ errmsg= "Fixed part checksum mismatch";
+ goto err;
+ }
+
+ if (my_checksum(0, buffer + new_cf_create_time_size + CF_CHECKSUM_SIZE,
+ new_cf_changeable_size - CF_CHECKSUM_SIZE) !=
+ uint4korr(buffer + new_cf_create_time_size))
+ {
+ error= CONTROL_FILE_BAD_CHECKSUM;
+ errmsg= "Changeable part (end of control file) checksum mismatch";
+ goto err;
+ }
+
+ memcpy(maria_uuid, buffer + CF_UUID_OFFSET, CF_UUID_SIZE);
+ cf_create_time_size= new_cf_create_time_size;
+ cf_changeable_size= new_cf_changeable_size;
+ last_checkpoint_lsn= lsn_korr(buffer + new_cf_create_time_size +
+ CF_LSN_OFFSET);
+ last_logno= uint4korr(buffer + new_cf_create_time_size + CF_FILENO_OFFSET);
+ if (new_cf_changeable_size >= (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE))
+ max_trid_in_control_file=
+ transid_korr(buffer + new_cf_create_time_size + CF_MAX_TRID_OFFSET);
+ if (new_cf_changeable_size >= (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE))
+ recovery_failures=
+ (buffer + new_cf_create_time_size + CF_RECOV_FAIL_OFFSET)[0];
+
+ok:
+ DBUG_RETURN(0);
+
+err:
+ if (print_error)
+ my_printf_error(HA_ERR_INITIALIZATION,
+ "Got error '%s' when trying to use maria control file "
+ "'%s'", 0, errmsg, name);
+ ma_control_file_end(); /* will unlock file if needed */
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Write information durably to the control file; stores this information into
+ the last_checkpoint_lsn, last_logno, max_trid_in_control_file,
+ recovery_failures global variables.
+ Called when we have created a new log (after syncing this log's creation),
+ when we have written a checkpoint (after syncing this log record), at
+ shutdown (for storing trid in case logs are soon removed by user), and
+ before and after recovery (to store recovery_failures).
+ Variables last_checkpoint_lsn and last_logno must be protected by caller
+ using log's lock, unless this function is called at startup.
+
+ SYNOPSIS
+ ma_control_file_write_and_force()
+ last_checkpoint_lsn_arg LSN of last checkpoint
+ last_logno_arg last log file number
+ max_trid_arg maximum transaction longid
+ recovery_failures_arg consecutive recovery failures
+
+ NOTE
+ We always want to do one single my_pwrite() here to be as atomic as
+ possible.
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+int ma_control_file_write_and_force(LSN last_checkpoint_lsn_arg,
+ uint32 last_logno_arg,
+ TrID max_trid_arg,
+ uint8 recovery_failures_arg)
+{
+ uchar buffer[CF_MAX_SIZE];
+ uint32 sum;
+ my_bool no_need_sync;
+ DBUG_ENTER("ma_control_file_write_and_force");
+
+ /*
+ We don't need to sync if this is just an increase of
+ recovery_failures: it's even good if that counter is not increased on disk
+ in case of power or hardware failure (less false positives when removing
+ logs).
+ */
+ no_need_sync= ((last_checkpoint_lsn == last_checkpoint_lsn_arg) &&
+ (last_logno == last_logno_arg) &&
+ (max_trid_in_control_file == max_trid_arg) &&
+ (recovery_failures_arg > 0));
+
+ if (control_file_fd < 0)
+ DBUG_RETURN(1);
+
+#ifndef DBUG_OFF
+ if (maria_multi_threaded)
+ translog_lock_handler_assert_owner();
+#endif
+
+ lsn_store(buffer + CF_LSN_OFFSET, last_checkpoint_lsn_arg);
+ int4store(buffer + CF_FILENO_OFFSET, last_logno_arg);
+ transid_store(buffer + CF_MAX_TRID_OFFSET, max_trid_arg);
+ (buffer + CF_RECOV_FAIL_OFFSET)[0]= recovery_failures_arg;
+
+ if (cf_changeable_size > CF_CHANGEABLE_TOTAL_SIZE)
+ {
+ /*
+ More room than needed for us. Must be a newer version. Clear part which
+ we cannot maintain, so that any future version notices we didn't
+ maintain its extra data.
+ */
+ uint zeroed= cf_changeable_size - CF_CHANGEABLE_TOTAL_SIZE;
+ char msg[150];
+ bzero(buffer + CF_CHANGEABLE_TOTAL_SIZE, zeroed);
+ my_snprintf(msg, sizeof(msg),
+ "Control file must be from a newer version; zero-ing out %u"
+ " unknown bytes in control file at offset %u", zeroed,
+ cf_changeable_size + cf_create_time_size);
+ ma_message_no_user(ME_JUST_WARNING, msg);
+ }
+ else
+ {
+ /* not enough room for what we need to store: enlarge */
+ cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE;
+ }
+ /* Note that the create-time portion is not touched */
+
+ /* Checksum is stored first */
+ compile_time_assert(CF_CHECKSUM_OFFSET == 0);
+ sum= my_checksum(0, buffer + CF_CHECKSUM_SIZE,
+ cf_changeable_size - CF_CHECKSUM_SIZE);
+ int4store(buffer, sum);
+
+ if (my_pwrite(control_file_fd, buffer, cf_changeable_size,
+ cf_create_time_size, MYF(MY_FNABP | MY_WME)) ||
+ (!no_need_sync && my_sync(control_file_fd, MYF(MY_WME))))
+ DBUG_RETURN(1);
+
+ last_checkpoint_lsn= last_checkpoint_lsn_arg;
+ last_logno= last_logno_arg;
+ max_trid_in_control_file= max_trid_arg;
+ recovery_failures= recovery_failures_arg;
+
+ cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE; /* no more warning */
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Free resources taken by control file subsystem
+
+ SYNOPSIS
+ ma_control_file_end()
+*/
+
+int ma_control_file_end(void)
+{
+ int close_error;
+ DBUG_ENTER("ma_control_file_end");
+
+ if (control_file_fd < 0) /* already closed */
+ DBUG_RETURN(0);
+
+#ifndef __WIN__
+ (void) my_lock(control_file_fd, F_UNLCK, 0L, F_TO_EOF,
+ MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK));
+#endif
+
+ close_error= my_close(control_file_fd, MYF(MY_WME));
+ /*
+ As my_close() frees structures even if close() fails, we do the same,
+ i.e. we mark the file as closed in all cases.
+ */
+ control_file_fd= -1;
+ /*
+ As this module owns these variables, closing the module forbids access to
+ them (just a safety):
+ */
+ last_checkpoint_lsn= LSN_IMPOSSIBLE;
+ last_logno= FILENO_IMPOSSIBLE;
+ max_trid_in_control_file= recovery_failures= 0;
+
+ DBUG_RETURN(close_error);
+}
+
+
+/**
+ Tells if control file is initialized.
+*/
+
+my_bool ma_control_file_inited(void)
+{
+ return (control_file_fd >= 0);
+}
+
+#endif /* EXTRACT_DEFINITIONS */
diff --git a/storage/maria/ma_control_file.h b/storage/maria/ma_control_file.h
new file mode 100644
index 00000000000..4cb5527620d
--- /dev/null
+++ b/storage/maria/ma_control_file.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ WL#3234 Maria control file
+ First version written by Guilhem Bichot on 2006-04-27.
+*/
+
+#ifndef _ma_control_file_h
+#define _ma_control_file_h
+
+#define CONTROL_FILE_BASE_NAME "maria_log_control"
+/*
+ Major version for control file. Should only be changed when doing
+ big changes that made the new control file incompatible with all
+ older versions of Maria.
+*/
+#define CONTROL_FILE_VERSION 1
+
+/* Here is the interface of this module */
+
+/*
+ LSN of the last checkoint
+ (if last_checkpoint_lsn == LSN_IMPOSSIBLE then there was never a checkpoint)
+*/
+extern LSN last_checkpoint_lsn;
+/*
+ Last log number (if last_logno == FILENO_IMPOSSIBLE then there is no log
+ file yet)
+*/
+extern uint32 last_logno;
+
+extern TrID max_trid_in_control_file;
+
+extern uint8 recovery_failures;
+
+extern my_bool maria_multi_threaded, maria_in_recovery;
+
+typedef enum enum_control_file_error {
+ CONTROL_FILE_OK= 0,
+ CONTROL_FILE_TOO_SMALL,
+ CONTROL_FILE_TOO_BIG,
+ CONTROL_FILE_BAD_MAGIC_STRING,
+ CONTROL_FILE_BAD_VERSION,
+ CONTROL_FILE_BAD_CHECKSUM,
+ CONTROL_FILE_BAD_HEAD_CHECKSUM,
+ CONTROL_FILE_MISSING,
+ CONTROL_FILE_INCONSISTENT_INFORMATION,
+ CONTROL_FILE_WRONG_BLOCKSIZE,
+ CONTROL_FILE_UNKNOWN_ERROR /* any other error */
+} CONTROL_FILE_ERROR;
+
+C_MODE_START
+CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
+ my_bool print_error);
+int ma_control_file_write_and_force(LSN last_checkpoint_lsn_arg,
+ uint32 last_logno_arg, TrID max_trid_arg,
+ uint8 recovery_failures_arg);
+int ma_control_file_end(void);
+my_bool ma_control_file_inited(void);
+C_MODE_END
+#endif
diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c
new file mode 100644
index 00000000000..d290007c86e
--- /dev/null
+++ b/storage/maria/ma_create.c
@@ -0,0 +1,1419 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Create a MARIA table */
+
+#include "ma_ftdefs.h"
+#include "ma_sp_defs.h"
+#include <my_bit.h>
+#include "ma_blockrec.h"
+#include "trnman_public.h"
+
+#if defined(MSDOS) || defined(__WIN__)
+#ifdef __WIN__
+#include <fcntl.h>
+#else
+#include <process.h> /* Prototype for getpid */
+#endif
+#endif
+#include <m_ctype.h>
+
+static int compare_columns(MARIA_COLUMNDEF **a, MARIA_COLUMNDEF **b);
+
+/*
+ Old options is used when recreating database, from maria_chk
+*/
+
+int maria_create(const char *name, enum data_file_type datafile_type,
+ uint keys,MARIA_KEYDEF *keydefs,
+ uint columns, MARIA_COLUMNDEF *columndef,
+ uint uniques, MARIA_UNIQUEDEF *uniquedefs,
+ MARIA_CREATE_INFO *ci,uint flags)
+{
+ register uint i,j;
+ File dfile,file;
+ int errpos,save_errno, create_mode= O_RDWR | O_TRUNC, res;
+ myf create_flag;
+ uint length,max_key_length,packed,pack_bytes,pointer,real_length_diff,
+ key_length,info_length,key_segs,options,min_key_length,
+ base_pos,long_varchar_count,varchar_length,
+ unique_key_parts,fulltext_keys,offset, not_block_record_extra_length;
+ uint max_field_lengths, extra_header_size, column_nr;
+ ulong reclength, real_reclength,min_pack_length;
+ char filename[FN_REFLEN], linkname[FN_REFLEN], *linkname_ptr;
+ ulong pack_reclength;
+ ulonglong tot_length,max_rows, tmp;
+ enum en_fieldtype type;
+ enum data_file_type org_datafile_type= datafile_type;
+ MARIA_SHARE share;
+ MARIA_KEYDEF *keydef,tmp_keydef;
+ MARIA_UNIQUEDEF *uniquedef;
+ HA_KEYSEG *keyseg,tmp_keyseg;
+ MARIA_COLUMNDEF *column, *end_column;
+ double *rec_per_key_part;
+ ulong *nulls_per_key_part;
+ uint16 *column_array;
+ my_off_t key_root[HA_MAX_POSSIBLE_KEY], kfile_size_before_extension;
+ MARIA_CREATE_INFO tmp_create_info;
+ my_bool tmp_table= FALSE; /* cache for presence of HA_OPTION_TMP_TABLE */
+ my_bool forced_packed;
+ myf sync_dir= 0;
+ uchar *log_data= NULL;
+ DBUG_ENTER("maria_create");
+ DBUG_PRINT("enter", ("keys: %u columns: %u uniques: %u flags: %u",
+ keys, columns, uniques, flags));
+
+ DBUG_ASSERT(maria_inited);
+ LINT_INIT(dfile);
+ LINT_INIT(file);
+
+ if (!ci)
+ {
+ bzero((char*) &tmp_create_info,sizeof(tmp_create_info));
+ ci=&tmp_create_info;
+ }
+
+ if (keys + uniques > MARIA_MAX_KEY)
+ {
+ DBUG_RETURN(my_errno=HA_WRONG_CREATE_OPTION);
+ }
+ errpos=0;
+ options=0;
+ bzero((uchar*) &share,sizeof(share));
+
+ if (flags & HA_DONT_TOUCH_DATA)
+ {
+ /* We come here from recreate table */
+ org_datafile_type= ci->org_data_file_type;
+ if (!(ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD))
+ options= (ci->old_options &
+ (HA_OPTION_COMPRESS_RECORD | HA_OPTION_PACK_RECORD |
+ HA_OPTION_READ_ONLY_DATA | HA_OPTION_CHECKSUM |
+ HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
+ HA_OPTION_LONG_BLOB_PTR | HA_OPTION_PAGE_CHECKSUM));
+ else
+ {
+ /* Uncompressing rows */
+ options= (ci->old_options &
+ (HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE |
+ HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_LONG_BLOB_PTR |
+ HA_OPTION_PAGE_CHECKSUM));
+ }
+ }
+ else
+ {
+ /* Transactional tables must be of type BLOCK_RECORD */
+ if (ci->transactional)
+ datafile_type= BLOCK_RECORD;
+ }
+
+ if (ci->reloc_rows > ci->max_rows)
+ ci->reloc_rows=ci->max_rows; /* Check if wrong parameter */
+
+ if (!(rec_per_key_part=
+ (double*) my_malloc((keys + uniques)*HA_MAX_KEY_SEG*sizeof(double) +
+ (keys + uniques)*HA_MAX_KEY_SEG*sizeof(ulong) +
+ sizeof(uint16) * columns,
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(my_errno);
+ nulls_per_key_part= (ulong*) (rec_per_key_part +
+ (keys + uniques) * HA_MAX_KEY_SEG);
+ column_array= (uint16*) (nulls_per_key_part +
+ (keys + uniques) * HA_MAX_KEY_SEG);
+
+
+ /* Start by checking fields and field-types used */
+ varchar_length=long_varchar_count=packed= not_block_record_extra_length=
+ pack_reclength= max_field_lengths= 0;
+ reclength= min_pack_length= ci->null_bytes;
+ forced_packed= 0;
+ column_nr= 0;
+
+ for (column= columndef, end_column= column + columns ;
+ column != end_column ;
+ column++)
+ {
+ /* Fill in not used struct parts */
+ column->column_nr= column_nr++;
+ column->offset= reclength;
+ column->empty_pos= 0;
+ column->empty_bit= 0;
+ column->fill_length= column->length;
+ if (column->null_bit)
+ options|= HA_OPTION_NULL_FIELDS;
+
+ reclength+= column->length;
+ type= column->type;
+ if (datafile_type == BLOCK_RECORD)
+ {
+ if (type == FIELD_SKIP_PRESPACE)
+ type= column->type= FIELD_NORMAL; /* SKIP_PRESPACE not supported */
+ if (type == FIELD_NORMAL &&
+ column->length > FULL_PAGE_SIZE(maria_block_size))
+ {
+ /* FIELD_NORMAL can't be split over many blocks, convert to a CHAR */
+ type= column->type= FIELD_SKIP_ENDSPACE;
+ }
+ }
+
+ if (type != FIELD_NORMAL && type != FIELD_CHECK)
+ {
+ column->empty_pos= packed/8;
+ column->empty_bit= (1 << (packed & 7));
+ if (type == FIELD_BLOB)
+ {
+ forced_packed= 1;
+ packed++;
+ share.base.blobs++;
+ if (pack_reclength != INT_MAX32)
+ {
+ if (column->length == 4+portable_sizeof_char_ptr)
+ pack_reclength= INT_MAX32;
+ else
+ {
+ /* Add max possible blob length */
+ pack_reclength+= (1 << ((column->length-
+ portable_sizeof_char_ptr)*8));
+ }
+ }
+ max_field_lengths+= (column->length - portable_sizeof_char_ptr);
+ }
+ else if (type == FIELD_SKIP_PRESPACE ||
+ type == FIELD_SKIP_ENDSPACE)
+ {
+ forced_packed= 1;
+ max_field_lengths+= column->length > 255 ? 2 : 1;
+ not_block_record_extra_length++;
+ packed++;
+ }
+ else if (type == FIELD_VARCHAR)
+ {
+ varchar_length+= column->length-1; /* Used for min_pack_length */
+ pack_reclength++;
+ not_block_record_extra_length++;
+ max_field_lengths++;
+ packed++;
+ column->fill_length= 1;
+ options|= HA_OPTION_NULL_FIELDS; /* Use ma_checksum() */
+
+ /* We must test for 257 as length includes pack-length */
+ if (test(column->length >= 257))
+ {
+ long_varchar_count++;
+ max_field_lengths++;
+ column->fill_length= 2;
+ }
+ }
+ else if (type == FIELD_SKIP_ZERO)
+ packed++;
+ else
+ {
+ if (!column->null_bit)
+ min_pack_length+= column->length;
+ else
+ {
+ /* Only BLOCK_RECORD skips NULL fields for all field values */
+ not_block_record_extra_length+= column->length;
+ }
+ column->empty_pos= 0;
+ column->empty_bit= 0;
+ }
+ }
+ else /* FIELD_NORMAL */
+ {
+ if (!column->null_bit)
+ {
+ min_pack_length+= column->length;
+ share.base.fixed_not_null_fields++;
+ share.base.fixed_not_null_fields_length+= column->length;
+ }
+ else
+ not_block_record_extra_length+= column->length;
+ }
+ }
+
+ if (datafile_type == STATIC_RECORD && forced_packed)
+ {
+ /* Can't use fixed length records, revert to block records */
+ datafile_type= BLOCK_RECORD;
+ }
+
+ if (datafile_type == DYNAMIC_RECORD)
+ options|= HA_OPTION_PACK_RECORD; /* Must use packed records */
+
+ if (datafile_type == STATIC_RECORD)
+ {
+ /* We can't use checksum with static length rows */
+ flags&= ~HA_CREATE_CHECKSUM;
+ options&= ~HA_OPTION_CHECKSUM;
+ min_pack_length= reclength;
+ packed= 0;
+ }
+ else if (datafile_type != BLOCK_RECORD)
+ min_pack_length+= not_block_record_extra_length;
+ else
+ min_pack_length+= 5; /* Min row overhead */
+
+ if (flags & HA_CREATE_TMP_TABLE)
+ {
+ options|= HA_OPTION_TMP_TABLE;
+ tmp_table= TRUE;
+ create_mode|= O_NOFOLLOW;
+ /* "CREATE TEMPORARY" tables are not crash-safe (dropped at restart) */
+ ci->transactional= FALSE;
+ flags&= ~HA_CREATE_PAGE_CHECKSUM;
+ }
+ share.base.null_bytes= ci->null_bytes;
+ share.base.original_null_bytes= ci->null_bytes;
+ share.base.born_transactional= ci->transactional;
+ share.base.max_field_lengths= max_field_lengths;
+ share.base.field_offsets= 0; /* for future */
+
+ if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
+ {
+ options|= HA_OPTION_CHECKSUM;
+ min_pack_length++;
+ pack_reclength++;
+ }
+ if (pack_reclength < INT_MAX32)
+ pack_reclength+= max_field_lengths + long_varchar_count;
+ else
+ pack_reclength= INT_MAX32;
+
+ if (flags & HA_CREATE_DELAY_KEY_WRITE)
+ options|= HA_OPTION_DELAY_KEY_WRITE;
+ if (flags & HA_CREATE_RELIES_ON_SQL_LAYER)
+ options|= HA_OPTION_RELIES_ON_SQL_LAYER;
+ if (flags & HA_CREATE_PAGE_CHECKSUM)
+ options|= HA_OPTION_PAGE_CHECKSUM;
+
+ pack_bytes= (packed + 7) / 8;
+ if (pack_reclength != INT_MAX32)
+ pack_reclength+= reclength+pack_bytes +
+ test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_OPTION_PACK_RECORD));
+ min_pack_length+= pack_bytes;
+ /* Calculate min possible row length for rows-in-block */
+ extra_header_size= MAX_FIXED_HEADER_SIZE;
+ if (ci->transactional)
+ {
+ extra_header_size= TRANS_MAX_FIXED_HEADER_SIZE;
+ DBUG_PRINT("info",("creating a transactional table"));
+ }
+ share.base.min_block_length= (extra_header_size + share.base.null_bytes +
+ pack_bytes);
+ if (!ci->data_file_length && ci->max_rows)
+ {
+ if (pack_reclength == INT_MAX32 ||
+ (~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength)
+ ci->data_file_length= ~(ulonglong) 0;
+ else
+ ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength;
+ }
+ else if (!ci->max_rows)
+ {
+ if (datafile_type == BLOCK_RECORD)
+ {
+ uint rows_per_page= ((maria_block_size - PAGE_OVERHEAD_SIZE) /
+ (min_pack_length + extra_header_size +
+ DIR_ENTRY_SIZE));
+ ulonglong data_file_length= ci->data_file_length;
+ if (!data_file_length)
+ data_file_length= ((((ulonglong) 1 << ((BLOCK_RECORD_POINTER_SIZE-1) *
+ 8)) -1) * maria_block_size);
+ if (rows_per_page > 0)
+ {
+ set_if_smaller(rows_per_page, MAX_ROWS_PER_PAGE);
+ ci->max_rows= data_file_length / maria_block_size * rows_per_page;
+ }
+ else
+ ci->max_rows= data_file_length / (min_pack_length +
+ extra_header_size +
+ DIR_ENTRY_SIZE);
+ }
+ else
+ ci->max_rows=(ha_rows) (ci->data_file_length/(min_pack_length +
+ ((options &
+ HA_OPTION_PACK_RECORD) ?
+ 3 : 0)));
+ }
+ max_rows= (ulonglong) ci->max_rows;
+ if (datafile_type == BLOCK_RECORD)
+ {
+ /*
+ The + 1 is for record position withing page
+ The / 2 is because we need one bit for knowing if there is transid's
+ after the row pointer
+ */
+ pointer= maria_get_pointer_length((ci->data_file_length /
+ (maria_block_size * 2)), 3) + 1;
+ set_if_smaller(pointer, BLOCK_RECORD_POINTER_SIZE);
+
+ if (!max_rows)
+ max_rows= (((((ulonglong) 1 << ((pointer-1)*8)) -1) * maria_block_size) /
+ min_pack_length / 2);
+ }
+ else
+ {
+ if (datafile_type != STATIC_RECORD)
+ pointer= maria_get_pointer_length(ci->data_file_length,
+ maria_data_pointer_size);
+ else
+ pointer= maria_get_pointer_length(ci->max_rows, maria_data_pointer_size);
+ if (!max_rows)
+ max_rows= ((((ulonglong) 1 << (pointer*8)) -1) / min_pack_length);
+ }
+
+ real_reclength=reclength;
+ if (datafile_type == STATIC_RECORD)
+ {
+ if (reclength <= pointer)
+ reclength=pointer+1; /* reserve place for delete link */
+ }
+ else
+ reclength+= long_varchar_count; /* We need space for varchar! */
+
+ max_key_length=0; tot_length=0 ; key_segs=0;
+ fulltext_keys=0;
+ share.state.rec_per_key_part= rec_per_key_part;
+ share.state.nulls_per_key_part= nulls_per_key_part;
+ share.state.key_root=key_root;
+ share.state.key_del= HA_OFFSET_ERROR;
+ if (uniques)
+ max_key_length= MARIA_UNIQUE_HASH_LENGTH + pointer;
+
+ for (i=0, keydef=keydefs ; i < keys ; i++ , keydef++)
+ {
+ share.state.key_root[i]= HA_OFFSET_ERROR;
+ length= real_length_diff= 0;
+ min_key_length= key_length= pointer;
+
+ if (keydef->key_alg == HA_KEY_ALG_RTREE)
+ keydef->flag|= HA_RTREE_INDEX; /* For easier tests */
+
+ if (keydef->flag & HA_SPATIAL)
+ {
+#ifdef HAVE_SPATIAL
+ /* BAR TODO to support 3D and more dimensions in the future */
+ uint sp_segs=SPDIMS*2;
+ keydef->flag=HA_SPATIAL;
+
+ if (flags & HA_DONT_TOUCH_DATA)
+ {
+ /*
+ Called by maria_chk - i.e. table structure was taken from
+ MYI file and SPATIAL key *does have* additional sp_segs keysegs.
+ keydef->seg here points right at the GEOMETRY segment,
+ so we only need to decrease keydef->keysegs.
+ (see maria_recreate_table() in _ma_check.c)
+ */
+ keydef->keysegs-=sp_segs-1;
+ }
+
+ for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
+ j++, keyseg++)
+ {
+ if (keyseg->type != HA_KEYTYPE_BINARY &&
+ keyseg->type != HA_KEYTYPE_VARBINARY1 &&
+ keyseg->type != HA_KEYTYPE_VARBINARY2)
+ {
+ my_errno=HA_WRONG_CREATE_OPTION;
+ goto err_no_lock;
+ }
+ }
+ keydef->keysegs+=sp_segs;
+ key_length+=SPLEN*sp_segs;
+ length++; /* At least one length uchar */
+ min_key_length++;
+#else
+ my_errno= HA_ERR_UNSUPPORTED;
+ goto err_no_lock;
+#endif /*HAVE_SPATIAL*/
+ }
+ else if (keydef->flag & HA_FULLTEXT)
+ {
+ keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+
+ for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
+ j++, keyseg++)
+ {
+ if (keyseg->type != HA_KEYTYPE_TEXT &&
+ keyseg->type != HA_KEYTYPE_VARTEXT1 &&
+ keyseg->type != HA_KEYTYPE_VARTEXT2)
+ {
+ my_errno=HA_WRONG_CREATE_OPTION;
+ goto err_no_lock;
+ }
+ if (!(keyseg->flag & HA_BLOB_PART) &&
+ (keyseg->type == HA_KEYTYPE_VARTEXT1 ||
+ keyseg->type == HA_KEYTYPE_VARTEXT2))
+ {
+ /* Make a flag that this is a VARCHAR */
+ keyseg->flag|= HA_VAR_LENGTH_PART;
+ /* Store in bit_start number of bytes used to pack the length */
+ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1)?
+ 1 : 2);
+ }
+ }
+
+ fulltext_keys++;
+ key_length+= HA_FT_MAXBYTELEN+HA_FT_WLEN;
+ length++; /* At least one length uchar */
+ min_key_length+= 1 + HA_FT_WLEN;
+ real_length_diff=HA_FT_MAXBYTELEN-FT_MAX_WORD_LEN_FOR_SORT;
+ }
+ else
+ {
+ /* Test if prefix compression */
+ if (keydef->flag & HA_PACK_KEY)
+ {
+ /* Can't use space_compression on number keys */
+ if ((keydef->seg[0].flag & HA_SPACE_PACK) &&
+ keydef->seg[0].type == (int) HA_KEYTYPE_NUM)
+ keydef->seg[0].flag&= ~HA_SPACE_PACK;
+
+ /* Only use HA_PACK_KEY when first segment is a variable length key */
+ if (!(keydef->seg[0].flag & (HA_SPACE_PACK | HA_BLOB_PART |
+ HA_VAR_LENGTH_PART)))
+ {
+ /* pack relative to previous key */
+ keydef->flag&= ~HA_PACK_KEY;
+ keydef->flag|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
+ }
+ else
+ {
+ keydef->seg[0].flag|=HA_PACK_KEY; /* for easyer intern test */
+ keydef->flag|=HA_VAR_LENGTH_KEY;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ }
+ }
+ if (keydef->flag & HA_BINARY_PACK_KEY)
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+
+ if (keydef->flag & HA_AUTO_KEY && ci->with_auto_increment)
+ share.base.auto_key=i+1;
+ for (j=0, keyseg=keydef->seg ; j < keydef->keysegs ; j++, keyseg++)
+ {
+ /* numbers are stored with high by first to make compression easier */
+ switch (keyseg->type) {
+ case HA_KEYTYPE_SHORT_INT:
+ case HA_KEYTYPE_LONG_INT:
+ case HA_KEYTYPE_FLOAT:
+ case HA_KEYTYPE_DOUBLE:
+ case HA_KEYTYPE_USHORT_INT:
+ case HA_KEYTYPE_ULONG_INT:
+ case HA_KEYTYPE_LONGLONG:
+ case HA_KEYTYPE_ULONGLONG:
+ case HA_KEYTYPE_INT24:
+ case HA_KEYTYPE_UINT24:
+ case HA_KEYTYPE_INT8:
+ keyseg->flag|= HA_SWAP_KEY;
+ break;
+ case HA_KEYTYPE_VARTEXT1:
+ case HA_KEYTYPE_VARTEXT2:
+ case HA_KEYTYPE_VARBINARY1:
+ case HA_KEYTYPE_VARBINARY2:
+ if (!(keyseg->flag & HA_BLOB_PART))
+ {
+ /* Make a flag that this is a VARCHAR */
+ keyseg->flag|= HA_VAR_LENGTH_PART;
+ /* Store in bit_start number of bytes used to pack the length */
+ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
+ keyseg->type == HA_KEYTYPE_VARBINARY1) ?
+ 1 : 2);
+ }
+ break;
+ default:
+ break;
+ }
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ DBUG_ASSERT(!(keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
+ keydef->flag |= HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ length++; /* At least one length uchar */
+ if (!keyseg->null_bit)
+ min_key_length++;
+ key_length+= keyseg->length;
+ if (keyseg->length >= 255)
+ {
+ /* prefix may be 3 bytes */
+ length+= 2;
+ }
+ }
+ else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
+ {
+ DBUG_ASSERT(!test_all_bits(keyseg->flag,
+ (HA_VAR_LENGTH_PART | HA_BLOB_PART)));
+ keydef->flag|=HA_VAR_LENGTH_KEY;
+ length++; /* At least one length uchar */
+ if (!keyseg->null_bit)
+ min_key_length++;
+ options|=HA_OPTION_PACK_KEYS; /* Using packed keys */
+ key_length+= keyseg->length;
+ if (keyseg->length >= 255)
+ {
+ /* prefix may be 3 bytes */
+ length+= 2;
+ }
+ }
+ else
+ {
+ key_length+= keyseg->length;
+ if (!keyseg->null_bit)
+ min_key_length+= keyseg->length;
+ }
+ if (keyseg->null_bit)
+ {
+ key_length++;
+ /* min key part is 1 byte */
+ min_key_length++;
+ options|=HA_OPTION_PACK_KEYS;
+ keyseg->flag|=HA_NULL_PART;
+ keydef->flag|=HA_VAR_LENGTH_KEY | HA_NULL_PART_KEY;
+ }
+ }
+ } /* if HA_FULLTEXT */
+ key_segs+=keydef->keysegs;
+ if (keydef->keysegs > HA_MAX_KEY_SEG)
+ {
+ my_errno=HA_WRONG_CREATE_OPTION;
+ goto err_no_lock;
+ }
+ /*
+ key_segs may be 0 in the case when we only want to be able to
+ add on row into the table. This can happen with some DISTINCT queries
+ in MySQL
+ */
+ if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME &&
+ key_segs)
+ share.state.rec_per_key_part[key_segs-1]=1L;
+ length+=key_length;
+ /*
+ A key can't be longer than than half a index block (as we have
+ to be able to put at least 2 keys on an index block for the key
+ algorithms to work).
+ */
+ if (length > maria_max_key_length())
+ {
+ my_errno=HA_WRONG_CREATE_OPTION;
+ goto err_no_lock;
+ }
+ keydef->block_length= (uint16) maria_block_size;
+ keydef->keylength= (uint16) key_length;
+ keydef->minlength= (uint16) min_key_length;
+ keydef->maxlength= (uint16) length;
+
+ if (length > max_key_length)
+ max_key_length= length;
+ tot_length+= ((max_rows/(ulong) (((uint) maria_block_size -
+ MAX_KEYPAGE_HEADER_SIZE -
+ KEYPAGE_CHECKSUM_SIZE)/
+ (length*2))) *
+ maria_block_size);
+ }
+
+ unique_key_parts=0;
+ for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++)
+ {
+ uniquedef->key=keys+i;
+ unique_key_parts+=uniquedef->keysegs;
+ share.state.key_root[keys+i]= HA_OFFSET_ERROR;
+ tot_length+= (max_rows/(ulong) (((uint) maria_block_size -
+ MAX_KEYPAGE_HEADER_SIZE -
+ KEYPAGE_CHECKSUM_SIZE) /
+ ((MARIA_UNIQUE_HASH_LENGTH + pointer)*2)))*
+ (ulong) maria_block_size;
+ }
+ keys+=uniques; /* Each unique has 1 key */
+ key_segs+=uniques; /* Each unique has 1 key seg */
+
+ base_pos=(MARIA_STATE_INFO_SIZE + keys * MARIA_STATE_KEY_SIZE +
+ key_segs * MARIA_STATE_KEYSEG_SIZE);
+ info_length= base_pos+(uint) (MARIA_BASE_INFO_SIZE+
+ keys * MARIA_KEYDEF_SIZE+
+ uniques * MARIA_UNIQUEDEF_SIZE +
+ (key_segs + unique_key_parts)*HA_KEYSEG_SIZE+
+ columns*(MARIA_COLUMNDEF_SIZE + 2));
+
+ DBUG_PRINT("info", ("info_length: %u", info_length));
+ /* There are only 16 bits for the total header length. */
+ if (info_length > 65535)
+ {
+ my_printf_error(HA_WRONG_CREATE_OPTION,
+ "Maria table '%s' has too many columns and/or "
+ "indexes and/or unique constraints.",
+ MYF(0), name + dirname_length(name));
+ my_errno= HA_WRONG_CREATE_OPTION;
+ goto err_no_lock;
+ }
+
+ bmove(share.state.header.file_version,(uchar*) maria_file_magic,4);
+ ci->old_options=options | (ci->old_options & HA_OPTION_TEMP_COMPRESS_RECORD ?
+ HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD: 0);
+ mi_int2store(share.state.header.options,ci->old_options);
+ mi_int2store(share.state.header.header_length,info_length);
+ mi_int2store(share.state.header.state_info_length,MARIA_STATE_INFO_SIZE);
+ mi_int2store(share.state.header.base_info_length,MARIA_BASE_INFO_SIZE);
+ mi_int2store(share.state.header.base_pos,base_pos);
+ share.state.header.data_file_type= share.data_file_type= datafile_type;
+ share.state.header.org_data_file_type= org_datafile_type;
+ share.state.header.language= (ci->language ?
+ ci->language : default_charset_info->number);
+
+ share.state.dellink = HA_OFFSET_ERROR;
+ share.state.first_bitmap_with_space= 0;
+#ifdef EXTERNAL_LOCKING
+ share.state.process= (ulong) getpid();
+#endif
+ share.state.version= (ulong) time((time_t*) 0);
+ share.state.sortkey= (ushort) ~0;
+ share.state.auto_increment=ci->auto_increment;
+ share.options=options;
+ share.base.rec_reflength=pointer;
+ share.base.block_size= maria_block_size;
+
+ /*
+ Get estimate for index file length (this may be wrong for FT keys)
+ This is used for pointers to other key pages.
+ */
+ tmp= (tot_length + maria_block_size * keys *
+ MARIA_INDEX_BLOCK_MARGIN) / maria_block_size;
+
+ /*
+ use maximum of key_file_length we calculated and key_file_length value we
+ got from MAI file header (see also mariapack.c:save_state)
+ */
+ share.base.key_reflength=
+ maria_get_pointer_length(max(ci->key_file_length,tmp),3);
+ share.base.keys= share.state.header.keys= keys;
+ share.state.header.uniques= uniques;
+ share.state.header.fulltext_keys= fulltext_keys;
+ mi_int2store(share.state.header.key_parts,key_segs);
+ mi_int2store(share.state.header.unique_key_parts,unique_key_parts);
+
+ maria_set_all_keys_active(share.state.key_map, keys);
+
+ share.base.keystart = share.state.state.key_file_length=
+ MY_ALIGN(info_length, maria_block_size);
+ share.base.max_key_block_length= maria_block_size;
+ share.base.max_key_length=ALIGN_SIZE(max_key_length+4);
+ share.base.records=ci->max_rows;
+ share.base.reloc= ci->reloc_rows;
+ share.base.reclength=real_reclength;
+ share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM);
+ share.base.max_pack_length=pack_reclength;
+ share.base.min_pack_length=min_pack_length;
+ share.base.pack_bytes= pack_bytes;
+ share.base.fields= columns;
+ share.base.pack_fields= packed;
+
+ if (share.data_file_type == BLOCK_RECORD)
+ {
+ /*
+ we are going to create a first bitmap page, set data_file_length
+ to reflect this, before the state goes to disk
+ */
+ share.state.state.data_file_length= maria_block_size;
+ /* Add length of packed fields + length */
+ share.base.pack_reclength+= share.base.max_field_lengths+3;
+
+ /* Adjust max_pack_length, to be used if we have short rows */
+ if (share.base.max_pack_length < maria_block_size)
+ {
+ share.base.max_pack_length+= FLAG_SIZE;
+ if (ci->transactional)
+ share.base.max_pack_length+= TRANSID_SIZE * 2;
+ }
+ }
+
+ /* max_data_file_length and max_key_file_length are recalculated on open */
+ if (tmp_table)
+ share.base.max_data_file_length= (my_off_t) ci->data_file_length;
+ else if (ci->transactional && translog_status == TRANSLOG_OK &&
+ !maria_in_recovery)
+ {
+ /*
+ we have checked translog_inited above, because maria_chk may call us
+ (via maria_recreate_table()) and it does not have a log.
+ */
+ sync_dir= MY_SYNC_DIR;
+ /*
+ If crash between _ma_state_info_write_sub() and
+ _ma_update_state__lsns_sub(), table should be ignored by Recovery (or
+ old REDOs would fail), so we cannot let LSNs be 0:
+ */
+ share.state.skip_redo_lsn= share.state.is_of_horizon=
+ share.state.create_rename_lsn= LSN_MAX;
+ }
+
+ if (datafile_type == DYNAMIC_RECORD)
+ {
+ share.base.min_block_length=
+ (share.base.pack_reclength+3 < MARIA_EXTEND_BLOCK_LENGTH &&
+ ! share.base.blobs) ?
+ max(share.base.pack_reclength,MARIA_MIN_BLOCK_LENGTH) :
+ MARIA_EXTEND_BLOCK_LENGTH;
+ }
+ else if (datafile_type == STATIC_RECORD)
+ share.base.min_block_length= share.base.pack_reclength;
+
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ share.state.create_time= (long) time((time_t*) 0);
+
+ pthread_mutex_lock(&THR_LOCK_maria);
+
+ /*
+ NOTE: For test_if_reopen() we need a real path name. Hence we need
+ MY_RETURN_REAL_PATH for every fn_format(filename, ...).
+ */
+ if (ci->index_file_name)
+ {
+ char *iext= strrchr(ci->index_file_name, '.');
+ int have_iext= iext && !strcmp(iext, MARIA_NAME_IEXT);
+ if (tmp_table)
+ {
+ char *path;
+ /* chop off the table name, tempory tables use generated name */
+ if ((path= strrchr(ci->index_file_name, FN_LIBCHAR)))
+ *path= '\0';
+ fn_format(filename, name, ci->index_file_name, MARIA_NAME_IEXT,
+ MY_REPLACE_DIR | MY_UNPACK_FILENAME |
+ MY_RETURN_REAL_PATH | MY_APPEND_EXT);
+ }
+ else
+ {
+ fn_format(filename, ci->index_file_name, "", MARIA_NAME_IEXT,
+ MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
+ (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
+ }
+ fn_format(linkname, name, "", MARIA_NAME_IEXT,
+ MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ linkname_ptr= linkname;
+ /*
+ Don't create the table if the link or file exists to ensure that one
+ doesn't accidently destroy another table.
+ Don't sync dir now if the data file has the same path.
+ */
+ create_flag=
+ (ci->data_file_name &&
+ !strcmp(ci->index_file_name, ci->data_file_name)) ? 0 : sync_dir;
+ }
+ else
+ {
+ char *iext= strrchr(name, '.');
+ int have_iext= iext && !strcmp(iext, MARIA_NAME_IEXT);
+ fn_format(filename, name, "", MARIA_NAME_IEXT,
+ MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
+ (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
+ linkname_ptr= NullS;
+ /*
+ Replace the current file.
+ Don't sync dir now if the data file has the same path.
+ */
+ create_flag= (flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
+ create_flag|= (!ci->data_file_name ? 0 : sync_dir);
+ }
+
+ /*
+ If a MRG_MARIA table is in use, the mapped MARIA tables are open,
+ but no entry is made in the table cache for them.
+ A TRUNCATE command checks for the table in the cache only and could
+ be fooled to believe, the table is not open.
+ Pull the emergency brake in this situation. (Bug #8306)
+
+
+ NOTE: The filename is compared against unique_file_name of every
+ open table. Hence we need a real path here.
+ */
+ if (_ma_test_if_reopen(filename))
+ {
+ my_printf_error(0, "MARIA table '%s' is in use "
+ "(most likely by a MERGE table). Try FLUSH TABLES.",
+ MYF(0), name + dirname_length(name));
+ my_errno= HA_ERR_TABLE_EXIST;
+ goto err;
+ }
+
+ if ((file= my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
+ MYF(MY_WME|create_flag))) < 0)
+ goto err;
+ errpos=1;
+
+ DBUG_PRINT("info", ("write state info and base info"));
+ if (_ma_state_info_write_sub(file, &share.state,
+ MA_STATE_INFO_WRITE_FULL_INFO) ||
+ _ma_base_info_write(file, &share.base))
+ goto err;
+ DBUG_PRINT("info", ("base_pos: %d base_info_size: %d",
+ base_pos, MARIA_BASE_INFO_SIZE));
+ DBUG_ASSERT(my_tell(file,MYF(0)) == base_pos+ MARIA_BASE_INFO_SIZE);
+
+ /* Write key and keyseg definitions */
+ DBUG_PRINT("info", ("write key and keyseg definitions"));
+ for (i=0 ; i < share.base.keys - uniques; i++)
+ {
+ uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0;
+
+ if (_ma_keydef_write(file, &keydefs[i]))
+ goto err;
+ for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
+ if (_ma_keyseg_write(file, &keydefs[i].seg[j]))
+ goto err;
+#ifdef HAVE_SPATIAL
+ for (j=0 ; j < sp_segs ; j++)
+ {
+ HA_KEYSEG sseg;
+ sseg.type=SPTYPE;
+ sseg.language= 7; /* Binary */
+ sseg.null_bit=0;
+ sseg.bit_start=0;
+ sseg.bit_end=0;
+ sseg.bit_length= 0;
+ sseg.bit_pos= 0;
+ sseg.length=SPLEN;
+ sseg.null_pos=0;
+ sseg.start=j*SPLEN;
+ sseg.flag= HA_SWAP_KEY;
+ if (_ma_keyseg_write(file, &sseg))
+ goto err;
+ }
+#endif
+ }
+ /* Create extra keys for unique definitions */
+ offset= real_reclength - uniques*MARIA_UNIQUE_HASH_LENGTH;
+ bzero((char*) &tmp_keydef,sizeof(tmp_keydef));
+ bzero((char*) &tmp_keyseg,sizeof(tmp_keyseg));
+ for (i=0; i < uniques ; i++)
+ {
+ tmp_keydef.keysegs=1;
+ tmp_keydef.flag= HA_UNIQUE_CHECK;
+ tmp_keydef.block_length= (uint16) maria_block_size;
+ tmp_keydef.keylength= MARIA_UNIQUE_HASH_LENGTH + pointer;
+ tmp_keydef.minlength=tmp_keydef.maxlength=tmp_keydef.keylength;
+ tmp_keyseg.type= MARIA_UNIQUE_HASH_TYPE;
+ tmp_keyseg.length= MARIA_UNIQUE_HASH_LENGTH;
+ tmp_keyseg.start= offset;
+ offset+= MARIA_UNIQUE_HASH_LENGTH;
+ if (_ma_keydef_write(file,&tmp_keydef) ||
+ _ma_keyseg_write(file,(&tmp_keyseg)))
+ goto err;
+ }
+
+ /* Save unique definition */
+ DBUG_PRINT("info", ("write unique definitions"));
+ for (i=0 ; i < share.state.header.uniques ; i++)
+ {
+ HA_KEYSEG *keyseg_end;
+ keyseg= uniquedefs[i].seg;
+ if (_ma_uniquedef_write(file, &uniquedefs[i]))
+ goto err;
+ for (keyseg= uniquedefs[i].seg, keyseg_end= keyseg+ uniquedefs[i].keysegs;
+ keyseg < keyseg_end;
+ keyseg++)
+ {
+ switch (keyseg->type) {
+ case HA_KEYTYPE_VARTEXT1:
+ case HA_KEYTYPE_VARTEXT2:
+ case HA_KEYTYPE_VARBINARY1:
+ case HA_KEYTYPE_VARBINARY2:
+ if (!(keyseg->flag & HA_BLOB_PART))
+ {
+ keyseg->flag|= HA_VAR_LENGTH_PART;
+ keyseg->bit_start= ((keyseg->type == HA_KEYTYPE_VARTEXT1 ||
+ keyseg->type == HA_KEYTYPE_VARBINARY1) ?
+ 1 : 2);
+ }
+ break;
+ default:
+ DBUG_ASSERT((keyseg->flag & HA_VAR_LENGTH_PART) == 0);
+ break;
+ }
+ if (_ma_keyseg_write(file, keyseg))
+ goto err;
+ }
+ }
+ DBUG_PRINT("info", ("write field definitions"));
+ if (datafile_type == BLOCK_RECORD)
+ {
+ /* Store columns in a more efficent order */
+ MARIA_COLUMNDEF **col_order, **pos;
+ if (!(col_order= (MARIA_COLUMNDEF**) my_malloc(share.base.fields *
+ sizeof(MARIA_COLUMNDEF*),
+ MYF(MY_WME))))
+ goto err;
+ for (column= columndef, pos= col_order ;
+ column != end_column ;
+ column++, pos++)
+ *pos= column;
+ qsort(col_order, share.base.fields, sizeof(*col_order),
+ (qsort_cmp) compare_columns);
+ for (i=0 ; i < share.base.fields ; i++)
+ {
+ column_array[col_order[i]->column_nr]= i;
+ if (_ma_columndef_write(file, col_order[i]))
+ {
+ my_free((uchar*) col_order, MYF(0));
+ goto err;
+ }
+ }
+ my_free((uchar*) col_order, MYF(0));
+ }
+ else
+ {
+ for (i=0 ; i < share.base.fields ; i++)
+ {
+ column_array[i]= (uint16) i;
+ if (_ma_columndef_write(file, &columndef[i]))
+ goto err;
+ }
+ }
+ if (_ma_column_nr_write(file, column_array, columns))
+ goto err;
+
+ if ((kfile_size_before_extension= my_tell(file,MYF(0))) == MY_FILEPOS_ERROR)
+ goto err;
+#ifndef DBUG_OFF
+ if (kfile_size_before_extension != info_length)
+ DBUG_PRINT("warning",("info_length: %u != used_length: %u",
+ info_length, (uint)kfile_size_before_extension));
+#endif
+
+ if (sync_dir)
+ {
+ /*
+ we log the first bytes and then the size to which we extend; this is
+ not log 1 KB of mostly zeroes if this is a small table.
+ */
+ char empty_string[]= "";
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 4];
+ translog_size_t total_rec_length= 0;
+ uint k;
+ LSN lsn;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= 1 + 2 + 2 +
+ (uint) kfile_size_before_extension;
+ /* we are needing maybe 64 kB, so don't use the stack */
+ log_data= my_malloc(log_array[TRANSLOG_INTERNAL_PARTS + 1].length, MYF(0));
+ if ((log_data == NULL) ||
+ my_pread(file, 1 + 2 + 2 + log_data,
+ (size_t) kfile_size_before_extension, 0, MYF(MY_NABP)))
+ goto err;
+ /*
+ remember if the data file was created or not, to know if Recovery can
+ do it or not, in the future
+ */
+ log_data[0]= test(flags & HA_DONT_TOUCH_DATA);
+ int2store(log_data + 1, kfile_size_before_extension);
+ int2store(log_data + 1 + 2, share.base.keystart);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (uchar *)name;
+ /* we store the end-zero, for Recovery to just pass it to my_create() */
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= strlen(name) + 1;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= log_data;
+ /* symlink description is also needed for re-creation by Recovery: */
+ {
+ const char *s= ci->data_file_name ? ci->data_file_name : empty_string;
+ log_array[TRANSLOG_INTERNAL_PARTS + 2].str= (uchar*)s;
+ log_array[TRANSLOG_INTERNAL_PARTS + 2].length= strlen(s) + 1;
+ s= ci->index_file_name ? ci->index_file_name : empty_string;
+ log_array[TRANSLOG_INTERNAL_PARTS + 3].str= (uchar*)s;
+ log_array[TRANSLOG_INTERNAL_PARTS + 3].length= strlen(s) + 1;
+ }
+ for (k= TRANSLOG_INTERNAL_PARTS;
+ k < (sizeof(log_array)/sizeof(log_array[0])); k++)
+ total_rec_length+= (translog_size_t) log_array[k].length;
+ /**
+ For this record to be of any use for Recovery, we need the upper
+ MySQL layer to be crash-safe, which it is not now (that would require
+ work using the ddl_log of sql/sql_table.cc); when it is, we should
+ reconsider the moment of writing this log record (before or after op,
+ under THR_LOCK_maria or not...), how to use it in Recovery.
+ For now this record can serve when we apply logs to a backup,
+ so we sync it. This happens before the data file is created. If the
+ data file was created before, and we crashed before writing the log
+ record, at restart the table may be used, so we would not have a
+ trustable history in the log (impossible to apply this log to a
+ backup). The way we do it, if we crash before writing the log record
+ then there is no data file and the table cannot be used.
+ @todo Note that in case of TRUNCATE TABLE we also come here; for
+ Recovery to be able to finish TRUNCATE TABLE, instead of leaving a
+ half-truncated table, we should log the record at start of
+ maria_create(); for that we shouldn't write to the index file but to a
+ buffer (DYNAMIC_STRING), put the buffer into the record, then put the
+ buffer into the index file (so, change _ma_keydef_write() etc). That
+ would also enable Recovery to finish a CREATE TABLE. The final result
+ would be that we would be able to finish what the SQL layer has asked
+ for: it would be atomic.
+ When in CREATE/TRUNCATE (or DROP or RENAME or REPAIR) we have not
+ called external_lock(), so have no TRN. It does not matter, as all
+ these operations are non-transactional and sync their files.
+ */
+ if (unlikely(translog_write_record(&lsn,
+ LOGREC_REDO_CREATE_TABLE,
+ &dummy_transaction_object, NULL,
+ total_rec_length,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL) ||
+ translog_flush(lsn)))
+ goto err;
+ share.kfile.file= file;
+ DBUG_EXECUTE_IF("maria_flush_whole_log",
+ {
+ DBUG_PRINT("maria_flush_whole_log", ("now"));
+ translog_flush(translog_get_horizon());
+ });
+ DBUG_EXECUTE_IF("maria_crash_create_table",
+ {
+ DBUG_PRINT("maria_crash_create_table", ("now"));
+ DBUG_ABORT();
+ });
+ /*
+ store LSN into file, needed for Recovery to not be confused if a
+ DROP+CREATE happened (applying REDOs to the wrong table).
+ */
+ if (_ma_update_state_lsns_sub(&share, lsn, trnman_get_min_safe_trid(),
+ FALSE, TRUE))
+ goto err;
+ my_free(log_data, MYF(0));
+ }
+
+ if (!(flags & HA_DONT_TOUCH_DATA))
+ {
+ if (ci->data_file_name)
+ {
+ char *dext= strrchr(ci->data_file_name, '.');
+ int have_dext= dext && !strcmp(dext, MARIA_NAME_DEXT);
+
+ if (tmp_table)
+ {
+ char *path;
+ /* chop off the table name, tempory tables use generated name */
+ if ((path= strrchr(ci->data_file_name, FN_LIBCHAR)))
+ *path= '\0';
+ fn_format(filename, name, ci->data_file_name, MARIA_NAME_DEXT,
+ MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ }
+ else
+ {
+ fn_format(filename, ci->data_file_name, "", MARIA_NAME_DEXT,
+ MY_UNPACK_FILENAME |
+ (have_dext ? MY_REPLACE_EXT : MY_APPEND_EXT));
+ }
+ fn_format(linkname, name, "",MARIA_NAME_DEXT,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ linkname_ptr= linkname;
+ create_flag=0;
+ }
+ else
+ {
+ fn_format(filename,name,"", MARIA_NAME_DEXT,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ linkname_ptr= NullS;
+ create_flag= (flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD;
+ }
+ if ((dfile=
+ my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
+ MYF(MY_WME | create_flag | sync_dir))) < 0)
+ goto err;
+ errpos=3;
+
+ if (_ma_initialize_data_file(&share, dfile))
+ goto err;
+ }
+
+ /* Enlarge files */
+ DBUG_PRINT("info", ("enlarge to keystart: %lu",
+ (ulong) share.base.keystart));
+ if (my_chsize(file,(ulong) share.base.keystart,0,MYF(0)))
+ goto err;
+
+ if (sync_dir && my_sync(file, MYF(0)))
+ goto err;
+
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ {
+#ifdef USE_RELOC
+ if (my_chsize(dfile,share.base.min_pack_length*ci->reloc_rows,0,MYF(0)))
+ goto err;
+#endif
+ if (sync_dir && my_sync(dfile, MYF(0)))
+ goto err;
+ if (my_close(dfile,MYF(0)))
+ goto err;
+ }
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ res= 0;
+ my_free((char*) rec_per_key_part,MYF(0));
+ errpos=0;
+ if (my_close(file,MYF(0)))
+ res= my_errno;
+ DBUG_RETURN(res);
+
+err:
+ pthread_mutex_unlock(&THR_LOCK_maria);
+
+err_no_lock:
+ save_errno=my_errno;
+ switch (errpos) {
+ case 3:
+ VOID(my_close(dfile,MYF(0)));
+ /* fall through */
+ case 2:
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ my_delete_with_symlink(fn_format(filename,name,"",MARIA_NAME_DEXT,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT),
+ sync_dir);
+ /* fall through */
+ case 1:
+ VOID(my_close(file,MYF(0)));
+ if (! (flags & HA_DONT_TOUCH_DATA))
+ my_delete_with_symlink(fn_format(filename,name,"",MARIA_NAME_IEXT,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT),
+ sync_dir);
+ }
+ my_free(log_data, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((char*) rec_per_key_part, MYF(0));
+ DBUG_RETURN(my_errno=save_errno); /* return the fatal errno */
+}
+
+
+uint maria_get_pointer_length(ulonglong file_length, uint def)
+{
+ DBUG_ASSERT(def >= 2 && def <= 7);
+ if (file_length) /* If not default */
+ {
+#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
+ if (file_length >= (ULL(1) << 56))
+ def=8;
+ else
+#endif
+ if (file_length >= (ULL(1) << 48))
+ def=7;
+ else if (file_length >= (ULL(1) << 40))
+ def=6;
+ else if (file_length >= (ULL(1) << 32))
+ def=5;
+ else if (file_length >= (ULL(1) << 24))
+ def=4;
+ else if (file_length >= (ULL(1) << 16))
+ def=3;
+ else
+ def=2;
+ }
+ return def;
+}
+
+
+/*
+ Sort columns for records-in-block
+
+ IMPLEMENTATION
+ Sort columns in following order:
+
+ Fixed size, not null columns
+ Fixed length, null fields
+ Numbers (zero fill fields)
+ Variable length fields (CHAR, VARCHAR) according to length
+ Blobs
+
+ For same kind of fields, keep fields in original order
+*/
+
+static inline int sign(long a)
+{
+ return a < 0 ? -1 : (a > 0 ? 1 : 0);
+}
+
+
+static int compare_columns(MARIA_COLUMNDEF **a_ptr, MARIA_COLUMNDEF **b_ptr)
+{
+ MARIA_COLUMNDEF *a= *a_ptr, *b= *b_ptr;
+ enum en_fieldtype a_type, b_type;
+
+ a_type= (a->type == FIELD_CHECK) ? FIELD_NORMAL : a->type;
+ b_type= (b->type == FIELD_CHECK) ? FIELD_NORMAL : b->type;
+
+ if (a_type == FIELD_NORMAL && !a->null_bit)
+ {
+ if (b_type != FIELD_NORMAL || b->null_bit)
+ return -1;
+ return sign((long) a->offset - (long) b->offset);
+ }
+ if (b_type == FIELD_NORMAL && !b->null_bit)
+ return 1;
+ if (a_type == b_type)
+ return sign((long) a->offset - (long) b->offset);
+ if (a_type == FIELD_NORMAL)
+ return -1;
+ if (b_type == FIELD_NORMAL)
+ return 1;
+ if (a_type == FIELD_SKIP_ZERO)
+ return -1;
+ if (b_type == FIELD_SKIP_ZERO)
+ return 1;
+ if (a->type != FIELD_BLOB && b->type != FIELD_BLOB)
+ if (a->length != b->length)
+ return sign((long) a->length - (long) b->length);
+ if (a_type == FIELD_BLOB)
+ return 1;
+ if (b_type == FIELD_BLOB)
+ return -1;
+ return sign((long) a->offset - (long) b->offset);
+}
+
+
+/**
+ @brief Initialize data file
+
+ @note
+ In BLOCK_RECORD, a freshly created datafile is one page long; while in
+ other formats it is 0-byte long.
+ */
+
+int _ma_initialize_data_file(MARIA_SHARE *share, File dfile)
+{
+ if (share->data_file_type == BLOCK_RECORD)
+ {
+ share->bitmap.block_size= share->base.block_size;
+ share->bitmap.file.file = dfile;
+ return _ma_bitmap_create_first(share);
+ }
+ return 0;
+}
+
+
+/**
+ @brief Writes create_rename_lsn, skip_redo_lsn and is_of_horizon to disk,
+ can force.
+
+ This is for special cases where:
+ - we don't want to write the full state to disk (so, not call
+ _ma_state_info_write()) because some parts of the state may be
+ currently inconsistent, or because it would be overkill
+ - we must sync these LSNs immediately for correctness.
+ It acquires intern_lock to protect the LSNs and state write.
+
+ @param share table's share
+ @param lsn LSN to write to log files
+ @param create_trid Trid to be used as state.create_trid
+ @param do_sync if the write should be forced to disk
+ @param update_create_rename_lsn if this LSN should be updated or not
+
+ @return Operation status
+ @retval 0 ok
+ @retval 1 error (disk problem)
+*/
+
+int _ma_update_state_lsns(MARIA_SHARE *share, LSN lsn, TrID create_trid,
+ my_bool do_sync, my_bool update_create_rename_lsn)
+{
+ int res;
+ pthread_mutex_lock(&share->intern_lock);
+ res= _ma_update_state_lsns_sub(share, lsn, create_trid, do_sync,
+ update_create_rename_lsn);
+ pthread_mutex_unlock(&share->intern_lock);
+ return res;
+}
+
+
+/**
+ @brief Writes create_rename_lsn, skip_redo_lsn and is_of_horizon to disk,
+ can force.
+
+ Shortcut of _ma_update_state_lsns() when we know that intern_lock is not
+ needed (when creating a table or opening it for the first time).
+
+ @param share table's share
+ @param lsn LSN to write to state; if LSN_IMPOSSIBLE, write
+ a LOGREC_IMPORTED_TABLE and use its LSN as lsn.
+ @param create_trid Trid to be used as state.create_trid
+ @param do_sync if the write should be forced to disk
+ @param update_create_rename_lsn if this LSN should be updated or not
+
+ @return Operation status
+ @retval 0 ok
+ @retval 1 error (disk problem)
+*/
+
+#if (_MSC_VER == 1310)
+/*
+ Visual Studio 2003 compiler produces internal compiler error
+ in this function. Disable optimizations to workaround.
+*/
+#pragma optimize("",off)
+#endif
+int _ma_update_state_lsns_sub(MARIA_SHARE *share, LSN lsn, TrID create_trid,
+ my_bool do_sync,
+ my_bool update_create_rename_lsn)
+{
+ uchar buf[LSN_STORE_SIZE * 3], *ptr;
+ uchar trid_buff[8];
+ File file= share->kfile.file;
+ DBUG_ASSERT(file >= 0);
+
+ if (lsn == LSN_IMPOSSIBLE)
+ {
+ int res;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ /* table name is logged only for information */
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str=
+ (uchar *)(share->open_file_name.str);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length=
+ share->open_file_name.length + 1;
+ if ((res= translog_write_record(&lsn, LOGREC_IMPORTED_TABLE,
+ &dummy_transaction_object, NULL,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL)))
+ return res;
+ }
+
+ for (ptr= buf; ptr < (buf + sizeof(buf)); ptr+= LSN_STORE_SIZE)
+ lsn_store(ptr, lsn);
+ share->state.skip_redo_lsn= share->state.is_of_horizon= lsn;
+ share->state.create_trid= create_trid;
+ mi_int8store(trid_buff, create_trid);
+ if (update_create_rename_lsn)
+ {
+ share->state.create_rename_lsn= lsn;
+ if (share->id != 0)
+ {
+ /*
+ If OP is the operation which is calling us, if table is later written,
+ we could see in the log:
+ FILE_ID ... REDO_OP ... REDO_INSERT.
+ (that can happen in real life at least with OP=REPAIR).
+ As FILE_ID will be ignored by Recovery because it is <
+ create_rename_lsn, REDO_INSERT would be ignored too, wrongly.
+ To avoid that, we force a LOGREC_FILE_ID to be logged at next write:
+ */
+ translog_deassign_id_from_share(share);
+ }
+ }
+ else
+ lsn_store(buf, share->state.create_rename_lsn);
+ return (my_pwrite(file, buf, sizeof(buf),
+ sizeof(share->state.header) +
+ MARIA_FILE_CREATE_RENAME_LSN_OFFSET, MYF(MY_NABP)) ||
+ my_pwrite(file, trid_buff, sizeof(trid_buff),
+ sizeof(share->state.header) +
+ MARIA_FILE_CREATE_TRID_OFFSET, MYF(MY_NABP)) ||
+ (do_sync && my_sync(file, MYF(0))));
+}
+#if (_MSC_VER == 1310)
+#pragma optimize("",on)
+#endif /*VS2003 compiler bug workaround*/
diff --git a/storage/maria/ma_dbug.c b/storage/maria/ma_dbug.c
new file mode 100644
index 00000000000..ea69975ad4b
--- /dev/null
+++ b/storage/maria/ma_dbug.c
@@ -0,0 +1,202 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Support rutiner with are using with dbug */
+
+#include "maria_def.h"
+
+void _ma_print_key(FILE *stream, MARIA_KEY *key)
+{
+ _ma_print_keydata(stream, key->keyinfo->seg, key->data, key->data_length);
+}
+
+
+/* Print a key in a user understandable format */
+
+void _ma_print_keydata(FILE *stream, register HA_KEYSEG *keyseg,
+ const uchar *key, uint length)
+{
+ int flag;
+ short int s_1;
+ long int l_1;
+ float f_1;
+ double d_1;
+ const uchar *end;
+ const uchar *key_end= key + length;
+
+ VOID(fputs("Key: \"",stream));
+ flag=0;
+ for (; keyseg->type && key < key_end ;keyseg++)
+ {
+ if (flag++)
+ VOID(putc('-',stream));
+ end= key+ keyseg->length;
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ /* A NULL value is encoded by a 1-byte flag. Zero means NULL. */
+ if (! *(key++))
+ {
+ fprintf(stream,"NULL");
+ continue;
+ }
+ end++;
+ }
+
+ switch (keyseg->type) {
+ case HA_KEYTYPE_BINARY:
+ if (!(keyseg->flag & HA_SPACE_PACK) && keyseg->length == 1)
+ { /* packed binary digit */
+ VOID(fprintf(stream,"%d",(uint) *key++));
+ break;
+ }
+ /* fall through */
+ case HA_KEYTYPE_TEXT:
+ case HA_KEYTYPE_NUM:
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ VOID(fprintf(stream,"%.*s",(int) *key,key+1));
+ key+= (int) *key+1;
+ }
+ else
+ {
+ VOID(fprintf(stream,"%.*s",(int) keyseg->length,key));
+ key=end;
+ }
+ break;
+ case HA_KEYTYPE_INT8:
+ VOID(fprintf(stream,"%d",(int) *((const signed char*) key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ s_1= mi_sint2korr(key);
+ VOID(fprintf(stream,"%d",(int) s_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ {
+ ushort u_1;
+ u_1= mi_uint2korr(key);
+ VOID(fprintf(stream,"%u",(uint) u_1));
+ key=end;
+ break;
+ }
+ case HA_KEYTYPE_LONG_INT:
+ l_1=mi_sint4korr(key);
+ VOID(fprintf(stream,"%ld",l_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ l_1=mi_uint4korr(key);
+ VOID(fprintf(stream,"%lu",(ulong) l_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_INT24:
+ VOID(fprintf(stream,"%ld",(long) mi_sint3korr(key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_UINT24:
+ VOID(fprintf(stream,"%lu",(ulong) mi_uint3korr(key)));
+ key=end;
+ break;
+ case HA_KEYTYPE_FLOAT:
+ mi_float4get(f_1,key);
+ VOID(fprintf(stream,"%g",(double) f_1));
+ key=end;
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ mi_float8get(d_1,key);
+ VOID(fprintf(stream,"%g",d_1));
+ key=end;
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ {
+ char buff[21];
+ longlong2str(mi_sint8korr(key),buff,-10);
+ VOID(fprintf(stream,"%s",buff));
+ key=end;
+ break;
+ }
+ case HA_KEYTYPE_ULONGLONG:
+ {
+ char buff[21];
+ longlong2str(mi_sint8korr(key),buff,10);
+ VOID(fprintf(stream,"%s",buff));
+ key=end;
+ break;
+ }
+ case HA_KEYTYPE_BIT:
+ {
+ uint i;
+ fputs("0x",stream);
+ for (i=0 ; i < keyseg->length ; i++)
+ fprintf(stream, "%02x", (uint) *key++);
+ key= end;
+ break;
+ }
+
+#endif
+ case HA_KEYTYPE_VARTEXT1: /* VARCHAR and TEXT */
+ case HA_KEYTYPE_VARTEXT2: /* VARCHAR and TEXT */
+ case HA_KEYTYPE_VARBINARY1: /* VARBINARY and BLOB */
+ case HA_KEYTYPE_VARBINARY2: /* VARBINARY and BLOB */
+ {
+ uint tmp_length;
+ get_key_length(tmp_length,key);
+ /*
+ The following command sometimes gives a warning from valgrind.
+ Not yet sure if the bug is in valgrind, glibc or mysqld
+ */
+ VOID(fprintf(stream,"%.*s",(int) tmp_length,key));
+ key+=tmp_length;
+ break;
+ }
+ default: break; /* This never happens */
+ }
+ }
+ VOID(fputs("\"\n",stream));
+ return;
+} /* print_key */
+
+
+#ifdef EXTRA_DEBUG
+
+my_bool _ma_check_table_is_closed(const char *name, const char *where)
+{
+ char filename[FN_REFLEN];
+ LIST *pos;
+ DBUG_ENTER("_ma_check_table_is_closed");
+
+ (void) fn_format(filename,name,"",MARIA_NAME_IEXT,4+16+32);
+ pthread_mutex_lock(&THR_LOCK_maria);
+ for (pos=maria_open_list ; pos ; pos=pos->next)
+ {
+ MARIA_HA *info=(MARIA_HA*) pos->data;
+ MARIA_SHARE *share= info->s;
+ if (!strcmp(share->unique_file_name.str, filename))
+ {
+ if (share->last_version)
+ {
+ fprintf(stderr,"Warning: Table: %s is open on %s\n", name,where);
+ DBUG_PRINT("warning",("Table: %s is open on %s", name,where));
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ DBUG_RETURN(0);
+}
+#endif /* EXTRA_DEBUG */
diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c
new file mode 100644
index 00000000000..a4223e2250c
--- /dev/null
+++ b/storage/maria/ma_delete.c
@@ -0,0 +1,1537 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "ma_fulltext.h"
+#include "ma_rt_index.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+
+static int d_search(MARIA_HA *info, MARIA_KEY *key, uint32 comp_flag,
+ my_off_t page, uchar *anc_buff,
+ MARIA_PINNED_PAGE *anc_page_link);
+static int del(MARIA_HA *info, MARIA_KEY *key,
+ my_off_t anc_page, uchar *anc_buff, my_off_t leaf_page,
+ uchar *leaf_buff, MARIA_PINNED_PAGE *leaf_page_link,
+ uchar *keypos, my_off_t next_block, uchar *ret_key);
+static int underflow(MARIA_HA *info,MARIA_KEYDEF *keyinfo,
+ my_off_t anc_page, uchar *anc_buff,
+ my_off_t leaf_page, uchar *leaf_buff,
+ MARIA_PINNED_PAGE *leaf_page_link, uchar *keypos);
+static uint remove_key(MARIA_KEYDEF *keyinfo, uint page_flag, uint nod_flag,
+ uchar *keypos, uchar *lastkey, uchar *page_end,
+ my_off_t *next_block, MARIA_KEY_PARAM *s_temp);
+
+/* @breif Remove a row from a MARIA table */
+
+int maria_delete(MARIA_HA *info,const uchar *record)
+{
+ uint i;
+ uchar *old_key;
+ int save_errno;
+ char lastpos[8];
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo;
+ DBUG_ENTER("maria_delete");
+
+ /* Test if record is in datafile */
+ DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
+ maria_print_error(share, HA_ERR_CRASHED);
+ DBUG_RETURN(my_errno= HA_ERR_CRASHED););
+ DBUG_EXECUTE_IF("my_error_test_undefined_error",
+ maria_print_error(share, INT_MAX);
+ DBUG_RETURN(my_errno= INT_MAX););
+ if (!(info->update & HA_STATE_AKTIV))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No database read */
+ }
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ if (_ma_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+ if ((*share->compare_record)(info,record))
+ goto err; /* Error on read-check */
+
+ if (_ma_mark_file_changed(info))
+ goto err;
+
+ /* Ensure we don't change the autoincrement value */
+ info->last_auto_increment= ~(ulonglong) 0;
+ /* Remove all keys from the index file */
+
+ old_key= info->lastkey_buff2;
+
+ for (i=0, keyinfo= share->keyinfo ; i < share->base.keys ; i++, keyinfo++)
+ {
+ if (maria_is_key_active(share->state.key_map, i))
+ {
+ keyinfo->version++;
+ if (keyinfo->flag & HA_FULLTEXT)
+ {
+ if (_ma_ft_del(info, i, old_key, record, info->cur_row.lastpos))
+ goto err;
+ }
+ else
+ {
+ MARIA_KEY key;
+ if (keyinfo->ck_delete(info,
+ (*keyinfo->make_key)(info, &key, i, old_key,
+ record,
+ info->cur_row.lastpos,
+ info->cur_row.trid)))
+ goto err;
+ }
+ /* The above changed info->lastkey2. Inform maria_rnext_same(). */
+ info->update&= ~HA_STATE_RNEXT_SAME;
+ }
+ }
+
+ if (share->calc_checksum)
+ {
+ /*
+ We can't use the row based checksum as this doesn't have enough
+ precision.
+ */
+ info->cur_row.checksum= (*share->calc_checksum)(info, record);
+ }
+
+ if ((*share->delete_record)(info, record))
+ goto err; /* Remove record from database */
+
+ info->state->checksum-= info->cur_row.checksum;
+ info->state->records--;
+ info->update= HA_STATE_CHANGED+HA_STATE_DELETED+HA_STATE_ROW_CHANGED;
+ share->state.changed|= (STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_MOVABLE |
+ STATE_NOT_ZEROFILLED);
+ info->state->changed=1;
+
+ mi_sizestore(lastpos, info->cur_row.lastpos);
+ VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (delete)",
+ share->open_file_name.str));
+ (*info->invalidator)(share->open_file_name.str);
+ info->invalidator=0;
+ }
+ DBUG_RETURN(0);
+
+err:
+ save_errno= my_errno;
+ DBUG_ASSERT(save_errno);
+ if (!save_errno)
+ save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
+
+ mi_sizestore(lastpos, info->cur_row.lastpos);
+ if (save_errno != HA_ERR_RECORD_CHANGED)
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ maria_mark_crashed(info); /* mark table crashed */
+ }
+ VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ info->update|=HA_STATE_WRITTEN; /* Buffer changed */
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ }
+ DBUG_RETURN(my_errno= save_errno);
+} /* maria_delete */
+
+
+/*
+ Remove a key from the btree index
+
+ TODO:
+ Change ma_ck_real_delete() to use another buffer for changed keys instead
+ of key->data. This would allows us to remove the copying of the key here.
+*/
+
+int _ma_ck_delete(register MARIA_HA *info, MARIA_KEY *key)
+{
+ MARIA_SHARE *share= info->s;
+ int res;
+ LSN lsn= LSN_IMPOSSIBLE;
+ my_off_t new_root= share->state.key_root[key->keyinfo->key_nr];
+ uchar key_buff[MARIA_MAX_KEY_BUFF], *save_key_data;
+ MARIA_KEY org_key;
+ DBUG_ENTER("_ma_ck_delete");
+
+ save_key_data= key->data;
+ if (share->now_transactional)
+ {
+ /* Save original value as the key may change */
+ memcpy(key_buff, key->data, key->data_length + key->ref_length);
+ org_key= *key;
+ key->data= key_buff;
+ }
+
+ res= _ma_ck_real_delete(info, key, &new_root);
+
+ key->data= save_key_data;
+ if (!res && share->now_transactional)
+ res= _ma_write_undo_key_delete(info, &org_key, new_root, &lsn);
+ else
+ {
+ share->state.key_root[key->keyinfo->key_nr]= new_root;
+ _ma_fast_unlock_key_del(info);
+ }
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+ DBUG_RETURN(res);
+} /* _ma_ck_delete */
+
+
+int _ma_ck_real_delete(register MARIA_HA *info, MARIA_KEY *key,
+ my_off_t *root)
+{
+ int error;
+ uint nod_flag;
+ my_off_t old_root;
+ uchar *root_buff;
+ MARIA_PINNED_PAGE *page_link;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_ck_real_delete");
+
+ if ((old_root=*root) == HA_OFFSET_ERROR)
+ {
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ DBUG_RETURN(my_errno=HA_ERR_CRASHED);
+ }
+ if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
+ MARIA_MAX_KEY_BUFF*2)))
+ {
+ DBUG_PRINT("error",("Couldn't allocate memory"));
+ DBUG_RETURN(my_errno=ENOMEM);
+ }
+ DBUG_PRINT("info",("root_page: %ld", (long) old_root));
+ if (!_ma_fetch_keypage(info, keyinfo, old_root,
+ PAGECACHE_LOCK_WRITE, DFLT_INIT_HITS, root_buff, 0,
+ &page_link))
+ {
+ error= -1;
+ goto err;
+ }
+ if ((error= d_search(info, key, (keyinfo->flag & HA_FULLTEXT ?
+ SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT:
+ SEARCH_SAME),
+ old_root, root_buff, page_link)) > 0)
+ {
+ if (error == 2)
+ {
+ DBUG_PRINT("test",("Enlarging of root when deleting"));
+ error= _ma_enlarge_root(info, key, root);
+ }
+ else /* error == 1 */
+ {
+ uint used_length;
+ MARIA_SHARE *share= info->s;
+ _ma_get_used_and_nod(share, root_buff, used_length, nod_flag);
+ page_link->changed= 1;
+ if (used_length <= nod_flag + share->keypage_header + 1)
+ {
+ error=0;
+ if (nod_flag)
+ *root= _ma_kpos(nod_flag, root_buff +share->keypage_header +
+ nod_flag);
+ else
+ *root=HA_OFFSET_ERROR;
+ if (_ma_dispose(info, old_root, 0))
+ error= -1;
+ }
+ else
+ error= _ma_write_keypage(info,keyinfo, old_root,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, root_buff);
+ }
+ }
+err:
+ my_afree((uchar*) root_buff);
+ DBUG_PRINT("exit",("Return: %d",error));
+ DBUG_RETURN(error);
+} /* _ma_ck_real_delete */
+
+
+/**
+ @brief Remove key below key root
+
+ @param key Key to delete. Will contain new key if block was enlarged
+
+ @return
+ @retval 0 ok (anc_page is not changed)
+ @retval 1 If data on page is too small; In this case anc_buff is not saved
+ @retval 2 If data on page is too big
+ @retval -1 On errors
+*/
+
+static int d_search(MARIA_HA *info, MARIA_KEY *key, uint32 comp_flag,
+ my_off_t anc_page, uchar *anc_buff,
+ MARIA_PINNED_PAGE *anc_page_link)
+{
+ int flag,ret_value,save_flag;
+ uint nod_flag, page_flag;
+ my_bool last_key;
+ uchar *leaf_buff,*keypos;
+ my_off_t leaf_page,next_block;
+ uchar lastkey[MARIA_MAX_KEY_BUFF];
+ MARIA_PINNED_PAGE *leaf_page_link;
+ MARIA_KEY_PARAM s_temp;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("d_search");
+ DBUG_DUMP("page",anc_buff,_ma_get_page_used(share, anc_buff));
+
+ flag=(*keyinfo->bin_search)(key, anc_buff, comp_flag, &keypos, lastkey,
+ &last_key);
+ if (flag == MARIA_FOUND_WRONG_KEY)
+ {
+ DBUG_PRINT("error",("Found wrong key"));
+ DBUG_RETURN(-1);
+ }
+ page_flag= _ma_get_keypage_flag(share, anc_buff);
+ nod_flag= _ma_test_if_nod(share, anc_buff);
+
+ if (!flag && (keyinfo->flag & HA_FULLTEXT))
+ {
+ uint off;
+ int subkeys;
+
+ get_key_full_length_rdonly(off, lastkey);
+ subkeys=ft_sintXkorr(lastkey+off);
+ DBUG_ASSERT(info->ft1_to_ft2==0 || subkeys >=0);
+ comp_flag=SEARCH_SAME;
+ if (subkeys >= 0)
+ {
+ /* normal word, one-level tree structure */
+ if (info->ft1_to_ft2)
+ {
+ /* we're in ft1->ft2 conversion mode. Saving key data */
+ insert_dynamic(info->ft1_to_ft2, (lastkey+off));
+ }
+ else
+ {
+ /* we need exact match only if not in ft1->ft2 conversion mode */
+ flag=(*keyinfo->bin_search)(key, anc_buff, comp_flag, &keypos,
+ lastkey, &last_key);
+ }
+ /* fall through to normal delete */
+ }
+ else
+ {
+ /* popular word. two-level tree. going down */
+ uint tmp_key_length;
+ my_off_t root;
+ uchar *kpos=keypos;
+ MARIA_KEY tmp_key;
+
+ tmp_key.data= lastkey;
+ tmp_key.keyinfo= keyinfo;
+
+ if (!(tmp_key_length=(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag,
+ &kpos)))
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno= HA_ERR_CRASHED;
+ DBUG_RETURN(-1);
+ }
+ root= _ma_row_pos_from_key(&tmp_key);
+ if (subkeys == -1)
+ {
+ /* the last entry in sub-tree */
+ if (_ma_dispose(info, root, 1))
+ DBUG_RETURN(-1);
+ /* fall through to normal delete */
+ }
+ else
+ {
+ MARIA_KEY word_key;
+ keyinfo=&share->ft2_keyinfo;
+ /* we'll modify key entry 'in vivo' */
+ kpos-=keyinfo->keylength+nod_flag;
+ get_key_full_length_rdonly(off, key->data);
+
+ word_key.data= key->data + off;
+ word_key.keyinfo= &share->ft2_keyinfo;
+ word_key.data_length= HA_FT_WLEN;
+ word_key.ref_length= 0;
+ word_key.flag= 0;
+ ret_value= _ma_ck_real_delete(info, &word_key, &root);
+ _ma_dpointer(share, kpos+HA_FT_WLEN, root);
+ subkeys++;
+ ft_intXstore(kpos, subkeys);
+ if (!ret_value)
+ {
+ anc_page_link->changed= 1;
+ ret_value= _ma_write_keypage(info, keyinfo, anc_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, anc_buff);
+ }
+ DBUG_PRINT("exit",("Return: %d",ret_value));
+ DBUG_RETURN(ret_value);
+ }
+ }
+ }
+ leaf_buff=0;
+ LINT_INIT(leaf_page);
+ if (nod_flag)
+ {
+ /* Read left child page */
+ leaf_page= _ma_kpos(nod_flag,keypos);
+ if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
+ MARIA_MAX_KEY_BUFF*2)))
+ {
+ DBUG_PRINT("error", ("Couldn't allocate memory"));
+ my_errno=ENOMEM;
+ DBUG_RETURN(-1);
+ }
+ if (!_ma_fetch_keypage(info,keyinfo,leaf_page,
+ PAGECACHE_LOCK_WRITE, DFLT_INIT_HITS, leaf_buff,
+ 0, &leaf_page_link))
+ goto err;
+ }
+
+ if (flag != 0)
+ {
+ if (!nod_flag)
+ {
+ DBUG_PRINT("error",("Didn't find key"));
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED; /* This should newer happend */
+ goto err;
+ }
+ save_flag=0;
+ ret_value= d_search(info, key, comp_flag, leaf_page, leaf_buff,
+ leaf_page_link);
+ }
+ else
+ { /* Found key */
+ uint tmp;
+ uint anc_buff_length= _ma_get_page_used(share, anc_buff);
+ uint anc_page_flag= _ma_get_keypage_flag(share, anc_buff);
+
+ if (!(tmp= remove_key(keyinfo, anc_page_flag, nod_flag, keypos, lastkey,
+ anc_buff + anc_buff_length,
+ &next_block, &s_temp)))
+ goto err;
+
+ anc_page_link->changed= 1;
+ anc_buff_length-= tmp;
+ _ma_store_page_used(share, anc_buff, anc_buff_length);
+
+ /*
+ Log initial changes on pages
+ If there is an underflow, there will be more changes logged to the
+ page
+ */
+ if (share->now_transactional &&
+ _ma_log_delete(info, anc_page, anc_buff, s_temp.key_pos,
+ s_temp.changed_length, s_temp.move_length))
+ DBUG_RETURN(-1);
+
+ if (!nod_flag)
+ { /* On leaf page */
+ if (anc_buff_length <= (info->quick_mode ?
+ MARIA_MIN_KEYBLOCK_LENGTH :
+ (uint) keyinfo->underflow_block_length))
+ {
+ /* Page will be written by caller if we return 1 */
+ DBUG_RETURN(1);
+ }
+ if (_ma_write_keypage(info, keyinfo, anc_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
+ anc_buff))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+ }
+ save_flag=1; /* Mark that anc_buff is changed */
+ ret_value= del(info, key, anc_page, anc_buff,
+ leaf_page, leaf_buff, leaf_page_link,
+ keypos, next_block, lastkey);
+ }
+ if (ret_value >0)
+ {
+ save_flag=1;
+ if (ret_value == 1)
+ ret_value= underflow(info, keyinfo, anc_page, anc_buff,
+ leaf_page, leaf_buff, leaf_page_link, keypos);
+ else
+ {
+ /* This can only happen with variable length keys */
+ MARIA_KEY last_key;
+ DBUG_PRINT("test",("Enlarging of key when deleting"));
+
+ last_key.data= lastkey;
+ last_key.keyinfo= keyinfo;
+ if (!_ma_get_last_key(&last_key, anc_buff, keypos))
+ goto err;
+ ret_value= _ma_insert(info, key, anc_buff, keypos, anc_page,
+ last_key.data, (my_off_t) 0, (uchar*) 0,
+ (MARIA_PINNED_PAGE*) 0, (uchar*) 0, (my_bool) 0);
+ }
+ }
+ if (ret_value == 0 && _ma_get_page_used(share, anc_buff) >
+ (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
+ {
+ /* parent buffer got too big ; We have to split the page */
+ save_flag=1;
+ ret_value= _ma_split_page(info, key, anc_page, anc_buff,
+ (uint) (keyinfo->block_length -
+ KEYPAGE_CHECKSUM_SIZE),
+ (uchar*) 0, 0, 0, lastkey, 0) | 2;
+ }
+ if (save_flag && ret_value != 1)
+ {
+ anc_page_link->changed= 1;
+ ret_value|= _ma_write_keypage(info, keyinfo, anc_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, anc_buff);
+ }
+ else
+ {
+ DBUG_DUMP("page", anc_buff, _ma_get_page_used(share, anc_buff));
+ }
+ my_afree(leaf_buff);
+ DBUG_PRINT("exit",("Return: %d",ret_value));
+ DBUG_RETURN(ret_value);
+
+err:
+ my_afree(leaf_buff);
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1);
+} /* d_search */
+
+
+/**
+ @brief Remove a key that has a page-reference
+
+ @param info Maria handler
+ @param key Buffer for key to be inserted at upper level
+ @param anc_page Page address for page where deleted key was
+ @param anc_buff Page buffer (nod) where deleted key was
+ @param leaf_page Page address for nod before the deleted key
+ @param leaf_buff Buffer for leaf_page
+ @param leaf_buff_link Pinned page link for leaf_buff
+ @param keypos Pos to where deleted key was on anc_buff
+ @param next_block Page adress for nod after deleted key
+ @param ret_key_buff Key before keypos in anc_buff
+
+ @notes
+ leaf_buff must be written to disk if retval > 0
+ anc_buff is not updated on disk. Caller should do this
+
+ @return
+ @retval < 0 Error
+ @retval 0 OK. leaf_buff is written to disk
+
+ @retval 1 key contains key to upper level (from balance page)
+ leaf_buff has underflow
+ @retval 2 key contains key to upper level (from split space)
+*/
+
+static int del(MARIA_HA *info, MARIA_KEY *key,
+ my_off_t anc_page, uchar *anc_buff,
+ my_off_t leaf_page, uchar *leaf_buff,
+ MARIA_PINNED_PAGE *leaf_page_link,
+ uchar *keypos, my_off_t next_block, uchar *ret_key_buff)
+{
+ int ret_value,length;
+ uint a_length, page_flag, nod_flag, leaf_length, new_leaf_length;
+ my_off_t next_page;
+ uchar keybuff[MARIA_MAX_KEY_BUFF],*endpos,*next_buff,*key_start, *prev_key;
+ MARIA_KEY_PARAM s_temp;
+ MARIA_PINNED_PAGE *next_page_link;
+ MARIA_KEY tmp_key;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ MARIA_KEY ret_key;
+ DBUG_ENTER("del");
+ DBUG_PRINT("enter",("leaf_page: %ld keypos: 0x%lx", (long) leaf_page,
+ (ulong) keypos));
+
+ page_flag= _ma_get_keypage_flag(share, leaf_buff);
+ _ma_get_used_and_nod_with_flag(share, page_flag, leaf_buff, leaf_length,
+ nod_flag);
+ DBUG_DUMP("leaf_buff", leaf_buff, leaf_length);
+
+ endpos= leaf_buff + leaf_length;
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= keybuff;
+
+ if (!(key_start= _ma_get_last_key(&tmp_key, leaf_buff, endpos)))
+ DBUG_RETURN(-1);
+
+ if (nod_flag)
+ {
+ next_page= _ma_kpos(nod_flag,endpos);
+ if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
+ MARIA_MAX_KEY_BUFF*2)))
+ DBUG_RETURN(-1);
+ if (!_ma_fetch_keypage(info, keyinfo, next_page, PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, next_buff, 0, &next_page_link))
+ ret_value= -1;
+ else
+ {
+ DBUG_DUMP("next_page", next_buff, _ma_get_page_used(share, next_buff));
+ if ((ret_value= del(info, key, anc_page, anc_buff, next_page,
+ next_buff, next_page_link, keypos, next_block,
+ ret_key_buff)) >0)
+ {
+ /* Get new length after key was deleted */
+ endpos=leaf_buff+_ma_get_page_used(share, leaf_buff);
+ if (ret_value == 1)
+ {
+ ret_value= underflow(info, keyinfo, leaf_page, leaf_buff, next_page,
+ next_buff, next_page_link, endpos);
+ if (ret_value == 0 &&
+ _ma_get_page_used(share, leaf_buff) >
+ (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
+ {
+ ret_value= (_ma_split_page(info, key,
+ leaf_page, leaf_buff,
+ (uint) (keyinfo->block_length -
+ KEYPAGE_CHECKSUM_SIZE),
+ (uchar*) 0, 0, 0,
+ ret_key_buff, 0) | 2);
+ }
+ }
+ else
+ {
+ DBUG_PRINT("test",("Inserting of key when deleting"));
+ if (!_ma_get_last_key(&tmp_key, leaf_buff, endpos))
+ goto err;
+ ret_value= _ma_insert(info, key, leaf_buff, endpos,
+ leaf_page, tmp_key.data, (my_off_t) 0,
+ (uchar*) 0, (MARIA_PINNED_PAGE *) 0,
+ (uchar*) 0, 0);
+ }
+ }
+ leaf_page_link->changed= 1;
+ /*
+ If ret_value <> 0, then leaf_page underflowed and caller will have
+ to handle underflow and write leaf_page to disk.
+ We can't write it here, as if leaf_page is empty we get an assert
+ in _ma_write_keypage.
+ */
+ if (ret_value == 0 && _ma_write_keypage(info, keyinfo, leaf_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, leaf_buff))
+ goto err;
+ }
+ my_afree(next_buff);
+ DBUG_RETURN(ret_value);
+ }
+
+ /*
+ Remove last key from leaf page
+ Note that leaf_page page may only have had one key (can normally only
+ happen in quick mode), in which ase it will now temporary have 0 keys
+ on it. This will be corrected by the caller as we will return 0.
+ */
+ new_leaf_length= (uint) (key_start - leaf_buff);
+ _ma_store_page_used(share, leaf_buff, new_leaf_length);
+
+ if (share->now_transactional &&
+ _ma_log_suffix(info, leaf_page, leaf_buff, leaf_length,
+ new_leaf_length))
+ goto err;
+
+ leaf_page_link->changed= 1; /* Safety */
+ if (new_leaf_length <= (info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH :
+ (uint) keyinfo->underflow_block_length))
+ {
+ /* Underflow, leaf_page will be written by caller */
+ ret_value= 1;
+ }
+ else
+ {
+ ret_value= 0;
+ if (_ma_write_keypage(info, keyinfo, leaf_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
+ leaf_buff))
+ goto err;
+ }
+
+ /* Place last key in ancestor page on deleted key position */
+ a_length= _ma_get_page_used(share, anc_buff);
+ endpos=anc_buff+a_length;
+
+ ret_key.keyinfo= keyinfo;
+ ret_key.data= ret_key_buff;
+
+ prev_key= 0;
+ if (keypos != anc_buff+share->keypage_header + share->base.key_reflength)
+ {
+ if (!_ma_get_last_key(&ret_key, anc_buff, keypos))
+ goto err;
+ prev_key= ret_key.data;
+ }
+ length= (*keyinfo->pack_key)(&tmp_key, share->base.key_reflength,
+ keypos == endpos ? (uchar*) 0 : keypos,
+ prev_key, prev_key,
+ &s_temp);
+ if (length > 0)
+ bmove_upp(endpos+length,endpos,(uint) (endpos-keypos));
+ else
+ bmove(keypos,keypos-length, (int) (endpos-keypos)+length);
+ (*keyinfo->store_key)(keyinfo,keypos,&s_temp);
+ key_start= keypos;
+ if (tmp_key.flag & (SEARCH_USER_KEY_HAS_TRANSID |
+ SEARCH_PAGE_KEY_HAS_TRANSID))
+ _ma_mark_page_with_transid(share, anc_buff);
+
+ /* Save pointer to next leaf on parent page */
+ if (!(*keyinfo->get_key)(&ret_key, page_flag, share->base.key_reflength,
+ &keypos))
+ goto err;
+ _ma_kpointer(info,keypos - share->base.key_reflength,next_block);
+ _ma_store_page_used(share, anc_buff, a_length + length);
+
+ if (share->now_transactional &&
+ _ma_log_add(info, anc_page, anc_buff, a_length,
+ key_start, s_temp.changed_length, s_temp.move_length, 1))
+ goto err;
+
+ DBUG_RETURN(new_leaf_length <=
+ (info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH :
+ (uint) keyinfo->underflow_block_length));
+err:
+ DBUG_RETURN(-1);
+} /* del */
+
+
+/**
+ @brief Balances adjacent pages if underflow occours
+
+ @fn underflow()
+ @param anc_buff Anchestor page data
+ @param leaf_page Page number of leaf page
+ @param leaf_buff Leaf page (page that underflowed)
+ @param leaf_page_link Pointer to pin information about leaf page
+ @param keypos Position after current key in anc_buff
+
+ @note
+ This function writes redo entries for all changes
+ leaf_page is saved to disk
+ Caller must save anc_buff
+
+ @return
+ @retval 0 ok
+ @retval 1 ok, but anc_buff did underflow
+ @retval -1 error
+ */
+
+static int underflow(register MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ my_off_t anc_page, uchar *anc_buff,
+ my_off_t leaf_page, uchar *leaf_buff,
+ MARIA_PINNED_PAGE *leaf_page_link,
+ uchar *keypos)
+{
+ int t_length;
+ uint anc_length,buff_length,leaf_length,p_length,s_length,nod_flag;
+ uint next_buff_length, new_buff_length, key_reflength;
+ uint unchanged_leaf_length, new_leaf_length, new_anc_length;
+ uint anc_page_flag, page_flag;
+ my_off_t next_page;
+ uchar anc_key_buff[MARIA_MAX_KEY_BUFF], leaf_key_buff[MARIA_MAX_KEY_BUFF];
+ uchar *buff,*endpos,*next_keypos,*anc_pos,*half_pos,*prev_key;
+ uchar *after_key, *anc_end_pos;
+ MARIA_KEY_PARAM key_deleted, key_inserted;
+ MARIA_SHARE *share= info->s;
+ MARIA_PINNED_PAGE *next_page_link;
+ my_bool first_key;
+ MARIA_KEY tmp_key, anc_key, leaf_key;
+ DBUG_ENTER("underflow");
+ DBUG_PRINT("enter",("leaf_page: %ld keypos: 0x%lx",(long) leaf_page,
+ (ulong) keypos));
+ DBUG_DUMP("anc_buff", anc_buff, _ma_get_page_used(share, anc_buff));
+ DBUG_DUMP("leaf_buff", leaf_buff, _ma_get_page_used(share, leaf_buff));
+
+ anc_page_flag= _ma_get_keypage_flag(share, anc_buff);
+ buff=info->buff;
+ info->keyread_buff_used=1;
+ next_keypos=keypos;
+ nod_flag= _ma_test_if_nod(share, leaf_buff);
+ p_length= nod_flag+share->keypage_header;
+ anc_length= _ma_get_page_used(share, anc_buff);
+ leaf_length= _ma_get_page_used(share, leaf_buff);
+ key_reflength=share->base.key_reflength;
+ if (share->keyinfo+info->lastinx == keyinfo)
+ info->page_changed=1;
+ first_key= keypos == anc_buff + share->keypage_header + key_reflength;
+
+ tmp_key.data= buff;
+ anc_key.data= anc_key_buff;
+ leaf_key.data= leaf_key_buff;
+ tmp_key.keyinfo= leaf_key.keyinfo= anc_key.keyinfo= keyinfo;
+
+ if ((keypos < anc_buff + anc_length && (info->state->records & 1)) ||
+ first_key)
+ {
+ size_t tmp_length;
+ uint next_page_flag;
+ /* Use page right of anc-page */
+ DBUG_PRINT("test",("use right page"));
+
+ /*
+ Calculate position after the current key. Note that keydata itself is
+ not used
+ */
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ {
+ if (!(next_keypos= _ma_get_key(&tmp_key, anc_buff, keypos)))
+ goto err;
+ }
+ else
+ {
+ /* Got to end of found key */
+ buff[0]=buff[1]=0; /* Avoid length error check if packed key */
+ if (!(*keyinfo->get_key)(&tmp_key, anc_page_flag, key_reflength,
+ &next_keypos))
+ goto err;
+ }
+ next_page= _ma_kpos(key_reflength,next_keypos);
+ if (!_ma_fetch_keypage(info,keyinfo, next_page, PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, buff, 0, &next_page_link))
+ goto err;
+ next_buff_length= _ma_get_page_used(share, buff);
+ next_page_flag= _ma_get_keypage_flag(share,buff);
+ DBUG_DUMP("next", buff, next_buff_length);
+
+ /* find keys to make a big key-page */
+ bmove(next_keypos-key_reflength, buff + share->keypage_header,
+ key_reflength);
+
+ if (!_ma_get_last_key(&anc_key, anc_buff, next_keypos) ||
+ !_ma_get_last_key(&leaf_key, leaf_buff, leaf_buff+leaf_length))
+ goto err;
+
+ /* merge pages and put parting key from anc_buff between */
+ prev_key= (leaf_length == p_length ? (uchar*) 0 : leaf_key.data);
+ t_length= (*keyinfo->pack_key)(&anc_key, nod_flag, buff+p_length,
+ prev_key, prev_key, &key_inserted);
+ tmp_length= next_buff_length - p_length;
+ endpos= buff+tmp_length+leaf_length+t_length;
+ /* buff will always be larger than before !*/
+ bmove_upp(endpos, buff + next_buff_length, tmp_length);
+ memcpy(buff, leaf_buff,(size_t) leaf_length);
+ (*keyinfo->store_key)(keyinfo, buff+leaf_length, &key_inserted);
+ buff_length= (uint) (endpos-buff);
+ _ma_store_page_used(share, buff, buff_length);
+
+ /* Set page flag from combination of both key pages and parting key */
+ page_flag= (next_page_flag |
+ _ma_get_keypage_flag(share, leaf_buff));
+ if (anc_key.flag & (SEARCH_USER_KEY_HAS_TRANSID |
+ SEARCH_PAGE_KEY_HAS_TRANSID))
+ page_flag|= KEYPAGE_FLAG_HAS_TRANSID;
+ _ma_store_keypage_flag(share, buff, page_flag);
+
+ /* remove key from anc_buff */
+ if (!(s_length=remove_key(keyinfo, anc_page_flag, key_reflength, keypos,
+ anc_key_buff, anc_buff+anc_length,
+ (my_off_t *) 0, &key_deleted)))
+ goto err;
+
+ new_anc_length= anc_length - s_length;
+ _ma_store_page_used(share, anc_buff, new_anc_length);
+
+ if (buff_length <= (uint) (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
+ {
+ /* All keys fitted into one page */
+ next_page_link->changed= 1;
+ if (_ma_dispose(info, next_page, 0))
+ goto err;
+
+ memcpy(leaf_buff, buff, (size_t) buff_length);
+
+ if (share->now_transactional)
+ {
+ /* Log changes to parent page */
+ if (_ma_log_delete(info, anc_page, anc_buff, key_deleted.key_pos,
+ key_deleted.changed_length,
+ key_deleted.move_length))
+ goto err;
+ /*
+ Log changes to leaf page. Data for leaf page is in buff
+ which contains original leaf_buff, parting key and next_buff
+ */
+ if (_ma_log_suffix(info, leaf_page, leaf_buff,
+ leaf_length, buff_length))
+ goto err;
+ }
+ }
+ else
+ {
+ /*
+ Balancing didn't free a page, so we have to split 'buff' into two
+ pages:
+ - Find key in middle of buffer
+ - Store everything before key in 'leaf_buff'
+ - Pack key into anc_buff at position of deleted key
+ Note that anc_buff may overflow! (is handled by caller)
+ - Store remaining keys in next_page (buff)
+ */
+ MARIA_KEY_PARAM anc_key_inserted;
+
+ anc_end_pos= anc_buff + new_anc_length;
+
+ DBUG_PRINT("test",("anc_buff: 0x%lx anc_end_pos: 0x%lx",
+ (long) anc_buff, (long) anc_end_pos));
+
+ if (!first_key && !_ma_get_last_key(&anc_key, anc_buff, keypos))
+ goto err;
+ if (!(half_pos= _ma_find_half_pos(info, &leaf_key, nod_flag, buff,
+ &after_key)))
+ goto err;
+ new_leaf_length= (uint) (half_pos-buff);
+ memcpy(leaf_buff, buff, (size_t) new_leaf_length);
+ _ma_store_page_used(share, leaf_buff, new_leaf_length);
+ _ma_store_keypage_flag(share, leaf_buff, page_flag);
+
+ /* Correct new keypointer to leaf_page */
+ half_pos=after_key;
+ _ma_kpointer(info,
+ leaf_key.data+leaf_key.data_length + leaf_key.ref_length,
+ next_page);
+
+ /* Save key in anc_buff */
+ prev_key= (first_key ? (uchar*) 0 : anc_key.data);
+ t_length= (*keyinfo->pack_key)(&leaf_key, key_reflength,
+ (keypos == anc_end_pos ? (uchar*) 0 :
+ keypos),
+ prev_key, prev_key, &anc_key_inserted);
+ if (t_length >= 0)
+ bmove_upp(anc_end_pos+t_length, anc_end_pos,
+ (uint) (anc_end_pos - keypos));
+ else
+ bmove(keypos,keypos-t_length,(uint) (anc_end_pos-keypos)+t_length);
+ (*keyinfo->store_key)(keyinfo,keypos, &anc_key_inserted);
+ new_anc_length+= t_length;
+ _ma_store_page_used(share, anc_buff, new_anc_length);
+ if (leaf_key.flag & (SEARCH_USER_KEY_HAS_TRANSID |
+ SEARCH_PAGE_KEY_HAS_TRANSID))
+ _ma_mark_page_with_transid(share, anc_buff);
+
+ /* Store key first in new page */
+ if (nod_flag)
+ bmove(buff+share->keypage_header, half_pos-nod_flag,
+ (size_t) nod_flag);
+ if (!(*keyinfo->get_key)(&leaf_key, page_flag, nod_flag, &half_pos))
+ goto err;
+ t_length=(int) (*keyinfo->pack_key)(&leaf_key, nod_flag, (uchar*) 0,
+ (uchar*) 0, (uchar*) 0,
+ &key_inserted);
+ /* t_length will always be > 0 for a new page !*/
+ tmp_length= (size_t) ((buff + buff_length) - half_pos);
+ bmove(buff+p_length+t_length, half_pos, tmp_length);
+ (*keyinfo->store_key)(keyinfo,buff+p_length, &key_inserted);
+ new_buff_length= tmp_length + t_length + p_length;
+ _ma_store_page_used(share, buff, new_buff_length);
+ /* keypage flag is already up to date */
+
+ if (share->now_transactional)
+ {
+ /*
+ Log changes to parent page
+ This has one key deleted from it and one key inserted to it at
+ keypos
+
+ ma_log_add ensures that we don't log changes that is outside of
+ key block size, as the REDO code can't handle that
+ */
+ if (_ma_log_add(info, anc_page, anc_buff, anc_length,
+ keypos,
+ anc_key_inserted.move_length +
+ max(anc_key_inserted.changed_length -
+ anc_key_inserted.move_length,
+ key_deleted.changed_length),
+ anc_key_inserted.move_length -
+ key_deleted.move_length, 1))
+ goto err;
+
+ /*
+ Log changes to leaf page.
+ This contains original data with new data added at end
+ */
+ DBUG_ASSERT(leaf_length <= new_leaf_length);
+ if (_ma_log_suffix(info, leaf_page, leaf_buff, leaf_length,
+ new_leaf_length))
+ goto err;
+ /*
+ Log changes to next page
+
+ This contains original data with some prefix data deleted and
+ some compressed data at start possible extended
+
+ Data in buff was originally:
+ org_leaf_buff [leaf_length]
+ separator_key [buff_key_inserted.move_length]
+ next_key_changes [buff_key_inserted.changed_length -move_length]
+ next_page_data [next_buff_length - p_length -
+ (buff_key_inserted.changed_length -move_length)]
+
+ After changes it's now:
+ unpacked_key [key_inserted.changed_length]
+ next_suffix [next_buff_length - key_inserted.changed_length]
+
+ */
+ DBUG_ASSERT(new_buff_length <= next_buff_length);
+ if (_ma_log_prefix(info, next_page, buff,
+ key_inserted.changed_length,
+ (int) (new_buff_length - next_buff_length)))
+ goto err;
+ }
+ next_page_link->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, next_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
+ buff))
+ goto err;
+ }
+
+ leaf_page_link->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, leaf_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
+ leaf_buff))
+ goto err;
+ DBUG_RETURN(new_anc_length <=
+ ((info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH :
+ (uint) keyinfo->underflow_block_length)));
+ }
+
+ DBUG_PRINT("test",("use left page"));
+
+ keypos= _ma_get_last_key(&anc_key, anc_buff, keypos);
+ if (!keypos)
+ goto err;
+ next_page= _ma_kpos(key_reflength,keypos);
+ if (!_ma_fetch_keypage(info, keyinfo, next_page, PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, buff, 0, &next_page_link))
+ goto err;
+ buff_length= _ma_get_page_used(share, buff);
+ endpos= buff + buff_length;
+ DBUG_DUMP("prev",buff,buff_length);
+
+ /* find keys to make a big key-page */
+ bmove(next_keypos - key_reflength, leaf_buff + share->keypage_header,
+ key_reflength);
+ next_keypos=keypos;
+ if (!(*keyinfo->get_key)(&anc_key, anc_page_flag, key_reflength,
+ &next_keypos))
+ goto err;
+ if (!_ma_get_last_key(&leaf_key, buff, endpos))
+ goto err;
+
+ /* merge pages and put parting key from anc_buff between */
+ prev_key= (leaf_length == p_length ? (uchar*) 0 : leaf_key.data);
+ t_length=(*keyinfo->pack_key)(&anc_key, nod_flag,
+ (leaf_length == p_length ?
+ (uchar*) 0 : leaf_buff+p_length),
+ prev_key, prev_key,
+ &key_inserted);
+ if (t_length >= 0)
+ bmove(endpos+t_length, leaf_buff+p_length,
+ (size_t) (leaf_length-p_length));
+ else /* We gained space */
+ bmove(endpos,leaf_buff+((int) p_length-t_length),
+ (size_t) (leaf_length-p_length+t_length));
+ (*keyinfo->store_key)(keyinfo,endpos, &key_inserted);
+
+ /* Remember for logging how many bytes of leaf_buff that are not changed */
+ DBUG_ASSERT((int) key_inserted.changed_length >= key_inserted.move_length);
+ unchanged_leaf_length= leaf_length - (key_inserted.changed_length -
+ key_inserted.move_length);
+
+ new_buff_length= buff_length + leaf_length - p_length + t_length;
+ _ma_store_page_used(share, buff, new_buff_length);
+
+ page_flag= (_ma_get_keypage_flag(share, buff) |
+ _ma_get_keypage_flag(share, leaf_buff));
+ if (anc_key.flag & (SEARCH_USER_KEY_HAS_TRANSID |
+ SEARCH_PAGE_KEY_HAS_TRANSID))
+ page_flag|= KEYPAGE_FLAG_HAS_TRANSID;
+ _ma_store_keypage_flag(share, buff, page_flag);
+
+ /* remove key from anc_buff */
+ if (!(s_length= remove_key(keyinfo, anc_page_flag, key_reflength, keypos,
+ anc_key_buff,
+ anc_buff+anc_length, (my_off_t *) 0,
+ &key_deleted)))
+ goto err;
+
+ new_anc_length= anc_length - s_length;
+ _ma_store_page_used(share, anc_buff, new_anc_length);
+
+ if (new_buff_length <= (uint) (keyinfo->block_length -
+ KEYPAGE_CHECKSUM_SIZE))
+ {
+ /* All keys fitted into one page */
+ leaf_page_link->changed= 1;
+ if (_ma_dispose(info, leaf_page, 0))
+ goto err;
+
+ if (share->now_transactional)
+ {
+ /* Log changes to parent page */
+ if (_ma_log_delete(info, anc_page, anc_buff, key_deleted.key_pos,
+ key_deleted.changed_length, key_deleted.move_length))
+
+ goto err;
+ /*
+ Log changes to next page. Data for leaf page is in buff
+ that contains original leaf_buff, parting key and next_buff
+ */
+ if (_ma_log_suffix(info, next_page, buff,
+ buff_length, new_buff_length))
+ goto err;
+ }
+ }
+ else
+ {
+ /*
+ Balancing didn't free a page, so we have to split 'buff' into two
+ pages
+ - Find key in middle of buffer (buff)
+ - Pack key at half_buff into anc_buff at position of deleted key
+ Note that anc_buff may overflow! (is handled by caller)
+ - Move everything after middlekey to 'leaf_buff'
+ - Shorten buff at 'endpos'
+ */
+ MARIA_KEY_PARAM anc_key_inserted;
+ size_t tmp_length;
+
+ if (keypos == anc_buff + share->keypage_header + key_reflength)
+ anc_pos= 0; /* First key */
+ else
+ {
+ if (!_ma_get_last_key(&anc_key, anc_buff, keypos))
+ goto err;
+ anc_pos= anc_key.data;
+ }
+ if (!(endpos= _ma_find_half_pos(info, &leaf_key, nod_flag, buff,
+ &half_pos)))
+ goto err;
+
+ /* Correct new keypointer to leaf_page */
+ _ma_kpointer(info,leaf_key.data + leaf_key.data_length +
+ leaf_key.ref_length, leaf_page);
+
+ /* Save key in anc_buff */
+ DBUG_DUMP("anc_buff", anc_buff, new_anc_length);
+ DBUG_DUMP_KEY("key_to_anc", &leaf_key);
+ anc_end_pos= anc_buff + new_anc_length;
+ t_length=(*keyinfo->pack_key)(&leaf_key, key_reflength,
+ keypos == anc_end_pos ? (uchar*) 0
+ : keypos,
+ anc_pos, anc_pos,
+ &anc_key_inserted);
+ if (t_length >= 0)
+ bmove_upp(anc_end_pos+t_length, anc_end_pos,
+ (uint) (anc_end_pos-keypos));
+ else
+ bmove(keypos,keypos-t_length,(uint) (anc_end_pos-keypos)+t_length);
+ (*keyinfo->store_key)(keyinfo,keypos, &anc_key_inserted);
+ new_anc_length+= t_length;
+ _ma_store_page_used(share, anc_buff, new_anc_length);
+ if (leaf_key.flag & (SEARCH_USER_KEY_HAS_TRANSID |
+ SEARCH_PAGE_KEY_HAS_TRANSID))
+ _ma_mark_page_with_transid(share, anc_buff);
+
+ /* Store first key on new page */
+ if (nod_flag)
+ bmove(leaf_buff + share->keypage_header, half_pos-nod_flag,
+ (size_t) nod_flag);
+ if (!(*keyinfo->get_key)(&leaf_key, page_flag, nod_flag, &half_pos))
+ goto err;
+ DBUG_DUMP_KEY("key_to_leaf", &leaf_key);
+ t_length=(*keyinfo->pack_key)(&leaf_key, nod_flag, (uchar*) 0,
+ (uchar*) 0, (uchar*) 0, &key_inserted);
+ /* t_length will always be > 0 for a new page !*/
+ tmp_length= (size_t) ((buff + new_buff_length) - half_pos);
+ DBUG_PRINT("info",("t_length: %d length: %d",t_length, (int) tmp_length));
+ bmove(leaf_buff+p_length+t_length, half_pos, tmp_length);
+ (*keyinfo->store_key)(keyinfo,leaf_buff+p_length, &key_inserted);
+ new_leaf_length= tmp_length + t_length + p_length;
+ _ma_store_page_used(share, leaf_buff, new_leaf_length);
+ _ma_store_keypage_flag(share, leaf_buff, page_flag);
+ new_buff_length= (uint) (endpos - buff);
+ _ma_store_page_used(share, buff, new_buff_length);
+
+ if (share->now_transactional)
+ {
+ /*
+ Log changes to parent page
+ This has one key deleted from it and one key inserted to it at
+ keypos
+
+ ma_log_add() ensures that we don't log changes that is outside of
+ key block size, as the REDO code can't handle that
+ */
+ if (_ma_log_add(info, anc_page, anc_buff, anc_length,
+ keypos,
+ anc_key_inserted.move_length +
+ max(anc_key_inserted.changed_length -
+ anc_key_inserted.move_length,
+ key_deleted.changed_length),
+ anc_key_inserted.move_length -
+ key_deleted.move_length, 1))
+ goto err;
+
+ /*
+ Log changes to leaf page.
+ This contains original data with new data added first
+ */
+ DBUG_ASSERT(leaf_length <= new_leaf_length);
+ if (_ma_log_prefix(info, leaf_page, leaf_buff,
+ new_leaf_length - unchanged_leaf_length,
+ (int) (new_leaf_length - leaf_length)))
+ goto err;
+ /*
+ Log changes to next page
+ This contains original data with some suffix data deleted
+
+ */
+ DBUG_ASSERT(new_buff_length <= buff_length);
+ if (_ma_log_suffix(info, next_page, buff,
+ buff_length, new_buff_length))
+ goto err;
+ }
+
+ leaf_page_link->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, leaf_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
+ leaf_buff))
+ goto err;
+ }
+ next_page_link->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, next_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS, buff))
+ goto err;
+
+ DBUG_RETURN(new_anc_length <=
+ ((info->quick_mode ? MARIA_MIN_KEYBLOCK_LENGTH :
+ (uint) keyinfo->underflow_block_length)));
+
+err:
+ DBUG_RETURN(-1);
+} /* underflow */
+
+
+/**
+ @brief Remove a key from page
+
+ @fn remove_key()
+ keyinfo Key handle
+ nod_flag Length of node ptr
+ keypos Where on page key starts
+ lastkey Buffer for storing keys to be removed
+ page_end Pointer to end of page
+ next_block If <> 0 and node-page, this is set to address of
+ next page
+ s_temp Information about what changes was done one the page:
+ s_temp.key_pos Start of key
+ s_temp.move_length Number of bytes removed at keypos
+ s_temp.changed_length Number of bytes changed at keypos
+
+ @todo
+ The current code doesn't handle the case that the next key may be
+ packed better against the previous key if there is a case difference
+
+ @return
+ @retval 0 error
+ @retval # How many chars was removed
+*/
+
+static uint remove_key(MARIA_KEYDEF *keyinfo, uint page_flag, uint nod_flag,
+ uchar *keypos, uchar *lastkey,
+ uchar *page_end, my_off_t *next_block,
+ MARIA_KEY_PARAM *s_temp)
+{
+ int s_length;
+ uchar *start;
+ DBUG_ENTER("remove_key");
+ DBUG_PRINT("enter", ("keypos: 0x%lx page_end: 0x%lx",
+ (long) keypos, (long) page_end));
+
+ start= s_temp->key_pos= keypos;
+ s_temp->changed_length= 0;
+ if (!(keyinfo->flag &
+ (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
+ HA_BINARY_PACK_KEY)) &&
+ !(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ {
+ /* Static length key */
+ s_length=(int) (keyinfo->keylength+nod_flag);
+ if (next_block && nod_flag)
+ *next_block= _ma_kpos(nod_flag,keypos+s_length);
+ }
+ else
+ {
+ /* Let keypos point at next key */
+ MARIA_KEY key;
+
+ /* Calculate length of key */
+ key.keyinfo= keyinfo;
+ key.data= lastkey;
+ if (!(*keyinfo->get_key)(&key, page_flag, nod_flag, &keypos))
+ DBUG_RETURN(0); /* Error */
+
+ if (next_block && nod_flag)
+ *next_block= _ma_kpos(nod_flag,keypos);
+ s_length=(int) (keypos-start);
+ if (keypos != page_end)
+ {
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ {
+ uchar *old_key= start;
+ uint next_length,prev_length,prev_pack_length;
+
+ /* keypos points here on start of next key */
+ get_key_length(next_length,keypos);
+ get_key_pack_length(prev_length,prev_pack_length,old_key);
+ if (next_length > prev_length)
+ {
+ uint diff= (next_length-prev_length);
+ /* We have to copy data from the current key to the next key */
+ keypos-= diff + prev_pack_length;
+ store_key_length(keypos, prev_length);
+ bmove(keypos + prev_pack_length, lastkey + prev_length, diff);
+ s_length=(int) (keypos-start);
+ s_temp->changed_length= diff + prev_pack_length;
+ }
+ }
+ else
+ {
+ /* Check if a variable length first key part */
+ if ((keyinfo->seg->flag & HA_PACK_KEY) && *keypos & 128)
+ {
+ /* Next key is packed against the current one */
+ uint next_length,prev_length,prev_pack_length,lastkey_length,
+ rest_length;
+ if (keyinfo->seg[0].length >= 127)
+ {
+ if (!(prev_length=mi_uint2korr(start) & 32767))
+ goto end;
+ next_length=mi_uint2korr(keypos) & 32767;
+ keypos+=2;
+ prev_pack_length=2;
+ }
+ else
+ {
+ if (!(prev_length= *start & 127))
+ goto end; /* Same key as previous*/
+ next_length= *keypos & 127;
+ keypos++;
+ prev_pack_length=1;
+ }
+ if (!(*start & 128))
+ prev_length=0; /* prev key not packed */
+ if (keyinfo->seg[0].flag & HA_NULL_PART)
+ lastkey++; /* Skip null marker */
+ get_key_length(lastkey_length,lastkey);
+ if (!next_length) /* Same key after */
+ {
+ next_length=lastkey_length;
+ rest_length=0;
+ }
+ else
+ get_key_length(rest_length,keypos);
+
+ if (next_length >= prev_length)
+ {
+ /* Next key is based on deleted key */
+ uint pack_length;
+ uint diff= (next_length-prev_length);
+
+ /* keypos points to data of next key (after key length) */
+ bmove(keypos - diff, lastkey + prev_length, diff);
+ rest_length+= diff;
+ pack_length= prev_length ? get_pack_length(rest_length): 0;
+ keypos-= diff + pack_length + prev_pack_length;
+ s_length=(int) (keypos-start);
+ if (prev_length) /* Pack against prev key */
+ {
+ *keypos++= start[0];
+ if (prev_pack_length == 2)
+ *keypos++= start[1];
+ store_key_length(keypos,rest_length);
+ }
+ else
+ {
+ /* Next key is not packed anymore */
+ if (keyinfo->seg[0].flag & HA_NULL_PART)
+ {
+ rest_length++; /* Mark not null */
+ }
+ if (prev_pack_length == 2)
+ {
+ mi_int2store(keypos,rest_length);
+ }
+ else
+ *keypos= rest_length;
+ }
+ s_temp->changed_length= diff + pack_length + prev_pack_length;
+ }
+ }
+ }
+ }
+ }
+ end:
+ bmove(start, start+s_length, (uint) (page_end-start-s_length));
+ s_temp->move_length= s_length;
+ DBUG_RETURN((uint) s_length);
+} /* remove_key */
+
+
+/****************************************************************************
+ Logging of redos
+****************************************************************************/
+
+/**
+ @brief log entry where some parts are deleted and some things are changed
+
+ @fn _ma_log_delete()
+ @param info Maria handler
+ @param page Pageaddress for changed page
+ @param buff Page buffer
+ @param key_pos Start of change area
+ @param changed_length How many bytes where changed at key_pos
+ @param move_length How many bytes where deleted at key_pos
+
+*/
+
+my_bool _ma_log_delete(MARIA_HA *info, my_off_t page, const uchar *buff,
+ const uchar *key_pos, uint changed_length,
+ uint move_length)
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 9 + 7], *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
+ MARIA_SHARE *share= info->s;
+ uint translog_parts;
+ uint offset= (uint) (key_pos - buff);
+ DBUG_ENTER("_ma_log_delete");
+ DBUG_PRINT("enter", ("page: %lu changed_length: %u move_length: %d",
+ (ulong) page, changed_length, move_length));
+ DBUG_ASSERT(share->now_transactional && move_length);
+ DBUG_ASSERT(offset + changed_length <= _ma_get_page_used(share, buff));
+
+ /* Store address of new root page */
+ page/= share->block_size;
+ page_store(log_data + FILEID_STORE_SIZE, page);
+ log_pos= log_data+ FILEID_STORE_SIZE + PAGE_STORE_SIZE;
+ log_pos[0]= KEY_OP_OFFSET;
+ int2store(log_pos+1, offset);
+ log_pos[3]= KEY_OP_SHIFT;
+ int2store(log_pos+4, -(int) move_length);
+ log_pos+= 6;
+ translog_parts= 1;
+ if (changed_length)
+ {
+ log_pos[0]= KEY_OP_CHANGE;
+ int2store(log_pos+1, changed_length);
+ log_pos+= 3;
+ translog_parts= 2;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= buff + offset;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= changed_length;
+ }
+
+#ifdef EXTRA_DEBUG_KEY_CHANGES
+ {
+ int page_length= _ma_get_page_used(share, buff);
+ ha_checksum crc;
+ crc= my_checksum(0, buff + LSN_STORE_SIZE, page_length - LSN_STORE_SIZE);
+ log_pos[0]= KEY_OP_CHECK;
+ int2store(log_pos+1, page_length);
+ int4store(log_pos+3, crc);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= log_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= 7;
+ changed_length+= 7;
+ translog_parts++;
+ }
+#endif
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos - log_data);
+
+ if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length +
+ changed_length,
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/****************************************************************************
+ Logging of undos
+****************************************************************************/
+
+int _ma_write_undo_key_delete(MARIA_HA *info, const MARIA_KEY *key,
+ my_off_t new_root, LSN *res_lsn)
+{
+ MARIA_SHARE *share= info->s;
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ KEY_NR_STORE_SIZE + PAGE_STORE_SIZE], *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ struct st_msg_to_write_hook_for_undo_key msg;
+ enum translog_record_type log_type= LOGREC_UNDO_KEY_DELETE;
+ uint keynr= key->keyinfo->key_nr;
+
+ lsn_store(log_data, info->trn->undo_lsn);
+ key_nr_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE, keynr);
+ log_pos= log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE;
+
+ /**
+ @todo BUG if we had concurrent insert/deletes, reading state's key_root
+ like this would be unsafe.
+ */
+ if (new_root != share->state.key_root[keynr])
+ {
+ my_off_t page;
+ page= ((new_root == HA_OFFSET_ERROR) ? IMPOSSIBLE_PAGE_NO :
+ new_root / share->block_size);
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+ log_type= LOGREC_UNDO_KEY_DELETE_WITH_ROOT;
+ }
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos - log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key->data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= (key->data_length +
+ key->ref_length);
+
+ msg.root= &share->state.key_root[keynr];
+ msg.value= new_root;
+ /*
+ set autoincrement to 1 if this is an auto_increment key
+ This is only used if we are now in a rollback of a duplicate key
+ */
+ msg.auto_increment= share->base.auto_key == keynr + 1;
+
+ return translog_write_record(res_lsn, log_type,
+ info->trn, info,
+ (translog_size_t)
+ (log_array[TRANSLOG_INTERNAL_PARTS + 0].length +
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length),
+ TRANSLOG_INTERNAL_PARTS + 2, log_array,
+ log_data + LSN_STORE_SIZE, &msg) ? -1 : 0;
+}
diff --git a/storage/maria/ma_delete_all.c b/storage/maria/ma_delete_all.c
new file mode 100644
index 00000000000..4661ea0ab59
--- /dev/null
+++ b/storage/maria/ma_delete_all.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Remove all rows from a MARIA table */
+/* This clears the status information and truncates files */
+
+#include "maria_def.h"
+#include "trnman.h"
+
+/**
+ @brief deletes all rows from a table
+
+ @param info Maria handler
+
+ @note It is important that this function does not rely on the state
+ information, as it may be called by ma_apply_undo_bulk_insert() on an
+ inconsistent table left by a crash.
+
+ @return Operation status
+ @retval 0 ok
+ @retval 1 error
+*/
+
+int maria_delete_all_rows(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ my_bool log_record;
+ LSN lsn;
+ DBUG_ENTER("maria_delete_all_rows");
+
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ /**
+ @todo LOCK take X-lock on table here.
+ When we have versioning, if some other thread is looking at this table,
+ we cannot shrink the file like this.
+ */
+ if (_ma_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+ log_record= share->now_transactional && !share->temporary;
+ if (_ma_mark_file_changed(info))
+ goto err;
+
+ if (log_record)
+ {
+ /*
+ This record will be used by Recovery to finish the deletion if it
+ crashed. We force it to have a complete history in the log.
+ */
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ uchar log_data[FILEID_STORE_SIZE];
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ if (unlikely(translog_write_record(&lsn, LOGREC_REDO_DELETE_ALL,
+ info->trn, info, 0,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, log_data, NULL) ||
+ translog_flush(lsn)))
+ goto err;
+ /*
+ If we fail in this function after this point, log and table will be
+ inconsistent.
+ */
+ }
+ else
+ {
+ /* Other branch called function below when writing log record, in hook */
+ _ma_reset_status(info);
+ }
+ /* Remove old history as the table is now empty for everyone */
+ _ma_reset_state(info);
+
+ /*
+ If we are using delayed keys or if the user has done changes to the tables
+ since it was locked then there may be key blocks in the page cache. Or
+ there may be data blocks there. We need to throw them away or they may
+ re-enter the emptied table or another table later.
+ */
+
+#ifdef HAVE_MMAP
+ if (share->file_map)
+ _ma_unmap_file(info);
+#endif
+
+ if (_ma_flush_table_files(info, MARIA_FLUSH_DATA|MARIA_FLUSH_INDEX,
+ FLUSH_IGNORE_CHANGED, FLUSH_IGNORE_CHANGED) ||
+ my_chsize(info->dfile.file, 0, 0, MYF(MY_WME)) ||
+ my_chsize(share->kfile.file, share->base.keystart, 0, MYF(MY_WME)))
+ goto err;
+
+ if (_ma_initialize_data_file(share, info->dfile.file))
+ goto err;
+
+ if (log_record)
+ {
+ /*
+ Because LOGREC_REDO_DELETE_ALL does not operate on pages, it has the
+ following problem:
+ delete_all; inserts (redo_insert); all pages get flushed; checkpoint:
+ the dirty pages list will be empty. In recovery, delete_all is executed,
+ but redo_insert are skipped (dirty pages list is empty).
+ To avoid this, we need to set skip_redo_lsn now, and thus need to sync
+ files.
+ Also fixes the problem of:
+ bulk insert; insert; delete_all; crash:
+ "bulk insert" is skipped (no REDOs), so if "insert" would not be skipped
+ (if we didn't update skip_redo_lsn below) then "insert" would be tried
+ and fail, saying that it sees that the first page has to be created
+ though the inserted row has rownr>0.
+ */
+ my_bool error= _ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_LOCK) ||
+ _ma_update_state_lsns(share, lsn, trnman_get_min_trid(), FALSE, FALSE) ||
+ _ma_sync_table_files(info);
+ info->trn->rec_lsn= LSN_IMPOSSIBLE;
+ if (error)
+ goto err;
+ }
+
+ VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+#ifdef HAVE_MMAP
+ /* Map again */
+ if (share->file_map)
+ _ma_dynmap_file(info, (my_off_t) 0);
+#endif
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ {
+ int save_errno=my_errno;
+ VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ info->update|=HA_STATE_WRITTEN; /* Buffer changed */
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(my_errno=save_errno);
+ }
+} /* maria_delete_all_rows */
+
+
+/*
+ Reset status information
+
+ SYNOPSIS
+ _ma_reset_status()
+ maria Maria handler
+
+ DESCRIPTION
+ Resets data and index file information as if the file would be empty
+ Files are not touched.
+*/
+
+void _ma_reset_status(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_STATE_INFO *state= &share->state;
+ uint i;
+ DBUG_ENTER("_ma_reset_status");
+
+ state->split= 0;
+ state->state.records= state->state.del= 0;
+ state->changed= 0; /* File is optimized */
+ state->dellink= HA_OFFSET_ERROR;
+ state->sortkey= (ushort) ~0;
+ state->state.key_file_length= share->base.keystart;
+ state->state.data_file_length= 0;
+ state->state.empty= state->state.key_empty= 0;
+ state->state.checksum= 0;
+
+ *info->state= state->state;
+
+ /* Drop the delete key chain. */
+ state->key_del= HA_OFFSET_ERROR;
+ /* Clear all keys */
+ for (i=0 ; i < share->base.keys ; i++)
+ state->key_root[i]= HA_OFFSET_ERROR;
+ DBUG_VOID_RETURN;
+}
diff --git a/storage/maria/ma_delete_table.c b/storage/maria/ma_delete_table.c
new file mode 100644
index 00000000000..0237bb884c5
--- /dev/null
+++ b/storage/maria/ma_delete_table.c
@@ -0,0 +1,107 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "ma_fulltext.h"
+#include "trnman_public.h"
+
+/**
+ @brief drops (deletes) a table
+
+ @param name table's name
+
+ @return Operation status
+ @retval 0 ok
+ @retval 1 error
+*/
+
+int maria_delete_table(const char *name)
+{
+ char from[FN_REFLEN];
+#ifdef USE_RAID
+ uint raid_type=0,raid_chunks=0;
+#endif
+ MARIA_HA *info;
+ myf sync_dir;
+ DBUG_ENTER("maria_delete_table");
+
+#ifdef EXTRA_DEBUG
+ _ma_check_table_is_closed(name,"delete");
+#endif
+ /** @todo LOCK take X-lock on table */
+ /*
+ We need to know if this table is transactional.
+ When built with RAID support, we also need to determine if this table
+ makes use of the raid feature. If yes, we need to remove all raid
+ chunks. This is done with my_raid_delete(). Unfortunately it is
+ necessary to open the table just to check this. We use
+ 'open_for_repair' to be able to open even a crashed table. If even
+ this open fails, we assume no raid configuration for this table
+ and try to remove the normal data file only. This may however
+ leave the raid chunks behind.
+ */
+ if (!(info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR)))
+ {
+#ifdef USE_RAID
+ raid_type= 0;
+#endif
+ sync_dir= 0;
+ }
+ else
+ {
+#ifdef USE_RAID
+ raid_type= info->s->base.raid_type;
+ raid_chunks= info->s->base.raid_chunks;
+#endif
+ sync_dir= (info->s->now_transactional && !info->s->temporary &&
+ !maria_in_recovery) ?
+ MY_SYNC_DIR : 0;
+ maria_close(info);
+ }
+
+ if (sync_dir)
+ {
+ /*
+ For this log record to be of any use for Recovery, we need the upper
+ MySQL layer to be crash-safe in DDLs.
+ For now this record can serve when we apply logs to a backup, so we sync
+ it.
+ */
+ LSN lsn;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (uchar*)name;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= strlen(name) + 1;
+ if (unlikely(translog_write_record(&lsn, LOGREC_REDO_DROP_TABLE,
+ &dummy_transaction_object, NULL,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL) ||
+ translog_flush(lsn)))
+ DBUG_RETURN(1);
+ }
+
+ fn_format(from,name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ if (my_delete_with_symlink(from, MYF(MY_WME | sync_dir)))
+ DBUG_RETURN(my_errno);
+ fn_format(from,name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+#ifdef USE_RAID
+ if (raid_type)
+ DBUG_RETURN(my_raid_delete(from, raid_chunks, MYF(MY_WME | sync_dir)) ?
+ my_errno : 0);
+#endif
+ DBUG_RETURN(my_delete_with_symlink(from, MYF(MY_WME | sync_dir)) ?
+ my_errno : 0);
+}
diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c
new file mode 100644
index 00000000000..c09ebc0a230
--- /dev/null
+++ b/storage/maria/ma_dynrec.c
@@ -0,0 +1,2043 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Functions to handle space-packed-records and blobs
+
+ A row may be stored in one or more linked blocks.
+ The block size is between MARIA_MIN_BLOCK_LENGTH and MARIA_MAX_BLOCK_LENGTH.
+ Each block is aligned on MARIA_DYN_ALIGN_SIZE.
+ The reson for the max block size is to not have too many different types
+ of blocks. For the differnet block types, look at _ma_get_block_info()
+*/
+
+#include "maria_def.h"
+
+static my_bool write_dynamic_record(MARIA_HA *info,const uchar *record,
+ ulong reclength);
+static int _ma_find_writepos(MARIA_HA *info,ulong reclength,my_off_t *filepos,
+ ulong *length);
+static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
+ uchar *record, ulong reclength);
+static my_bool delete_dynamic_record(MARIA_HA *info,MARIA_RECORD_POS filepos,
+ uint second_read);
+static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
+ uint length);
+
+#ifdef THREAD
+/* Play it safe; We have a small stack when using threads */
+#undef my_alloca
+#undef my_afree
+#define my_alloca(A) my_malloc((A),MYF(0))
+#define my_afree(A) my_free((A),MYF(0))
+#endif
+
+ /* Interface function from MARIA_HA */
+
+#ifdef HAVE_MMAP
+
+/*
+ Create mmaped area for MARIA handler
+
+ SYNOPSIS
+ _ma_dynmap_file()
+ info MARIA handler
+
+ RETURN
+ 0 ok
+ 1 error.
+*/
+
+my_bool _ma_dynmap_file(MARIA_HA *info, my_off_t size)
+{
+ DBUG_ENTER("_ma_dynmap_file");
+ if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
+ {
+ DBUG_PRINT("warning", ("File is too large for mmap"));
+ DBUG_RETURN(1);
+ }
+ /*
+ Ingo wonders if it is good to use MAP_NORESERVE. From the Linux man page:
+ MAP_NORESERVE
+ Do not reserve swap space for this mapping. When swap space is
+ reserved, one has the guarantee that it is possible to modify the
+ mapping. When swap space is not reserved one might get SIGSEGV
+ upon a write if no physical memory is available.
+ */
+ info->s->file_map= (uchar*)
+ my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN),
+ info->s->mode==O_RDONLY ? PROT_READ :
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_NORESERVE,
+ info->dfile.file, 0L);
+ if (info->s->file_map == (uchar*) MAP_FAILED)
+ {
+ info->s->file_map= NULL;
+ DBUG_RETURN(1);
+ }
+#if defined(HAVE_MADVISE)
+ madvise((char*) info->s->file_map, size, MADV_RANDOM);
+#endif
+ info->s->mmaped_length= size;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Resize mmaped area for MARIA handler
+
+ SYNOPSIS
+ _ma_remap_file()
+ info MARIA handler
+
+ RETURN
+*/
+
+void _ma_remap_file(MARIA_HA *info, my_off_t size)
+{
+ if (info->s->file_map)
+ {
+ VOID(my_munmap((char*) info->s->file_map,
+ (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN));
+ _ma_dynmap_file(info, size);
+ }
+}
+#endif
+
+
+/*
+ Read bytes from MySAM handler, using mmap or pread
+
+ SYNOPSIS
+ _ma_mmap_pread()
+ info MARIA handler
+ Buffer Input buffer
+ Count Count of bytes for read
+ offset Start position
+ MyFlags
+
+ RETURN
+ 0 ok
+*/
+
+size_t _ma_mmap_pread(MARIA_HA *info, uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags)
+{
+ DBUG_PRINT("info", ("maria_read with mmap %d\n", info->dfile.file));
+ if (info->s->lock_key_trees)
+ rw_rdlock(&info->s->mmap_lock);
+
+ /*
+ The following test may fail in the following cases:
+ - We failed to remap a memory area (fragmented memory?)
+ - This thread has done some writes, but not yet extended the
+ memory mapped area.
+ */
+
+ if (info->s->mmaped_length >= offset + Count)
+ {
+ memcpy(Buffer, info->s->file_map + offset, Count);
+ if (info->s->lock_key_trees)
+ rw_unlock(&info->s->mmap_lock);
+ return 0;
+ }
+ else
+ {
+ if (info->s->lock_key_trees)
+ rw_unlock(&info->s->mmap_lock);
+ return my_pread(info->dfile.file, Buffer, Count, offset, MyFlags);
+ }
+}
+
+
+ /* wrapper for my_pread in case if mmap isn't used */
+
+size_t _ma_nommap_pread(MARIA_HA *info, uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags)
+{
+ return my_pread(info->dfile.file, Buffer, Count, offset, MyFlags);
+}
+
+
+/*
+ Write bytes to MySAM handler, using mmap or pwrite
+
+ SYNOPSIS
+ _ma_mmap_pwrite()
+ info MARIA handler
+ Buffer Output buffer
+ Count Count of bytes for write
+ offset Start position
+ MyFlags
+
+ RETURN
+ 0 ok
+ !=0 error. In this case return error from pwrite
+*/
+
+size_t _ma_mmap_pwrite(MARIA_HA *info, const uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags)
+{
+ DBUG_PRINT("info", ("maria_write with mmap %d\n", info->dfile.file));
+ if (info->s->lock_key_trees)
+ rw_rdlock(&info->s->mmap_lock);
+
+ /*
+ The following test may fail in the following cases:
+ - We failed to remap a memory area (fragmented memory?)
+ - This thread has done some writes, but not yet extended the
+ memory mapped area.
+ */
+
+ if (info->s->mmaped_length >= offset + Count)
+ {
+ memcpy(info->s->file_map + offset, Buffer, Count);
+ if (info->s->lock_key_trees)
+ rw_unlock(&info->s->mmap_lock);
+ return 0;
+ }
+ else
+ {
+ info->s->nonmmaped_inserts++;
+ if (info->s->lock_key_trees)
+ rw_unlock(&info->s->mmap_lock);
+ return my_pwrite(info->dfile.file, Buffer, Count, offset, MyFlags);
+ }
+
+}
+
+
+ /* wrapper for my_pwrite in case if mmap isn't used */
+
+size_t _ma_nommap_pwrite(MARIA_HA *info, const uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags)
+{
+ return my_pwrite(info->dfile.file, Buffer, Count, offset, MyFlags);
+}
+
+
+my_bool _ma_write_dynamic_record(MARIA_HA *info, const uchar *record)
+{
+ ulong reclength= _ma_rec_pack(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
+ record);
+ return (write_dynamic_record(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
+ reclength));
+}
+
+my_bool _ma_update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS pos,
+ const uchar *oldrec __attribute__ ((unused)),
+ const uchar *record)
+{
+ uint length= _ma_rec_pack(info, info->rec_buff + MARIA_REC_BUFF_OFFSET,
+ record);
+ return (update_dynamic_record(info, pos,
+ info->rec_buff + MARIA_REC_BUFF_OFFSET,
+ length));
+}
+
+
+my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
+{
+ uchar *rec_buff;
+ int error;
+ ulong reclength,reclength2,extra;
+
+ extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
+ MARIA_DYN_DELETE_BLOCK_HEADER+1);
+ reclength= (info->s->base.pack_reclength +
+ _ma_calc_total_blob_length(info,record)+ extra);
+ if (!(rec_buff=(uchar*) my_alloca(reclength)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
+ return(1);
+ }
+ reclength2= _ma_rec_pack(info,
+ rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
+ record);
+ DBUG_PRINT("info",("reclength: %lu reclength2: %lu",
+ reclength, reclength2));
+ DBUG_ASSERT(reclength2 <= reclength);
+ error= write_dynamic_record(info,
+ rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
+ reclength2);
+ my_afree(rec_buff);
+ return(error != 0);
+}
+
+
+my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
+ const uchar *oldrec __attribute__ ((unused)),
+ const uchar *record)
+{
+ uchar *rec_buff;
+ int error;
+ ulong reclength,extra;
+
+ extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
+ MARIA_DYN_DELETE_BLOCK_HEADER);
+ reclength= (info->s->base.pack_reclength+
+ _ma_calc_total_blob_length(info,record)+ extra);
+#ifdef NOT_USED /* We now support big rows */
+ if (reclength > MARIA_DYN_MAX_ROW_LENGTH)
+ {
+ my_errno=HA_ERR_TO_BIG_ROW;
+ return 1;
+ }
+#endif
+ if (!(rec_buff=(uchar*) my_alloca(reclength)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
+ return(1);
+ }
+ reclength= _ma_rec_pack(info,rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
+ record);
+ error=update_dynamic_record(info,pos,
+ rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
+ reclength);
+ my_afree(rec_buff);
+ return(error != 0);
+}
+
+
+my_bool _ma_delete_dynamic_record(MARIA_HA *info,
+ const uchar *record __attribute__ ((unused)))
+{
+ return delete_dynamic_record(info, info->cur_row.lastpos, 0);
+}
+
+
+/**
+ Write record to data-file.
+
+ @todo it's cheating: it casts "const uchar*" to uchar*.
+*/
+
+static my_bool write_dynamic_record(MARIA_HA *info, const uchar *record,
+ ulong reclength)
+{
+ int flag;
+ ulong length;
+ my_off_t filepos;
+ DBUG_ENTER("write_dynamic_record");
+
+ flag=0;
+
+ /*
+ Check if we have enough room for the new record.
+ First we do simplified check to make usual case faster.
+ Then we do more precise check for the space left.
+ Though it still is not absolutely precise, as
+ we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
+ less in the most of the cases.
+ */
+
+ if (unlikely(info->s->base.max_data_file_length -
+ info->state->data_file_length <
+ reclength + MARIA_MAX_DYN_BLOCK_HEADER))
+ {
+ if (info->s->base.max_data_file_length - info->state->data_file_length +
+ info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
+ reclength + MARIA_MAX_DYN_BLOCK_HEADER)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ DBUG_RETURN(1);
+ }
+ }
+
+ do
+ {
+ if (_ma_find_writepos(info,reclength,&filepos,&length))
+ goto err;
+ if (_ma_write_part_record(info,filepos,length,
+ (info->append_insert_at_end ?
+ HA_OFFSET_ERROR : info->s->state.dellink),
+ (uchar**) &record,&reclength,&flag))
+ goto err;
+ } while (reclength);
+
+ DBUG_RETURN(0);
+err:
+ DBUG_RETURN(1);
+}
+
+
+ /* Get a block for data ; The given data-area must be used !! */
+
+static int _ma_find_writepos(MARIA_HA *info,
+ ulong reclength, /* record length */
+ my_off_t *filepos, /* Return file pos */
+ ulong *length) /* length of block at filepos */
+{
+ MARIA_BLOCK_INFO block_info;
+ ulong tmp;
+ DBUG_ENTER("_ma_find_writepos");
+
+ if (info->s->state.dellink != HA_OFFSET_ERROR &&
+ !info->append_insert_at_end)
+ {
+ /* Deleted blocks exists; Get last used block */
+ *filepos=info->s->state.dellink;
+ block_info.second_read=0;
+ info->rec_cache.seek_not_done=1;
+ if (!(_ma_get_block_info(&block_info, info->dfile.file,
+ info->s->state.dellink) &
+ BLOCK_DELETED))
+ {
+ DBUG_PRINT("error",("Delete link crashed"));
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(-1);
+ }
+ info->s->state.dellink=block_info.next_filepos;
+ info->state->del--;
+ info->state->empty-= block_info.block_len;
+ *length= block_info.block_len;
+ }
+ else
+ {
+ /* No deleted blocks; Allocate a new block */
+ *filepos=info->state->data_file_length;
+ if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
+ info->s->base.min_block_length)
+ tmp= info->s->base.min_block_length;
+ else
+ tmp= ((tmp+MARIA_DYN_ALIGN_SIZE-1) &
+ (~ (ulong) (MARIA_DYN_ALIGN_SIZE-1)));
+ if (info->state->data_file_length >
+ (info->s->base.max_data_file_length - tmp))
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ DBUG_RETURN(-1);
+ }
+ if (tmp > MARIA_MAX_BLOCK_LENGTH)
+ tmp=MARIA_MAX_BLOCK_LENGTH;
+ *length= tmp;
+ info->state->data_file_length+= tmp;
+ info->s->state.split++;
+ info->update|=HA_STATE_WRITE_AT_END;
+ }
+ DBUG_RETURN(0);
+} /* _ma_find_writepos */
+
+
+
+/*
+ Unlink a deleted block from the deleted list.
+ This block will be combined with the preceding or next block to form
+ a big block.
+*/
+
+static my_bool unlink_deleted_block(MARIA_HA *info,
+ MARIA_BLOCK_INFO *block_info)
+{
+ DBUG_ENTER("unlink_deleted_block");
+ if (block_info->filepos == info->s->state.dellink)
+ {
+ /* First deleted block; We can just use this ! */
+ info->s->state.dellink=block_info->next_filepos;
+ }
+ else
+ {
+ MARIA_BLOCK_INFO tmp;
+ tmp.second_read=0;
+ /* Unlink block from the previous block */
+ if (!(_ma_get_block_info(&tmp, info->dfile.file, block_info->prev_filepos)
+ & BLOCK_DELETED))
+ DBUG_RETURN(1); /* Something is wrong */
+ mi_sizestore(tmp.header+4,block_info->next_filepos);
+ if (info->s->file_write(info, tmp.header+4,8,
+ block_info->prev_filepos+4, MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ /* Unlink block from next block */
+ if (block_info->next_filepos != HA_OFFSET_ERROR)
+ {
+ if (!(_ma_get_block_info(&tmp, info->dfile.file,
+ block_info->next_filepos)
+ & BLOCK_DELETED))
+ DBUG_RETURN(1); /* Something is wrong */
+ mi_sizestore(tmp.header+12,block_info->prev_filepos);
+ if (info->s->file_write(info, tmp.header+12,8,
+ block_info->next_filepos+12,
+ MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ }
+ }
+ /* We now have one less deleted block */
+ info->state->del--;
+ info->state->empty-= block_info->block_len;
+ info->s->state.split--;
+
+ /*
+ If this was a block that we where accessing through table scan
+ (maria_rrnd() or maria_scan(), then ensure that we skip over this block
+ when doing next maria_rrnd() or maria_scan().
+ */
+ if (info->cur_row.nextpos == block_info->filepos)
+ info->cur_row.nextpos+= block_info->block_len;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Add a backward link to delete block
+
+ SYNOPSIS
+ update_backward_delete_link()
+ info MARIA handler
+ delete_block Position to delete block to update.
+ If this is 'HA_OFFSET_ERROR', nothing will be done
+ filepos Position to block that 'delete_block' should point to
+
+ RETURN
+ 0 ok
+ 1 error. In this case my_error is set.
+*/
+
+static my_bool update_backward_delete_link(MARIA_HA *info,
+ my_off_t delete_block,
+ MARIA_RECORD_POS filepos)
+{
+ MARIA_BLOCK_INFO block_info;
+ DBUG_ENTER("update_backward_delete_link");
+
+ if (delete_block != HA_OFFSET_ERROR)
+ {
+ block_info.second_read=0;
+ if (_ma_get_block_info(&block_info, info->dfile.file, delete_block)
+ & BLOCK_DELETED)
+ {
+ uchar buff[8];
+ mi_sizestore(buff,filepos);
+ if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
+ DBUG_RETURN(1); /* Error on write */
+ }
+ else
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1); /* Wrong delete link */
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+/* Delete datarecord from database */
+/* info->rec_cache.seek_not_done is updated in cmp_record */
+
+static my_bool delete_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
+ uint second_read)
+{
+ uint length,b_type;
+ MARIA_BLOCK_INFO block_info,del_block;
+ int error;
+ my_bool remove_next_block;
+ DBUG_ENTER("delete_dynamic_record");
+
+ /* First add a link from the last block to the new one */
+ error= update_backward_delete_link(info, info->s->state.dellink, filepos);
+
+ block_info.second_read=second_read;
+ do
+ {
+ /* Remove block at 'filepos' */
+ if ((b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR) ||
+ (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
+ MARIA_MIN_BLOCK_LENGTH)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(1);
+ }
+ /* Check if next block is a delete block */
+ del_block.second_read=0;
+ remove_next_block=0;
+ if (_ma_get_block_info(&del_block, info->dfile.file, filepos + length) &
+ BLOCK_DELETED && del_block.block_len+length <
+ MARIA_DYN_MAX_BLOCK_LENGTH)
+ {
+ /* We can't remove this yet as this block may be the head block */
+ remove_next_block=1;
+ length+=del_block.block_len;
+ }
+
+ block_info.header[0]=0;
+ mi_int3store(block_info.header+1,length);
+ mi_sizestore(block_info.header+4,info->s->state.dellink);
+ if (b_type & BLOCK_LAST)
+ bfill(block_info.header+12,8,255);
+ else
+ mi_sizestore(block_info.header+12,block_info.next_filepos);
+ if (info->s->file_write(info,(uchar*) block_info.header,20,filepos,
+ MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ info->s->state.dellink = filepos;
+ info->state->del++;
+ info->state->empty+=length;
+ filepos=block_info.next_filepos;
+
+ /* Now it's safe to unlink the deleted block directly after this one */
+ if (remove_next_block && unlink_deleted_block(info,&del_block))
+ error=1;
+ } while (!(b_type & BLOCK_LAST));
+
+ DBUG_RETURN(error);
+}
+
+
+ /* Write a block to datafile */
+
+int _ma_write_part_record(MARIA_HA *info,
+ my_off_t filepos, /* points at empty block */
+ ulong length, /* length of block */
+ my_off_t next_filepos,/* Next empty block */
+ uchar **record, /* pointer to record ptr */
+ ulong *reclength, /* length of *record */
+ int *flag) /* *flag == 0 if header */
+{
+ ulong head_length,res_length,extra_length,long_block,del_length;
+ uchar *pos,*record_end;
+ my_off_t next_delete_block;
+ uchar temp[MARIA_SPLIT_LENGTH+MARIA_DYN_DELETE_BLOCK_HEADER];
+ DBUG_ENTER("_ma_write_part_record");
+
+ next_delete_block=HA_OFFSET_ERROR;
+
+ res_length=extra_length=0;
+ if (length > *reclength + MARIA_SPLIT_LENGTH)
+ { /* Splitt big block */
+ res_length=MY_ALIGN(length- *reclength - MARIA_EXTEND_BLOCK_LENGTH,
+ MARIA_DYN_ALIGN_SIZE);
+ length-= res_length; /* Use this for first part */
+ }
+ long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
+ if (length == *reclength+ 3 + long_block)
+ {
+ /* Block is exactly of the right length */
+ temp[0]=(uchar) (1+ *flag)+(uchar) long_block; /* Flag is 0 or 6 */
+ if (long_block)
+ {
+ mi_int3store(temp+1,*reclength);
+ head_length=4;
+ }
+ else
+ {
+ mi_int2store(temp+1,*reclength);
+ head_length=3;
+ }
+ }
+ else if (length-long_block < *reclength+4)
+ { /* To short block */
+ if (next_filepos == HA_OFFSET_ERROR)
+ next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
+ !info->append_insert_at_end ?
+ info->s->state.dellink : info->state->data_file_length);
+ if (*flag == 0) /* First block */
+ {
+ if (*reclength > MARIA_MAX_BLOCK_LENGTH)
+ {
+ head_length= 16;
+ temp[0]=13;
+ mi_int4store(temp+1,*reclength);
+ mi_int3store(temp+5,length-head_length);
+ mi_sizestore((uchar*) temp+8,next_filepos);
+ }
+ else
+ {
+ head_length=5+8+long_block*2;
+ temp[0]=5+(uchar) long_block;
+ if (long_block)
+ {
+ mi_int3store(temp+1,*reclength);
+ mi_int3store(temp+4,length-head_length);
+ mi_sizestore((uchar*) temp+7,next_filepos);
+ }
+ else
+ {
+ mi_int2store(temp+1,*reclength);
+ mi_int2store(temp+3,length-head_length);
+ mi_sizestore((uchar*) temp+5,next_filepos);
+ }
+ }
+ }
+ else
+ {
+ head_length=3+8+long_block;
+ temp[0]=11+(uchar) long_block;
+ if (long_block)
+ {
+ mi_int3store(temp+1,length-head_length);
+ mi_sizestore((uchar*) temp+4,next_filepos);
+ }
+ else
+ {
+ mi_int2store(temp+1,length-head_length);
+ mi_sizestore((uchar*) temp+3,next_filepos);
+ }
+ }
+ }
+ else
+ { /* Block with empty info last */
+ head_length=4+long_block;
+ extra_length= length- *reclength-head_length;
+ temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */
+ if (long_block)
+ {
+ mi_int3store(temp+1,*reclength);
+ temp[4]= (uchar) (extra_length);
+ }
+ else
+ {
+ mi_int2store(temp+1,*reclength);
+ temp[3]= (uchar) (extra_length);
+ }
+ length= *reclength+head_length; /* Write only what is needed */
+ }
+ DBUG_DUMP("header",(uchar*) temp,head_length);
+
+ /* Make a long block for one write */
+ record_end= *record+length-head_length;
+ del_length=(res_length ? MARIA_DYN_DELETE_BLOCK_HEADER : 0);
+ bmove((uchar*) (*record-head_length),(uchar*) temp,head_length);
+ memcpy(temp,record_end,(size_t) (extra_length+del_length));
+ bzero((uchar*) record_end,extra_length);
+
+ if (res_length)
+ {
+ /* Check first if we can join this block with the next one */
+ MARIA_BLOCK_INFO del_block;
+ my_off_t next_block=filepos+length+extra_length+res_length;
+
+ del_block.second_read=0;
+ if (next_block < info->state->data_file_length &&
+ info->s->state.dellink != HA_OFFSET_ERROR)
+ {
+ if ((_ma_get_block_info(&del_block, info->dfile.file, next_block)
+ & BLOCK_DELETED) &&
+ res_length + del_block.block_len < MARIA_DYN_MAX_BLOCK_LENGTH)
+ {
+ if (unlink_deleted_block(info,&del_block))
+ goto err;
+ res_length+=del_block.block_len;
+ }
+ }
+
+ /* Create a delete link of the last part of the block */
+ pos=record_end+extra_length;
+ pos[0]= '\0';
+ mi_int3store(pos+1,res_length);
+ mi_sizestore(pos+4,info->s->state.dellink);
+ bfill(pos+12,8,255); /* End link */
+ next_delete_block=info->s->state.dellink;
+ info->s->state.dellink= filepos+length+extra_length;
+ info->state->del++;
+ info->state->empty+=res_length;
+ info->s->state.split++;
+ }
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->update & HA_STATE_WRITE_AT_END)
+ {
+ if (info->update & HA_STATE_EXTEND_BLOCK)
+ {
+ info->update&= ~HA_STATE_EXTEND_BLOCK;
+ if (my_block_write(&info->rec_cache,(uchar*) *record-head_length,
+ length+extra_length+del_length,filepos))
+ goto err;
+ }
+ else if (my_b_write(&info->rec_cache,(uchar*) *record-head_length,
+ length+extra_length+del_length))
+ goto err;
+ }
+ else
+ {
+ info->rec_cache.seek_not_done=1;
+ if (info->s->file_write(info,(uchar*) *record-head_length,
+ length+extra_length+
+ del_length,filepos,info->s->write_flag))
+ goto err;
+ }
+ memcpy(record_end,temp,(size_t) (extra_length+del_length));
+ *record=record_end;
+ *reclength-=(length-head_length);
+ *flag=6;
+
+ if (del_length)
+ {
+ /* link the next delete block to this */
+ if (update_backward_delete_link(info, next_delete_block,
+ info->s->state.dellink))
+ goto err;
+ }
+
+ DBUG_RETURN(0);
+err:
+ DBUG_PRINT("exit",("errno: %d",my_errno));
+ DBUG_RETURN(1);
+} /* _ma_write_part_record */
+
+
+ /* update record from datafile */
+
+static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
+ uchar *record, ulong reclength)
+{
+ int flag;
+ uint error;
+ ulong length;
+ MARIA_BLOCK_INFO block_info;
+ DBUG_ENTER("update_dynamic_record");
+
+ flag=block_info.second_read=0;
+ /*
+ Check if we have enough room for the record.
+ First we do simplified check to make usual case faster.
+ Then we do more precise check for the space left.
+ Though it still is not absolutely precise, as
+ we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
+ less in the most of the cases.
+ */
+
+ /*
+ compare with just the reclength as we're going
+ to get some space from the old replaced record
+ */
+ if (unlikely(info->s->base.max_data_file_length -
+ info->state->data_file_length < reclength))
+ {
+ /* If new record isn't longer, we can go on safely */
+ if (info->cur_row.total_length < reclength)
+ {
+ if (info->s->base.max_data_file_length - info->state->data_file_length +
+ info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
+ reclength - info->cur_row.total_length + MARIA_MAX_DYN_BLOCK_HEADER)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ goto err;
+ }
+ }
+ }
+ /* Remember length for updated row if it's updated again */
+ info->cur_row.total_length= reclength;
+
+ while (reclength > 0)
+ {
+ if (filepos != info->s->state.dellink)
+ {
+ block_info.next_filepos= HA_OFFSET_ERROR;
+ if ((error= _ma_get_block_info(&block_info, info->dfile.file, filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ DBUG_PRINT("error",("Got wrong block info"));
+ if (!(error & BLOCK_FATAL_ERROR))
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
+ if (length < reclength)
+ {
+ uint tmp=MY_ALIGN(reclength - length + 3 +
+ test(reclength >= 65520L),MARIA_DYN_ALIGN_SIZE);
+ /* Don't create a block bigger than MARIA_MAX_BLOCK_LENGTH */
+ tmp= min(length+tmp, MARIA_MAX_BLOCK_LENGTH)-length;
+ /* Check if we can extend this block */
+ if (block_info.filepos + block_info.block_len ==
+ info->state->data_file_length &&
+ info->state->data_file_length <
+ info->s->base.max_data_file_length-tmp)
+ {
+ /* extend file */
+ DBUG_PRINT("info",("Extending file with %d bytes",tmp));
+ if (info->cur_row.nextpos == info->state->data_file_length)
+ info->cur_row.nextpos+= tmp;
+ info->state->data_file_length+= tmp;
+ info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
+ length+=tmp;
+ }
+ else if (length < MARIA_MAX_BLOCK_LENGTH - MARIA_MIN_BLOCK_LENGTH)
+ {
+ /*
+ Check if next block is a deleted block
+ Above we have MARIA_MIN_BLOCK_LENGTH to avoid the problem where
+ the next block is so small it can't be splited which could
+ casue problems
+ */
+
+ MARIA_BLOCK_INFO del_block;
+ del_block.second_read=0;
+ if (_ma_get_block_info(&del_block, info->dfile.file,
+ block_info.filepos + block_info.block_len) &
+ BLOCK_DELETED)
+ {
+ /* Use; Unlink it and extend the current block */
+ DBUG_PRINT("info",("Extending current block"));
+ if (unlink_deleted_block(info,&del_block))
+ goto err;
+ if ((length+=del_block.block_len) > MARIA_MAX_BLOCK_LENGTH)
+ {
+ /*
+ New block was too big, link overflow part back to
+ delete list
+ */
+ my_off_t next_pos;
+ ulong rest_length= length-MARIA_MAX_BLOCK_LENGTH;
+ set_if_bigger(rest_length, MARIA_MIN_BLOCK_LENGTH);
+ next_pos= del_block.filepos+ del_block.block_len - rest_length;
+
+ if (update_backward_delete_link(info, info->s->state.dellink,
+ next_pos))
+ DBUG_RETURN(1);
+
+ /* create delete link for data that didn't fit into the page */
+ del_block.header[0]=0;
+ mi_int3store(del_block.header+1, rest_length);
+ mi_sizestore(del_block.header+4,info->s->state.dellink);
+ bfill(del_block.header+12,8,255);
+ if (info->s->file_write(info,(uchar*) del_block.header, 20,
+ next_pos, MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ info->s->state.dellink= next_pos;
+ info->s->state.split++;
+ info->state->del++;
+ info->state->empty+= rest_length;
+ length-= rest_length;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (_ma_find_writepos(info,reclength,&filepos,&length))
+ goto err;
+ }
+ if (_ma_write_part_record(info,filepos,length,block_info.next_filepos,
+ &record,&reclength,&flag))
+ goto err;
+ if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
+ {
+ /* Start writing data on deleted blocks */
+ filepos=info->s->state.dellink;
+ }
+ }
+
+ if (block_info.next_filepos != HA_OFFSET_ERROR)
+ if (delete_dynamic_record(info,block_info.next_filepos,1))
+ goto err;
+
+ DBUG_RETURN(0);
+err:
+ DBUG_RETURN(1);
+}
+
+
+ /* Pack a record. Return new reclength */
+
+uint _ma_rec_pack(MARIA_HA *info, register uchar *to,
+ register const uchar *from)
+{
+ uint length,new_length,flag,bit,i;
+ const uchar *pos,*end;
+ uchar *startpos,*packpos;
+ enum en_fieldtype type;
+ reg3 MARIA_COLUMNDEF *column;
+ MARIA_BLOB *blob;
+ DBUG_ENTER("_ma_rec_pack");
+
+ flag= 0;
+ bit= 1;
+ startpos= packpos=to;
+ to+= info->s->base.pack_bytes;
+ blob= info->blobs;
+ column= info->s->columndef;
+ if (info->s->base.null_bytes)
+ {
+ memcpy(to, from, info->s->base.null_bytes);
+ from+= info->s->base.null_bytes;
+ to+= info->s->base.null_bytes;
+ }
+
+ for (i=info->s->base.fields ; i-- > 0; from+= length, column++)
+ {
+ length=(uint) column->length;
+ if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
+ {
+ if (type == FIELD_BLOB)
+ {
+ if (!blob->length)
+ flag|=bit;
+ else
+ {
+ char *temp_pos;
+ size_t tmp_length=length-portable_sizeof_char_ptr;
+ memcpy((uchar*) to,from,tmp_length);
+ memcpy_fixed(&temp_pos,from+tmp_length,sizeof(char*));
+ memcpy(to+tmp_length,temp_pos,(size_t) blob->length);
+ to+=tmp_length+blob->length;
+ }
+ blob++;
+ }
+ else if (type == FIELD_SKIP_ZERO)
+ {
+ if (memcmp(from, maria_zero_string, length) == 0)
+ flag|=bit;
+ else
+ {
+ memcpy((uchar*) to,from,(size_t) length);
+ to+=length;
+ }
+ }
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
+ {
+ pos= from; end= from + length;
+ if (type == FIELD_SKIP_ENDSPACE)
+ { /* Pack trailing spaces */
+ while (end > from && *(end-1) == ' ')
+ end--;
+ }
+ else
+ { /* Pack pref-spaces */
+ while (pos < end && *pos == ' ')
+ pos++;
+ }
+ new_length=(uint) (end-pos);
+ if (new_length +1 + test(column->length > 255 && new_length > 127)
+ < length)
+ {
+ if (column->length > 255 && new_length > 127)
+ {
+ to[0]= (uchar) ((new_length & 127) + 128);
+ to[1]= (uchar) (new_length >> 7);
+ to+=2;
+ }
+ else
+ *to++= (uchar) new_length;
+ memcpy((uchar*) to,pos,(size_t) new_length); to+=new_length;
+ flag|=bit;
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ }
+ }
+ else if (type == FIELD_VARCHAR)
+ {
+ uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
+ uint tmp_length;
+ if (pack_length == 1)
+ {
+ tmp_length= (uint) *from;
+ *to++= *from;
+ }
+ else
+ {
+ tmp_length= uint2korr(from);
+ store_key_length_inc(to,tmp_length);
+ }
+ memcpy(to, from+pack_length,tmp_length);
+ to+= tmp_length;
+ continue;
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ continue; /* Normal field */
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ *packpos++ = (uchar) flag;
+ bit=1; flag=0;
+ }
+ }
+ else
+ {
+ memcpy(to,from,(size_t) length); to+=length;
+ }
+ }
+ if (bit != 1)
+ *packpos= (uchar) flag;
+ if (info->s->calc_checksum)
+ *to++= (uchar) info->cur_row.checksum;
+ DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
+ DBUG_RETURN((uint) (to-startpos));
+} /* _ma_rec_pack */
+
+
+
+/*
+ Check if a record was correctly packed. Used only by maria_chk
+ Returns 0 if record is ok.
+*/
+
+my_bool _ma_rec_check(MARIA_HA *info,const uchar *record, uchar *rec_buff,
+ ulong packed_length, my_bool with_checksum,
+ ha_checksum checksum)
+{
+ uint length,new_length,flag,bit,i;
+ const uchar *pos,*end;
+ uchar *packpos,*to;
+ enum en_fieldtype type;
+ reg3 MARIA_COLUMNDEF *column;
+ DBUG_ENTER("_ma_rec_check");
+
+ packpos=rec_buff; to= rec_buff+info->s->base.pack_bytes;
+ column= info->s->columndef;
+ flag= *packpos; bit=1;
+ record+= info->s->base.null_bytes;
+ to+= info->s->base.null_bytes;
+
+ for (i=info->s->base.fields ; i-- > 0; record+= length, column++)
+ {
+ length=(uint) column->length;
+ if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
+ {
+ if (type == FIELD_BLOB)
+ {
+ uint blob_length=
+ _ma_calc_blob_length(length-portable_sizeof_char_ptr,record);
+ if (!blob_length && !(flag & bit))
+ goto err;
+ if (blob_length)
+ to+=length - portable_sizeof_char_ptr+ blob_length;
+ }
+ else if (type == FIELD_SKIP_ZERO)
+ {
+ if (memcmp(record, maria_zero_string, length) == 0)
+ {
+ if (!(flag & bit))
+ goto err;
+ }
+ else
+ to+=length;
+ }
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
+ {
+ pos= record; end= record + length;
+ if (type == FIELD_SKIP_ENDSPACE)
+ { /* Pack trailing spaces */
+ while (end > record && *(end-1) == ' ')
+ end--;
+ }
+ else
+ { /* Pack pre-spaces */
+ while (pos < end && *pos == ' ')
+ pos++;
+ }
+ new_length=(uint) (end-pos);
+ if (new_length +1 + test(column->length > 255 && new_length > 127)
+ < length)
+ {
+ if (!(flag & bit))
+ goto err;
+ if (column->length > 255 && new_length > 127)
+ {
+ /* purecov: begin inspected */
+ if (to[0] != (uchar) ((new_length & 127) + 128) ||
+ to[1] != (uchar) (new_length >> 7))
+ goto err;
+ to+=2;
+ /* purecov: end */
+ }
+ else if (*to++ != (uchar) new_length)
+ goto err;
+ to+=new_length;
+ }
+ else
+ to+=length;
+ }
+ else if (type == FIELD_VARCHAR)
+ {
+ uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
+ uint tmp_length;
+ if (pack_length == 1)
+ {
+ tmp_length= (uint) *record;
+ to+= 1+ tmp_length;
+ continue;
+ }
+ else
+ {
+ tmp_length= uint2korr(record);
+ to+= get_pack_length(tmp_length)+tmp_length;
+ }
+ continue;
+ }
+ else
+ {
+ to+=length;
+ continue; /* Normal field */
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ flag= *++packpos;
+ bit=1;
+ }
+ }
+ else
+ to+= length;
+ }
+ if (packed_length != (uint) (to - rec_buff) +
+ test(info->s->calc_checksum) || (bit != 1 && (flag & ~(bit - 1))))
+ goto err;
+ if (with_checksum && ((uchar) checksum != (uchar) *to))
+ {
+ DBUG_PRINT("error",("wrong checksum for row"));
+ goto err;
+ }
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1);
+}
+
+
+/*
+ @brief Unpacks a record
+
+ @return Recordlength
+ @retval >0 ok
+ @retval MY_FILE_ERROR (== -1) Error.
+ my_errno is set to HA_ERR_WRONG_IN_RECORD
+*/
+
+ulong _ma_rec_unpack(register MARIA_HA *info, register uchar *to, uchar *from,
+ ulong found_length)
+{
+ uint flag,bit,length,min_pack_length, column_length;
+ enum en_fieldtype type;
+ uchar *from_end,*to_end,*packpos;
+ reg3 MARIA_COLUMNDEF *column, *end_column;
+ DBUG_ENTER("_ma_rec_unpack");
+
+ to_end=to + info->s->base.reclength;
+ from_end=from+found_length;
+ flag= (uchar) *from; bit=1; packpos=from;
+ if (found_length < info->s->base.min_pack_length)
+ goto err;
+ from+= info->s->base.pack_bytes;
+ min_pack_length= info->s->base.min_pack_length - info->s->base.pack_bytes;
+
+ if ((length= info->s->base.null_bytes))
+ {
+ memcpy(to, from, length);
+ from+= length;
+ to+= length;
+ min_pack_length-= length;
+ }
+
+ for (column= info->s->columndef, end_column= column + info->s->base.fields;
+ column < end_column ; to+= column_length, column++)
+ {
+ column_length= column->length;
+ if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL &&
+ (type != FIELD_CHECK))
+ {
+ if (type == FIELD_VARCHAR)
+ {
+ uint pack_length= HA_VARCHAR_PACKLENGTH(column_length-1);
+ if (pack_length == 1)
+ {
+ length= (uint) *(uchar*) from;
+ if (length > column_length-1)
+ goto err;
+ *to= *from++;
+ }
+ else
+ {
+ get_key_length(length, from);
+ if (length > column_length-2)
+ goto err;
+ int2store(to,length);
+ }
+ if (from+length > from_end)
+ goto err;
+ memcpy(to+pack_length, from, length);
+ from+= length;
+ min_pack_length--;
+ continue;
+ }
+ if (flag & bit)
+ {
+ if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
+ bzero((uchar*) to,column_length);
+ else if (type == FIELD_SKIP_ENDSPACE ||
+ type == FIELD_SKIP_PRESPACE)
+ {
+ if (column->length > 255 && *from & 128)
+ {
+ if (from + 1 >= from_end)
+ goto err;
+ length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
+ }
+ else
+ {
+ if (from == from_end)
+ goto err;
+ length= (uchar) *from++;
+ }
+ min_pack_length--;
+ if (length >= column_length ||
+ min_pack_length + length > (uint) (from_end - from))
+ goto err;
+ if (type == FIELD_SKIP_ENDSPACE)
+ {
+ memcpy(to,(uchar*) from,(size_t) length);
+ bfill((uchar*) to+length,column_length-length,' ');
+ }
+ else
+ {
+ bfill((uchar*) to,column_length-length,' ');
+ memcpy(to+column_length-length,(uchar*) from,(size_t) length);
+ }
+ from+=length;
+ }
+ }
+ else if (type == FIELD_BLOB)
+ {
+ uint size_length=column_length- portable_sizeof_char_ptr;
+ ulong blob_length= _ma_calc_blob_length(size_length,from);
+ ulong from_left= (ulong) (from_end - from);
+ if (from_left < size_length ||
+ from_left - size_length < blob_length ||
+ from_left - size_length - blob_length < min_pack_length)
+ goto err;
+ memcpy((uchar*) to,(uchar*) from,(size_t) size_length);
+ from+=size_length;
+ memcpy_fixed((uchar*) to+size_length,(uchar*) &from,sizeof(char*));
+ from+=blob_length;
+ }
+ else
+ {
+ if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
+ min_pack_length--;
+ if (min_pack_length + column_length > (uint) (from_end - from))
+ goto err;
+ memcpy(to,(uchar*) from,(size_t) column_length); from+=column_length;
+ }
+ if ((bit= bit << 1) >= 256)
+ {
+ flag= (uchar) *++packpos; bit=1;
+ }
+ }
+ else
+ {
+ if (min_pack_length > (uint) (from_end - from))
+ goto err;
+ min_pack_length-=column_length;
+ memcpy(to, (uchar*) from, (size_t) column_length);
+ from+=column_length;
+ }
+ }
+ if (info->s->calc_checksum)
+ info->cur_row.checksum= (uint) (uchar) *from++;
+ if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
+ DBUG_RETURN(found_length);
+
+err:
+ my_errno= HA_ERR_WRONG_IN_RECORD;
+ DBUG_PRINT("error",("to_end: 0x%lx -> 0x%lx from_end: 0x%lx -> 0x%lx",
+ (long) to, (long) to_end, (long) from, (long) from_end));
+ DBUG_DUMP("from",(uchar*) info->rec_buff,info->s->base.min_pack_length);
+ DBUG_RETURN(MY_FILE_ERROR);
+} /* _ma_rec_unpack */
+
+
+ /* Calc length of blob. Update info in blobs->length */
+
+ulong _ma_calc_total_blob_length(MARIA_HA *info, const uchar *record)
+{
+ ulong length;
+ MARIA_BLOB *blob,*end;
+
+ for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
+ blob != end;
+ blob++)
+ {
+ blob->length= _ma_calc_blob_length(blob->pack_length,
+ record + blob->offset);
+ length+=blob->length;
+ }
+ return length;
+}
+
+
+ulong _ma_calc_blob_length(uint length, const uchar *pos)
+{
+ switch (length) {
+ case 1:
+ return (uint) (uchar) *pos;
+ case 2:
+ return (uint) uint2korr(pos);
+ case 3:
+ return uint3korr(pos);
+ case 4:
+ return uint4korr(pos);
+ default:
+ break;
+ }
+ return 0; /* Impossible */
+}
+
+
+void _ma_store_blob_length(uchar *pos,uint pack_length,uint length)
+{
+ switch (pack_length) {
+ case 1:
+ *pos= (uchar) length;
+ break;
+ case 2:
+ int2store(pos,length);
+ break;
+ case 3:
+ int3store(pos,length);
+ break;
+ case 4:
+ int4store(pos,length);
+ default:
+ break;
+ }
+ return;
+}
+
+
+/*
+ Read record from datafile.
+
+ SYNOPSIS
+ _ma_read_dynamic_record()
+ info MARIA_HA pointer to table.
+ filepos From where to read the record.
+ buf Destination for record.
+
+ NOTE
+ If a write buffer is active, it needs to be flushed if its contents
+ intersects with the record to read. We always check if the position
+ of the first uchar of the write buffer is lower than the position
+ past the last uchar to read. In theory this is also true if the write
+ buffer is completely below the read segment. That is, if there is no
+ intersection. But this case is unusual. We flush anyway. Only if the
+ first uchar in the write buffer is above the last uchar to read, we do
+ not flush.
+
+ A dynamic record may need several reads. So this check must be done
+ before every read. Reading a dynamic record starts with reading the
+ block header. If the record does not fit into the free space of the
+ header, the block may be longer than the header. In this case a
+ second read is necessary. These one or two reads repeat for every
+ part of the record.
+
+ RETURN
+ 0 OK
+ # Error number
+*/
+
+int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf,
+ MARIA_RECORD_POS filepos)
+{
+ int block_of_record;
+ uint b_type;
+ MARIA_BLOCK_INFO block_info;
+ File file;
+ uchar *to;
+ uint left_length;
+ DBUG_ENTER("_ma_read_dynamic_record");
+
+ if (filepos == HA_OFFSET_ERROR)
+ goto err;
+
+ LINT_INIT(to);
+ LINT_INIT(left_length);
+ file= info->dfile.file;
+ block_of_record= 0; /* First block of record is numbered as zero. */
+ block_info.second_read= 0;
+ do
+ {
+ /* A corrupted table can have wrong pointers. (Bug# 19835) */
+ if (filepos == HA_OFFSET_ERROR)
+ goto panic;
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ (info->rec_cache.pos_in_file < filepos +
+ MARIA_BLOCK_INFO_HEADER_LENGTH) &&
+ flush_io_cache(&info->rec_cache))
+ goto err;
+ info->rec_cache.seek_not_done=1;
+ if ((b_type= _ma_get_block_info(&block_info, file, filepos)) &
+ (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
+ my_errno=HA_ERR_RECORD_DELETED;
+ goto err;
+ }
+ if (block_of_record++ == 0) /* First block */
+ {
+ info->cur_row.total_length= block_info.rec_len;
+ if (block_info.rec_len > (uint) info->s->base.max_pack_length)
+ goto panic;
+ if (info->s->base.blobs)
+ {
+ if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
+ block_info.rec_len +
+ info->s->base.extra_rec_buff_size))
+ goto err;
+ }
+ to= info->rec_buff;
+ left_length=block_info.rec_len;
+ }
+ if (left_length < block_info.data_len || ! block_info.data_len)
+ goto panic; /* Wrong linked record */
+ /* copy information that is already read */
+ {
+ uint offset= (uint) (block_info.filepos - filepos);
+ uint prefetch_len= (sizeof(block_info.header) - offset);
+ filepos+= sizeof(block_info.header);
+
+ if (prefetch_len > block_info.data_len)
+ prefetch_len= block_info.data_len;
+ if (prefetch_len)
+ {
+ memcpy((uchar*) to, block_info.header + offset, prefetch_len);
+ block_info.data_len-= prefetch_len;
+ left_length-= prefetch_len;
+ to+= prefetch_len;
+ }
+ }
+ /* read rest of record from file */
+ if (block_info.data_len)
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file < filepos + block_info.data_len &&
+ flush_io_cache(&info->rec_cache))
+ goto err;
+ /*
+ What a pity that this method is not called 'file_pread' and that
+ there is no equivalent without seeking. We are at the right
+ position already. :(
+ */
+ if (info->s->file_read(info, (uchar*) to, block_info.data_len,
+ filepos, MYF(MY_NABP)))
+ goto panic;
+ left_length-=block_info.data_len;
+ to+=block_info.data_len;
+ }
+ filepos= block_info.next_filepos;
+ } while (left_length);
+
+ info->update|= HA_STATE_AKTIV; /* We have a aktive record */
+ fast_ma_writeinfo(info);
+ DBUG_RETURN(_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
+ MY_FILE_ERROR ? 0 : my_errno);
+
+err:
+ fast_ma_writeinfo(info);
+ DBUG_RETURN(my_errno);
+
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+}
+
+ /* compare unique constraint between stored rows */
+
+my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
+ const uchar *record, MARIA_RECORD_POS pos)
+{
+ uchar *old_rec_buff,*old_record;
+ size_t old_rec_buff_size;
+ my_bool error;
+ DBUG_ENTER("_ma_cmp_dynamic_unique");
+
+ if (!(old_record=my_alloca(info->s->base.reclength)))
+ DBUG_RETURN(1);
+
+ /* Don't let the compare destroy blobs that may be in use */
+ old_rec_buff= info->rec_buff;
+ old_rec_buff_size= info->rec_buff_size;
+
+ if (info->s->base.blobs)
+ {
+ info->rec_buff= 0;
+ info->rec_buff_size= 0;
+ }
+ error= _ma_read_dynamic_record(info, old_record, pos) != 0;
+ if (!error)
+ error=_ma_unique_comp(def, record, old_record, def->null_are_equal) != 0;
+ if (info->s->base.blobs)
+ {
+ my_free(info->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
+ info->rec_buff= old_rec_buff;
+ info->rec_buff_size= old_rec_buff_size;
+ }
+ my_afree(old_record);
+ DBUG_RETURN(error);
+}
+
+
+ /* Compare of record on disk with packed record in memory */
+
+my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
+ register const uchar *record)
+{
+ uint flag, reclength, b_type,cmp_length;
+ my_off_t filepos;
+ uchar *buffer;
+ MARIA_BLOCK_INFO block_info;
+ my_bool error= 1;
+ DBUG_ENTER("_ma_cmp_dynamic_record");
+
+ /* We are going to do changes; dont let anybody disturb */
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
+ if (flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(1);
+ }
+ info->rec_cache.seek_not_done=1;
+
+ /* If nobody have touched the database we don't have to test rec */
+
+ buffer=info->rec_buff;
+ if ((info->opt_flag & READ_CHECK_USED))
+ { /* If check isn't disabled */
+ if (info->s->base.blobs)
+ {
+ if (!(buffer=(uchar*) my_alloca(info->s->base.pack_reclength+
+ _ma_calc_total_blob_length(info,record))))
+ DBUG_RETURN(1);
+ }
+ reclength= _ma_rec_pack(info,buffer,record);
+ record= buffer;
+
+ filepos= info->cur_row.lastpos;
+ flag=block_info.second_read=0;
+ block_info.next_filepos=filepos;
+ while (reclength > 0)
+ {
+ if ((b_type= _ma_get_block_info(&block_info, info->dfile.file,
+ block_info.next_filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ if (flag == 0) /* First block */
+ {
+ flag=1;
+ if (reclength != block_info.rec_len)
+ {
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ } else if (reclength < block_info.data_len)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+ reclength-= block_info.data_len;
+ cmp_length= block_info.data_len;
+ if (!reclength && info->s->calc_checksum)
+ cmp_length--; /* 'record' may not contain checksum */
+
+ if (_ma_cmp_buffer(info->dfile.file, record, block_info.filepos,
+ cmp_length))
+ {
+ my_errno=HA_ERR_RECORD_CHANGED;
+ goto err;
+ }
+ flag=1;
+ record+=block_info.data_len;
+ }
+ }
+ my_errno=0;
+ error= 0;
+err:
+ if (buffer != info->rec_buff)
+ my_afree((uchar*) buffer);
+ DBUG_PRINT("exit", ("result: %d", error));
+ DBUG_RETURN(error);
+}
+
+
+ /* Compare file to buffert */
+
+static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
+ uint length)
+{
+ uint next_length;
+ uchar temp_buff[IO_SIZE*2];
+ DBUG_ENTER("_ma_cmp_buffer");
+
+ next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
+
+ while (length > IO_SIZE*2)
+ {
+ if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
+ memcmp(buff, temp_buff, next_length))
+ goto err;
+ filepos+=next_length;
+ buff+=next_length;
+ length-= next_length;
+ next_length=IO_SIZE*2;
+ }
+ if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
+ goto err;
+ DBUG_RETURN(memcmp(buff, temp_buff, length) != 0);
+err:
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Read next record from datafile during table scan.
+
+ SYNOPSIS
+ _ma_read_rnd_dynamic_record()
+ info MARIA_HA pointer to table.
+ buf Destination for record.
+ filepos From where to read the record.
+ skip_deleted_blocks If to repeat reading until a non-deleted
+ record is found.
+
+ NOTE
+ This is identical to _ma_read_dynamic_record(), except the following
+ cases:
+
+ - If there is no active row at 'filepos', continue scanning for
+ an active row. (This is becasue the previous
+ _ma_read_rnd_dynamic_record() call stored the next block position
+ in filepos, but this position may not be a start block for a row
+ - We may have READ_CACHING enabled, in which case we use the cache
+ to read rows.
+
+ For other comments, check _ma_read_dynamic_record()
+
+ RETURN
+ 0 OK
+ != 0 Error number
+*/
+
+int _ma_read_rnd_dynamic_record(MARIA_HA *info,
+ uchar *buf,
+ MARIA_RECORD_POS filepos,
+ my_bool skip_deleted_blocks)
+{
+ int block_of_record, info_read;
+ uint left_len,b_type;
+ uchar *to;
+ MARIA_BLOCK_INFO block_info;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_read_rnd_dynamic_record");
+
+ info_read=0;
+ LINT_INIT(to);
+
+ if (info->lock_type == F_UNLCK)
+ {
+#ifndef UNSAFE_LOCKING
+#else
+ info->tmp_lock_type=F_RDLCK;
+#endif
+ }
+ else
+ info_read=1; /* memory-keyinfoblock is ok */
+
+ block_of_record= 0; /* First block of record is numbered as zero. */
+ block_info.second_read= 0;
+ left_len=1;
+ do
+ {
+ if (filepos >= info->state->data_file_length)
+ {
+ if (!info_read)
+ { /* Check if changed */
+ info_read=1;
+ info->rec_cache.seek_not_done=1;
+ if (_ma_state_info_read_dsk(share->kfile.file, &share->state))
+ goto panic;
+ }
+ if (filepos >= info->state->data_file_length)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ goto err;
+ }
+ }
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_ma_read_cache(&info->rec_cache,(uchar*) block_info.header,filepos,
+ sizeof(block_info.header),
+ (!block_of_record && skip_deleted_blocks ?
+ READING_NEXT : 0) | READING_HEADER))
+ goto panic;
+ b_type= _ma_get_block_info(&block_info,-1,filepos);
+ }
+ else
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file < filepos + MARIA_BLOCK_INFO_HEADER_LENGTH &&
+ flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+ info->rec_cache.seek_not_done=1;
+ b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos);
+ }
+
+ if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
+ BLOCK_FATAL_ERROR))
+ {
+ if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ && skip_deleted_blocks)
+ {
+ filepos=block_info.filepos+block_info.block_len;
+ block_info.second_read=0;
+ continue; /* Search after next_record */
+ }
+ if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
+ {
+ my_errno= HA_ERR_RECORD_DELETED;
+ info->cur_row.lastpos= block_info.filepos;
+ info->cur_row.nextpos= block_info.filepos+block_info.block_len;
+ }
+ goto err;
+ }
+ if (block_of_record == 0) /* First block */
+ {
+ info->cur_row.total_length= block_info.rec_len;
+ if (block_info.rec_len > (uint) share->base.max_pack_length)
+ goto panic;
+ info->cur_row.lastpos= filepos;
+ if (share->base.blobs)
+ {
+ if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
+ block_info.rec_len +
+ info->s->base.extra_rec_buff_size))
+ goto err;
+ }
+ to= info->rec_buff;
+ left_len=block_info.rec_len;
+ }
+ if (left_len < block_info.data_len)
+ goto panic; /* Wrong linked record */
+
+ /* copy information that is already read */
+ {
+ uint offset=(uint) (block_info.filepos - filepos);
+ uint tmp_length= (sizeof(block_info.header) - offset);
+ filepos=block_info.filepos;
+
+ if (tmp_length > block_info.data_len)
+ tmp_length= block_info.data_len;
+ if (tmp_length)
+ {
+ memcpy((uchar*) to, block_info.header+offset,tmp_length);
+ block_info.data_len-=tmp_length;
+ left_len-=tmp_length;
+ to+=tmp_length;
+ filepos+=tmp_length;
+ }
+ }
+ /* read rest of record from file */
+ if (block_info.data_len)
+ {
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_ma_read_cache(&info->rec_cache,(uchar*) to,filepos,
+ block_info.data_len,
+ (!block_of_record && skip_deleted_blocks) ?
+ READING_NEXT : 0))
+ goto panic;
+ }
+ else
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <
+ block_info.filepos + block_info.data_len &&
+ flush_io_cache(&info->rec_cache))
+ goto err;
+ /* VOID(my_seek(info->dfile.file, filepos, MY_SEEK_SET, MYF(0))); */
+ if (my_read(info->dfile.file, (uchar*)to, block_info.data_len,
+ MYF(MY_NABP)))
+ {
+ if (my_errno == HA_ERR_FILE_TOO_SHORT)
+ my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
+ goto err;
+ }
+ }
+ }
+ /*
+ Increment block-of-record counter. If it was the first block,
+ remember the position behind the block for the next call.
+ */
+ if (block_of_record++ == 0)
+ {
+ info->cur_row.nextpos= block_info.filepos+block_info.block_len;
+ skip_deleted_blocks=0;
+ }
+ left_len-=block_info.data_len;
+ to+=block_info.data_len;
+ filepos=block_info.next_filepos;
+ } while (left_len);
+
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+ fast_ma_writeinfo(info);
+ if (_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
+ MY_FILE_ERROR)
+ DBUG_RETURN(0);
+ DBUG_RETURN(my_errno); /* Wrong record */
+
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
+err:
+ fast_ma_writeinfo(info);
+ DBUG_RETURN(my_errno);
+}
+
+
+ /* Read and process header from a dynamic-record-file */
+
+uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos)
+{
+ uint return_val=0;
+ uchar *header=info->header;
+
+ if (file >= 0)
+ {
+ /*
+ We do not use my_pread() here because we want to have the file
+ pointer set to the end of the header after this function.
+ my_pread() may leave the file pointer untouched.
+ */
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ if (my_read(file, header, sizeof(info->header),MYF(0)) !=
+ sizeof(info->header))
+ goto err;
+ }
+ DBUG_DUMP("header",header,MARIA_BLOCK_INFO_HEADER_LENGTH);
+ if (info->second_read)
+ {
+ if (info->header[0] <= 6 || info->header[0] == 13)
+ return_val=BLOCK_SYNC_ERROR;
+ }
+ else
+ {
+ if (info->header[0] > 6 && info->header[0] != 13)
+ return_val=BLOCK_SYNC_ERROR;
+ }
+ info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
+
+ switch (info->header[0]) {
+ case 0:
+ if ((info->block_len=(uint) mi_uint3korr(header+1)) <
+ MARIA_MIN_BLOCK_LENGTH ||
+ (info->block_len & (MARIA_DYN_ALIGN_SIZE -1)))
+ goto err;
+ info->filepos=filepos;
+ info->next_filepos=mi_sizekorr(header+4);
+ info->prev_filepos=mi_sizekorr(header+12);
+#if SIZEOF_OFF_T == 4
+ if ((mi_uint4korr(header+4) != 0 &&
+ (mi_uint4korr(header+4) != (ulong) ~0 ||
+ info->next_filepos != (ulong) ~0)) ||
+ (mi_uint4korr(header+12) != 0 &&
+ (mi_uint4korr(header+12) != (ulong) ~0 ||
+ info->prev_filepos != (ulong) ~0)))
+ goto err;
+#endif
+ return return_val | BLOCK_DELETED; /* Deleted block */
+
+ case 1:
+ info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
+ info->filepos=filepos+3;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 2:
+ info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
+ info->filepos=filepos+4;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+
+ case 13:
+ info->rec_len=mi_uint4korr(header+1);
+ info->block_len=info->data_len=mi_uint3korr(header+5);
+ info->next_filepos=mi_sizekorr(header+8);
+ info->second_read=1;
+ info->filepos=filepos+16;
+ return return_val | BLOCK_FIRST;
+
+ case 3:
+ info->rec_len=info->data_len=mi_uint2korr(header+1);
+ info->block_len=info->rec_len+ (uint) header[3];
+ info->filepos=filepos+4;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+ case 4:
+ info->rec_len=info->data_len=mi_uint3korr(header+1);
+ info->block_len=info->rec_len+ (uint) header[4];
+ info->filepos=filepos+5;
+ return return_val | BLOCK_FIRST | BLOCK_LAST;
+
+ case 5:
+ info->rec_len=mi_uint2korr(header+1);
+ info->block_len=info->data_len=mi_uint2korr(header+3);
+ info->next_filepos=mi_sizekorr(header+5);
+ info->second_read=1;
+ info->filepos=filepos+13;
+ return return_val | BLOCK_FIRST;
+ case 6:
+ info->rec_len=mi_uint3korr(header+1);
+ info->block_len=info->data_len=mi_uint3korr(header+4);
+ info->next_filepos=mi_sizekorr(header+7);
+ info->second_read=1;
+ info->filepos=filepos+15;
+ return return_val | BLOCK_FIRST;
+
+ /* The following blocks are identical to 1-6 without rec_len */
+ case 7:
+ info->data_len=info->block_len=mi_uint2korr(header+1);
+ info->filepos=filepos+3;
+ return return_val | BLOCK_LAST;
+ case 8:
+ info->data_len=info->block_len=mi_uint3korr(header+1);
+ info->filepos=filepos+4;
+ return return_val | BLOCK_LAST;
+
+ case 9:
+ info->data_len=mi_uint2korr(header+1);
+ info->block_len=info->data_len+ (uint) header[3];
+ info->filepos=filepos+4;
+ return return_val | BLOCK_LAST;
+ case 10:
+ info->data_len=mi_uint3korr(header+1);
+ info->block_len=info->data_len+ (uint) header[4];
+ info->filepos=filepos+5;
+ return return_val | BLOCK_LAST;
+
+ case 11:
+ info->data_len=info->block_len=mi_uint2korr(header+1);
+ info->next_filepos=mi_sizekorr(header+3);
+ info->second_read=1;
+ info->filepos=filepos+11;
+ return return_val;
+ case 12:
+ info->data_len=info->block_len=mi_uint3korr(header+1);
+ info->next_filepos=mi_sizekorr(header+4);
+ info->second_read=1;
+ info->filepos=filepos+12;
+ return return_val;
+ }
+
+err:
+ my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
+ return BLOCK_ERROR;
+}
diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c
new file mode 100644
index 00000000000..92e0b0d4e15
--- /dev/null
+++ b/storage/maria/ma_extra.c
@@ -0,0 +1,615 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include "ma_blockrec.h"
+
+static void maria_extra_keyflag(MARIA_HA *info,
+ enum ha_extra_function function);
+
+/**
+ @brief Set options and buffers to optimize table handling
+
+ @param name table's name
+ @param info open table
+ @param function operation
+ @param extra_arg Pointer to extra argument (normally pointer to
+ ulong); used when function is one of:
+ HA_EXTRA_WRITE_CACHE
+ HA_EXTRA_CACHE
+
+ @return Operation status
+ @retval 0 ok
+ @retval !=0 error
+*/
+
+int maria_extra(MARIA_HA *info, enum ha_extra_function function,
+ void *extra_arg)
+{
+ int error= 0;
+ ulong cache_size;
+ MARIA_SHARE *share= info->s;
+ my_bool block_records= share->data_file_type == BLOCK_RECORD;
+ DBUG_ENTER("maria_extra");
+ DBUG_PRINT("enter",("function: %d",(int) function));
+
+ switch (function) {
+ case HA_EXTRA_RESET_STATE: /* Reset state (don't free buffers) */
+ info->lastinx= 0; /* Use first index as def */
+ info->last_search_keypage= info->cur_row.lastpos= HA_OFFSET_ERROR;
+ info->page_changed= 1;
+ /* Next/prev gives first/last */
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ reinit_io_cache(&info->rec_cache,READ_CACHE,0,
+ (pbool) (info->lock_type != F_UNLCK),
+ (pbool) test(info->update & HA_STATE_ROW_CHANGED)
+ );
+ }
+ info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
+ HA_STATE_PREV_FOUND);
+ break;
+ case HA_EXTRA_CACHE:
+ if (block_records)
+ break; /* Not supported */
+
+ if (info->lock_type == F_UNLCK &&
+ (share->options & HA_OPTION_PACK_RECORD))
+ {
+ error= 1; /* Not possibly if not locked */
+ my_errno= EACCES;
+ break;
+ }
+ if (info->s->file_map) /* Don't use cache if mmap */
+ break;
+#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
+ if ((share->options & HA_OPTION_COMPRESS_RECORD))
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ if (_ma_memmap_file(info))
+ {
+ /* We don't nead MADV_SEQUENTIAL if small file */
+ madvise((char*) share->file_map, share->state.state.data_file_length,
+ share->state.state.data_file_length <= RECORD_CACHE_SIZE*16 ?
+ MADV_RANDOM : MADV_SEQUENTIAL);
+ pthread_mutex_unlock(&share->intern_lock);
+ break;
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+#endif
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ info->opt_flag&= ~WRITE_CACHE_USED;
+ if ((error= end_io_cache(&info->rec_cache)))
+ break;
+ }
+ if (!(info->opt_flag &
+ (READ_CACHE_USED | WRITE_CACHE_USED | MEMMAP_USED)))
+ {
+ cache_size= (extra_arg ? *(ulong*) extra_arg :
+ my_default_record_cache_size);
+ if (!(init_io_cache(&info->rec_cache, info->dfile.file,
+ (uint) min(share->state.state.data_file_length+1,
+ cache_size),
+ READ_CACHE,0L,(pbool) (info->lock_type != F_UNLCK),
+ MYF(share->write_flag & MY_WAIT_IF_FULL))))
+ {
+ info->opt_flag|= READ_CACHE_USED;
+ info->update&= ~HA_STATE_ROW_CHANGED;
+ }
+ if (share->non_transactional_concurrent_insert)
+ info->rec_cache.end_of_file= info->state->data_file_length;
+ }
+ break;
+ case HA_EXTRA_REINIT_CACHE:
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ reinit_io_cache(&info->rec_cache, READ_CACHE, info->cur_row.nextpos,
+ (pbool) (info->lock_type != F_UNLCK),
+ (pbool) test(info->update & HA_STATE_ROW_CHANGED));
+ info->update&= ~HA_STATE_ROW_CHANGED;
+ if (share->non_transactional_concurrent_insert)
+ info->rec_cache.end_of_file= info->state->data_file_length;
+ }
+ break;
+ case HA_EXTRA_WRITE_CACHE:
+ if (info->lock_type == F_UNLCK)
+ {
+ error= 1; /* Not possibly if not locked */
+ break;
+ }
+ if (block_records)
+ break; /* Not supported */
+
+ cache_size= (extra_arg ? *(ulong*) extra_arg :
+ my_default_record_cache_size);
+ if (!(info->opt_flag &
+ (READ_CACHE_USED | WRITE_CACHE_USED | OPT_NO_ROWS)) &&
+ !share->state.header.uniques)
+ if (!(init_io_cache(&info->rec_cache, info->dfile.file, cache_size,
+ WRITE_CACHE,share->state.state.data_file_length,
+ (pbool) (info->lock_type != F_UNLCK),
+ MYF(share->write_flag & MY_WAIT_IF_FULL))))
+ {
+ info->opt_flag|= WRITE_CACHE_USED;
+ info->update&= ~(HA_STATE_ROW_CHANGED |
+ HA_STATE_WRITE_AT_END |
+ HA_STATE_EXTEND_BLOCK);
+ }
+ break;
+ case HA_EXTRA_PREPARE_FOR_UPDATE:
+ if (info->s->data_file_type != DYNAMIC_RECORD)
+ break;
+ /* Remove read/write cache if dynamic rows */
+ case HA_EXTRA_NO_CACHE:
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ error= end_io_cache(&info->rec_cache);
+ /* Sergei will insert full text index caching here */
+ }
+#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
+ if (info->opt_flag & MEMMAP_USED)
+ madvise((char*) share->file_map, share->state.state.data_file_length,
+ MADV_RANDOM);
+#endif
+ break;
+ case HA_EXTRA_FLUSH_CACHE:
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ if ((error= flush_io_cache(&info->rec_cache)))
+ {
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_mark_crashed(info); /* Fatal error found */
+ }
+ }
+ break;
+ case HA_EXTRA_NO_READCHECK:
+ info->opt_flag&= ~READ_CHECK_USED; /* No readcheck */
+ break;
+ case HA_EXTRA_READCHECK:
+ info->opt_flag|= READ_CHECK_USED;
+ break;
+ case HA_EXTRA_KEYREAD: /* Read only keys to record */
+ case HA_EXTRA_REMEMBER_POS:
+ info->opt_flag|= REMEMBER_OLD_POS;
+ bmove((uchar*) info->last_key.data + share->base.max_key_length*2,
+ (uchar*) info->last_key.data,
+ info->last_key.data_length + info->last_key.ref_length);
+ info->save_update= info->update;
+ info->save_lastinx= info->lastinx;
+ info->save_lastpos= info->cur_row.lastpos;
+ info->save_lastkey_data_length= info->last_key.data_length;
+ info->save_lastkey_ref_length= info->last_key.ref_length;
+ if (function == HA_EXTRA_REMEMBER_POS)
+ break;
+ /* fall through */
+ case HA_EXTRA_KEYREAD_CHANGE_POS:
+ info->opt_flag|= KEY_READ_USED;
+ info->read_record= _ma_read_key_record;
+ break;
+ case HA_EXTRA_NO_KEYREAD:
+ case HA_EXTRA_RESTORE_POS:
+ if (info->opt_flag & REMEMBER_OLD_POS)
+ {
+ bmove((uchar*) info->last_key.data,
+ (uchar*) info->last_key.data + share->base.max_key_length*2,
+ info->save_lastkey_data_length + info->save_lastkey_ref_length);
+ info->update= info->save_update | HA_STATE_WRITTEN;
+ info->lastinx= info->save_lastinx;
+ info->cur_row.lastpos= info->save_lastpos;
+ info->last_key.data_length= info->save_lastkey_data_length;
+ info->last_key.ref_length= info->save_lastkey_ref_length;
+ info->last_key.flag= 0;
+ }
+ info->read_record= share->read_record;
+ info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
+ break;
+ case HA_EXTRA_NO_USER_CHANGE: /* Database is somehow locked agains changes */
+ info->lock_type= F_EXTRA_LCK; /* Simulate as locked */
+ break;
+ case HA_EXTRA_WAIT_LOCK:
+ info->lock_wait= 0;
+ break;
+ case HA_EXTRA_NO_WAIT_LOCK:
+ info->lock_wait= MY_SHORT_WAIT;
+ break;
+ case HA_EXTRA_NO_KEYS:
+ /* we're going to modify pieces of the state, stall Checkpoint */
+ pthread_mutex_lock(&share->intern_lock);
+ if (info->lock_type == F_UNLCK)
+ {
+ pthread_mutex_unlock(&share->intern_lock);
+ error= 1; /* Not possibly if not lock */
+ break;
+ }
+ if (maria_is_any_key_active(share->state.key_map))
+ {
+ MARIA_KEYDEF *key= share->keyinfo;
+ uint i;
+ for (i =0 ; i < share->base.keys ; i++,key++)
+ {
+ if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1)
+ {
+ maria_clear_key_active(share->state.key_map, i);
+ info->update|= HA_STATE_CHANGED;
+ }
+ }
+
+ if (!share->changed)
+ {
+ share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED;
+ share->changed= 1; /* Update on close */
+ if (!share->global_changed)
+ {
+ share->global_changed= 1;
+ share->state.open_count++;
+ }
+ }
+ if (!share->now_transactional)
+ share->state.state= *info->state;
+ /*
+ That state write to disk must be done, even for transactional tables;
+ indeed the table's share is going to be lost (there was a
+ HA_EXTRA_FORCE_REOPEN before, which set share->last_version to
+ 0), and so the only way it leaves information (share->state.key_map)
+ for the posterity is by writing it to disk.
+ */
+ DBUG_ASSERT(!maria_in_recovery);
+ error= _ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO);
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+ break;
+ case HA_EXTRA_FORCE_REOPEN:
+ /*
+ MySQL uses this case after it has closed all other instances
+ of this table.
+ We however do a flush here for additional safety.
+ */
+ /** @todo consider porting these flush-es to MyISAM */
+ DBUG_ASSERT(share->reopen == 1);
+ error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE);
+ if (!error && share->changed)
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ if (!(error= _ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET|
+ MA_STATE_INFO_WRITE_FULL_INFO)))
+ share->changed= 0;
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ pthread_mutex_lock(&THR_LOCK_maria);
+ pthread_mutex_lock(&share->intern_lock); /* protect against Checkpoint */
+ /* this makes the share not be re-used next time the table is opened */
+ share->last_version= 0L; /* Impossible version */
+ pthread_mutex_unlock(&share->intern_lock);
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ break;
+ case HA_EXTRA_PREPARE_FOR_DROP:
+ case HA_EXTRA_PREPARE_FOR_RENAME:
+ {
+ my_bool do_flush= test(function != HA_EXTRA_PREPARE_FOR_DROP);
+ enum flush_type type;
+ pthread_mutex_lock(&THR_LOCK_maria);
+ /*
+ This share, to have last_version=0, needs to save all its data/index
+ blocks to disk if this is not for a DROP TABLE. Otherwise they would be
+ invisible to future openers; and they could even go to disk late and
+ cancel the work of future openers.
+ */
+ if (info->lock_type != F_UNLCK && !info->was_locked)
+ {
+ info->was_locked= info->lock_type;
+ if (maria_lock_database(info, F_UNLCK))
+ error= my_errno;
+ info->lock_type= F_UNLCK;
+ }
+ if (share->kfile.file >= 0)
+ _ma_decrement_open_count(info);
+ pthread_mutex_lock(&share->intern_lock);
+ if (info->trn)
+ {
+ _ma_remove_table_from_trnman(share, info->trn);
+ /* Ensure we don't point to the deleted data in trn */
+ info->state= info->state_start= &share->state.state;
+ }
+
+ type= do_flush ? FLUSH_RELEASE : FLUSH_IGNORE_CHANGED;
+ if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ type, type))
+ {
+ error=my_errno;
+ share->changed= 1;
+ }
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ if (end_io_cache(&info->rec_cache))
+ error= 1;
+ }
+ if (share->kfile.file >= 0)
+ {
+ if (do_flush)
+ {
+ /* Save the state so that others can find it from disk. */
+ if ((share->changed &&
+ _ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO)) ||
+ my_sync(share->kfile.file, MYF(0)))
+ error= my_errno;
+ else
+ share->changed= 0;
+ }
+ else
+ {
+ /* be sure that state is not tried for write as file may be closed */
+ share->changed= 0;
+ }
+ }
+ if (share->data_file_type == BLOCK_RECORD &&
+ share->bitmap.file.file >= 0)
+ {
+ if (do_flush && my_sync(share->bitmap.file.file, MYF(0)))
+ error= my_errno;
+ }
+ /* For protection against Checkpoint, we set under intern_lock: */
+ share->last_version= 0L; /* Impossible version */
+ pthread_mutex_unlock(&share->intern_lock);
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ break;
+ }
+ case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
+ if (info->trn)
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ _ma_remove_table_from_trnman(share, info->trn);
+ /* Ensure we don't point to the deleted data in trn */
+ info->state= info->state_start= &share->state.state;
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ break;
+ case HA_EXTRA_FLUSH:
+ if (!share->temporary)
+ error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_KEEP, FLUSH_KEEP);
+#ifdef HAVE_PWRITE
+ _ma_decrement_open_count(info);
+#endif
+ if (share->not_flushed)
+ {
+ share->not_flushed= 0;
+ if (_ma_sync_table_files(info))
+ error= my_errno;
+ if (error)
+ {
+ share->changed= 1;
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_mark_crashed(info); /* Fatal error found */
+ }
+ }
+ break;
+ case HA_EXTRA_NORMAL: /* Theese isn't in use */
+ info->quick_mode= 0;
+ break;
+ case HA_EXTRA_QUICK:
+ info->quick_mode= 1;
+ break;
+ case HA_EXTRA_NO_ROWS:
+ if (!share->state.header.uniques)
+ info->opt_flag|= OPT_NO_ROWS;
+ break;
+ case HA_EXTRA_PRELOAD_BUFFER_SIZE:
+ info->preload_buff_size= *((ulong *) extra_arg);
+ break;
+ case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
+ case HA_EXTRA_CHANGE_KEY_TO_DUP:
+ maria_extra_keyflag(info, function);
+ break;
+ case HA_EXTRA_MMAP:
+#ifdef HAVE_MMAP
+ if (block_records)
+ break; /* Not supported */
+ pthread_mutex_lock(&share->intern_lock);
+ /*
+ Memory map the data file if it is not already mapped. It is safe
+ to memory map a file while other threads are using file I/O on it.
+ Assigning a new address to a function pointer is an atomic
+ operation. intern_lock prevents that two or more mappings are done
+ at the same time.
+ */
+ if (!share->file_map)
+ {
+ if (_ma_dynmap_file(info, share->state.state.data_file_length))
+ {
+ DBUG_PRINT("warning",("mmap failed: errno: %d",errno));
+ error= my_errno= errno;
+ }
+ else
+ {
+ share->file_read= _ma_mmap_pread;
+ share->file_write= _ma_mmap_pwrite;
+ }
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+#endif
+ break;
+ case HA_EXTRA_MARK_AS_LOG_TABLE:
+ pthread_mutex_lock(&share->intern_lock);
+ share->is_log_table= TRUE;
+ pthread_mutex_unlock(&share->intern_lock);
+ break;
+ case HA_EXTRA_KEY_CACHE:
+ case HA_EXTRA_NO_KEY_CACHE:
+ default:
+ break;
+ }
+ DBUG_RETURN(error);
+} /* maria_extra */
+
+
+/*
+ Start/Stop Inserting Duplicates Into a Table, WL#1648.
+*/
+
+static void maria_extra_keyflag(MARIA_HA *info,
+ enum ha_extra_function function)
+{
+ uint idx;
+
+ for (idx= 0; idx< info->s->base.keys; idx++)
+ {
+ switch (function) {
+ case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
+ info->s->keyinfo[idx].flag|= HA_NOSAME;
+ break;
+ case HA_EXTRA_CHANGE_KEY_TO_DUP:
+ info->s->keyinfo[idx].flag&= ~(HA_NOSAME);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+int maria_reset(MARIA_HA *info)
+{
+ int error= 0;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_reset");
+ /*
+ Free buffers and reset the following flags:
+ EXTRA_CACHE, EXTRA_WRITE_CACHE, EXTRA_KEYREAD, EXTRA_QUICK
+
+ If the row buffer cache is large (for dynamic tables), reduce it
+ to save memory.
+ */
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ error= end_io_cache(&info->rec_cache);
+ }
+ /* Free memory used for keeping blobs */
+ if (share->base.blobs)
+ {
+ if (info->rec_buff_size > share->base.default_rec_buff_size)
+ {
+ info->rec_buff_size= 1; /* Force realloc */
+ _ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
+ share->base.default_rec_buff_size);
+ }
+ if (info->blob_buff_size > MARIA_SMALL_BLOB_BUFFER)
+ {
+ info->blob_buff_size= 1; /* Force realloc */
+ _ma_alloc_buffer(&info->blob_buff, &info->blob_buff_size,
+ MARIA_SMALL_BLOB_BUFFER);
+ }
+ }
+#if defined(HAVE_MMAP) && defined(HAVE_MADVISE)
+ if (info->opt_flag & MEMMAP_USED)
+ madvise((char*) share->file_map, share->state.state.data_file_length,
+ MADV_RANDOM);
+#endif
+ info->opt_flag&= ~(KEY_READ_USED | REMEMBER_OLD_POS);
+ info->quick_mode= 0;
+ info->lastinx= 0; /* Use first index as def */
+ info->last_search_keypage= info->cur_row.lastpos= HA_OFFSET_ERROR;
+ info->page_changed= 1;
+ info->update= ((info->update & HA_STATE_CHANGED) | HA_STATE_NEXT_FOUND |
+ HA_STATE_PREV_FOUND);
+ DBUG_RETURN(error);
+}
+
+
+int _ma_sync_table_files(const MARIA_HA *info)
+{
+ return (my_sync(info->dfile.file, MYF(MY_WME)) ||
+ my_sync(info->s->kfile.file, MYF(MY_WME)));
+}
+
+
+/**
+ @brief flushes the data and/or index file of a table
+
+ This is useful when one wants to read a table using OS syscalls (like
+ my_copy()) and first wants to be sure that MySQL-level caches go down to
+ the OS so that OS syscalls can see all data. It can flush rec_cache,
+ bitmap, pagecache of data file, pagecache of index file.
+
+ @param info table
+ @param flush_data_or_index one or two of these flags:
+ MARIA_FLUSH_DATA, MARIA_FLUSH_INDEX
+ @param flush_type_for_data
+ @param flush_type_for_index
+
+ @note does not sync files (@see _ma_sync_table_files()).
+ @note Progressively this function will be used in all places where we flush
+ the index but not the data file (probable bugs).
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
+ enum flush_type flush_type_for_data,
+ enum flush_type flush_type_for_index)
+{
+ int error= 0;
+ MARIA_SHARE *share= info->s;
+ /* flush data file first because it's more critical */
+ if (flush_data_or_index & MARIA_FLUSH_DATA)
+ {
+ if ((info->opt_flag & WRITE_CACHE_USED) &&
+ flush_type_for_data != FLUSH_IGNORE_CHANGED &&
+ flush_io_cache(&info->rec_cache))
+ error= 1;
+ if (share->data_file_type == BLOCK_RECORD)
+ {
+ if (flush_type_for_data != FLUSH_IGNORE_CHANGED)
+ {
+ if (_ma_bitmap_flush(share))
+ error= 1;
+ }
+ else
+ {
+ pthread_mutex_lock(&share->bitmap.bitmap_lock);
+ share->bitmap.changed= 0;
+ pthread_mutex_unlock(&share->bitmap.bitmap_lock);
+ }
+ if (flush_pagecache_blocks(share->pagecache, &info->dfile,
+ flush_type_for_data))
+ error= 1;
+ }
+ }
+ if ((flush_data_or_index & MARIA_FLUSH_INDEX) &&
+ flush_pagecache_blocks(share->pagecache, &share->kfile,
+ flush_type_for_index))
+ error= 1;
+ if (!error)
+ return 0;
+
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_mark_crashed(info);
+ return 1;
+}
diff --git a/storage/maria/ma_ft_boolean_search.c b/storage/maria/ma_ft_boolean_search.c
new file mode 100644
index 00000000000..3bcbd9edfbf
--- /dev/null
+++ b/storage/maria/ma_ft_boolean_search.c
@@ -0,0 +1,1013 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/* TODO: add caching - pre-read several index entries at once */
+
+/*
+ Added optimization for full-text queries with plus-words. It was
+ implemented by sharing maximal document id (max_docid) variable
+ inside plus subtree. max_docid could be used by any word in plus
+ subtree, but it could be updated by plus-word only.
+
+ Fulltext "smarter index merge" optimization assumes that rows
+ it gets are ordered by doc_id. That is not the case when we
+ search for a word with truncation operator. It may return
+ rows in random order. Thus we may not use "smarter index merge"
+ optimization with "trunc-words".
+
+ The idea is: there is no need to search for docid smaller than
+ biggest docid inside current plus subtree or any upper plus subtree.
+
+ Examples:
+ +word1 word2
+ share same max_docid
+ max_docid updated by word1
+ +word1 +(word2 word3)
+ share same max_docid
+ max_docid updated by word1
+ +(word1 -word2) +(+word3 word4)
+ share same max_docid
+ max_docid updated by word3
+ +word1 word2 (+word3 word4 (+word5 word6))
+ three subexpressions (including the top-level one),
+ every one has its own max_docid, updated by its plus word.
+ but for the search word6 uses
+ max(word1.max_docid, word3.max_docid, word5.max_docid),
+ while word4 uses, accordingly,
+ max(word1.max_docid, word3.max_docid).
+*/
+
+#define FT_CORE
+#include "ma_ftdefs.h"
+
+/* search with boolean queries */
+
+static double _wghts[11]=
+{
+ 0.131687242798354,
+ 0.197530864197531,
+ 0.296296296296296,
+ 0.444444444444444,
+ 0.666666666666667,
+ 1.000000000000000,
+ 1.500000000000000,
+ 2.250000000000000,
+ 3.375000000000000,
+ 5.062500000000000,
+ 7.593750000000000};
+static double *wghts=_wghts+5; /* wghts[i] = 1.5**i */
+
+static double _nwghts[11]=
+{
+ -0.065843621399177,
+ -0.098765432098766,
+ -0.148148148148148,
+ -0.222222222222222,
+ -0.333333333333334,
+ -0.500000000000000,
+ -0.750000000000000,
+ -1.125000000000000,
+ -1.687500000000000,
+ -2.531250000000000,
+ -3.796875000000000};
+static double *nwghts=_nwghts+5; /* nwghts[i] = -0.5*1.5**i */
+
+#define FTB_FLAG_TRUNC 1
+/* At most one of the following flags can be set */
+#define FTB_FLAG_YES 2
+#define FTB_FLAG_NO 4
+#define FTB_FLAG_WONLY 8
+
+typedef struct st_ftb_expr FTB_EXPR;
+struct st_ftb_expr
+{
+ FTB_EXPR *up;
+ uint flags;
+/* ^^^^^^^^^^^^^^^^^^ FTB_{EXPR,WORD} common section */
+ my_off_t docid[2];
+ my_off_t max_docid;
+ float weight;
+ float cur_weight;
+ LIST *phrase; /* phrase words */
+ LIST *document; /* for phrase search */
+ uint yesses; /* number of "yes" words matched */
+ uint nos; /* number of "no" words matched */
+ uint ythresh; /* number of "yes" words in expr */
+ uint yweaks; /* number of "yes" words for scan only */
+};
+
+typedef struct st_ftb_word
+{
+ FTB_EXPR *up;
+ uint flags;
+/* ^^^^^^^^^^^^^^^^^^ FTB_{EXPR,WORD} common section */
+ my_off_t docid[2]; /* for index search and for scan */
+ my_off_t key_root;
+ FTB_EXPR *max_docid_expr;
+ MARIA_KEYDEF *keyinfo;
+ struct st_ftb_word *prev;
+ float weight;
+ uint ndepth;
+ uint len;
+ uchar off;
+ uchar word[1];
+} FTB_WORD;
+
+typedef struct st_ft_info
+{
+ struct _ft_vft *please;
+ MARIA_HA *info;
+ CHARSET_INFO *charset;
+ FTB_EXPR *root;
+ FTB_WORD **list;
+ FTB_WORD *last_word;
+ MEM_ROOT mem_root;
+ QUEUE queue;
+ TREE no_dupes;
+ my_off_t lastpos;
+ uint keynr;
+ uchar with_scan;
+ enum { UNINITIALIZED, READY, INDEX_SEARCH, INDEX_DONE } state;
+} FTB;
+
+static int FTB_WORD_cmp(my_off_t *v, FTB_WORD *a, FTB_WORD *b)
+{
+ int i;
+
+ /* if a==curdoc, take it as a < b */
+ if (v && a->docid[0] == *v)
+ return -1;
+
+ /* ORDER BY docid, ndepth DESC */
+ i=CMP_NUM(a->docid[0], b->docid[0]);
+ if (!i)
+ i=CMP_NUM(b->ndepth,a->ndepth);
+ return i;
+}
+
+static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b)
+{
+ /* ORDER BY word DESC, ndepth DESC */
+ int i= ha_compare_text(cs, (uchar*) (*b)->word+1,(*b)->len-1,
+ (uchar*) (*a)->word+1,(*a)->len-1,0,0);
+ if (!i)
+ i=CMP_NUM((*b)->ndepth,(*a)->ndepth);
+ return i;
+}
+
+
+typedef struct st_my_ftb_param
+{
+ FTB *ftb;
+ FTB_EXPR *ftbe;
+ uchar *up_quot;
+ uint depth;
+} MY_FTB_PARAM;
+
+
+static int ftb_query_add_word(MYSQL_FTPARSER_PARAM *param,
+ char *word, int word_len,
+ MYSQL_FTPARSER_BOOLEAN_INFO *info)
+{
+ MY_FTB_PARAM *ftb_param= param->mysql_ftparam;
+ FTB_WORD *ftbw;
+ FTB_EXPR *ftbe, *tmp_expr;
+ FT_WORD *phrase_word;
+ LIST *tmp_element;
+ int r= info->weight_adjust;
+ float weight= (float)
+ (info->wasign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];
+
+ switch (info->type) {
+ case FT_TOKEN_WORD:
+ ftbw= (FTB_WORD *)alloc_root(&ftb_param->ftb->mem_root,
+ sizeof(FTB_WORD) +
+ (info->trunc ? MARIA_MAX_KEY_BUFF :
+ word_len * ftb_param->ftb->charset->mbmaxlen +
+ HA_FT_WLEN +
+ ftb_param->ftb->info->s->rec_reflength));
+ ftbw->len= word_len + 1;
+ ftbw->flags= 0;
+ ftbw->off= 0;
+ if (info->yesno > 0) ftbw->flags|= FTB_FLAG_YES;
+ if (info->yesno < 0) ftbw->flags|= FTB_FLAG_NO;
+ if (info->trunc) ftbw->flags|= FTB_FLAG_TRUNC;
+ ftbw->weight= weight;
+ ftbw->up= ftb_param->ftbe;
+ ftbw->docid[0]= ftbw->docid[1]= HA_OFFSET_ERROR;
+ ftbw->ndepth= (info->yesno < 0) + ftb_param->depth;
+ ftbw->key_root= HA_OFFSET_ERROR;
+ memcpy(ftbw->word + 1, word, word_len);
+ ftbw->word[0]= word_len;
+ if (info->yesno > 0) ftbw->up->ythresh++;
+ ftb_param->ftb->queue.max_elements++;
+ ftbw->prev= ftb_param->ftb->last_word;
+ ftb_param->ftb->last_word= ftbw;
+ ftb_param->ftb->with_scan|= (info->trunc & FTB_FLAG_TRUNC);
+ for (tmp_expr= ftb_param->ftbe; tmp_expr->up; tmp_expr= tmp_expr->up)
+ if (! (tmp_expr->flags & FTB_FLAG_YES))
+ break;
+ ftbw->max_docid_expr= tmp_expr;
+ /* fall through */
+ case FT_TOKEN_STOPWORD:
+ if (! ftb_param->up_quot) break;
+ phrase_word= (FT_WORD *)alloc_root(&ftb_param->ftb->mem_root, sizeof(FT_WORD));
+ tmp_element= (LIST *)alloc_root(&ftb_param->ftb->mem_root, sizeof(LIST));
+ phrase_word->pos= (uchar*) word;
+ phrase_word->len= word_len;
+ tmp_element->data= (void *)phrase_word;
+ ftb_param->ftbe->phrase= list_add(ftb_param->ftbe->phrase, tmp_element);
+ /* Allocate document list at this point.
+ It allows to avoid huge amount of allocs/frees for each row.*/
+ tmp_element= (LIST *)alloc_root(&ftb_param->ftb->mem_root, sizeof(LIST));
+ tmp_element->data= alloc_root(&ftb_param->ftb->mem_root, sizeof(FT_WORD));
+ ftb_param->ftbe->document=
+ list_add(ftb_param->ftbe->document, tmp_element);
+ break;
+ case FT_TOKEN_LEFT_PAREN:
+ ftbe=(FTB_EXPR *)alloc_root(&ftb_param->ftb->mem_root, sizeof(FTB_EXPR));
+ ftbe->flags= 0;
+ if (info->yesno > 0) ftbe->flags|= FTB_FLAG_YES;
+ if (info->yesno < 0) ftbe->flags|= FTB_FLAG_NO;
+ ftbe->weight= weight;
+ ftbe->up= ftb_param->ftbe;
+ ftbe->max_docid= ftbe->ythresh= ftbe->yweaks= 0;
+ ftbe->docid[0]= ftbe->docid[1]= HA_OFFSET_ERROR;
+ ftbe->phrase= NULL;
+ ftbe->document= 0;
+ if (info->quot) ftb_param->ftb->with_scan|= 2;
+ if (info->yesno > 0) ftbe->up->ythresh++;
+ ftb_param->ftbe= ftbe;
+ ftb_param->depth++;
+ ftb_param->up_quot= (uchar*) info->quot;
+ break;
+ case FT_TOKEN_RIGHT_PAREN:
+ if (ftb_param->ftbe->document)
+ {
+ /* Circuit document list */
+ for (tmp_element= ftb_param->ftbe->document;
+ tmp_element->next; tmp_element= tmp_element->next) /* no-op */;
+ tmp_element->next= ftb_param->ftbe->document;
+ ftb_param->ftbe->document->prev= tmp_element;
+ }
+ info->quot= 0;
+ if (ftb_param->ftbe->up)
+ {
+ DBUG_ASSERT(ftb_param->depth);
+ ftb_param->ftbe= ftb_param->ftbe->up;
+ ftb_param->depth--;
+ ftb_param->up_quot= 0;
+ }
+ break;
+ case FT_TOKEN_EOF:
+ default:
+ break;
+ }
+ return(0);
+}
+
+
+static int ftb_parse_query_internal(MYSQL_FTPARSER_PARAM *param,
+ char *query, int len)
+{
+ MY_FTB_PARAM *ftb_param= param->mysql_ftparam;
+ MYSQL_FTPARSER_BOOLEAN_INFO info;
+ CHARSET_INFO *cs= ftb_param->ftb->charset;
+ uchar **start= (uchar**) &query;
+ uchar *end= (uchar*) query + len;
+ FT_WORD w;
+
+ info.prev= ' ';
+ info.quot= 0;
+ while (maria_ft_get_word(cs, start, end, &w, &info))
+ param->mysql_add_word(param, (char *) w.pos, w.len, &info);
+ return(0);
+}
+
+
+static int _ftb_parse_query(FTB *ftb, uchar *query, uint len,
+ struct st_mysql_ftparser *parser)
+{
+ MYSQL_FTPARSER_PARAM *param;
+ MY_FTB_PARAM ftb_param;
+ DBUG_ENTER("_ftb_parse_query");
+ DBUG_ASSERT(parser);
+
+ if (ftb->state != UNINITIALIZED)
+ DBUG_RETURN(0);
+ if (! (param= maria_ftparser_call_initializer(ftb->info, ftb->keynr, 0)))
+ DBUG_RETURN(1);
+
+ ftb_param.ftb= ftb;
+ ftb_param.depth= 0;
+ ftb_param.ftbe= ftb->root;
+ ftb_param.up_quot= 0;
+
+ param->mysql_parse= ftb_parse_query_internal;
+ param->mysql_add_word= ftb_query_add_word;
+ param->mysql_ftparam= (void *)&ftb_param;
+ param->cs= ftb->charset;
+ param->doc= (char*) query;
+ param->length= len;
+ param->flags= 0;
+ param->mode= MYSQL_FTPARSER_FULL_BOOLEAN_INFO;
+ DBUG_RETURN(parser->parse(param));
+}
+
+
+static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)),
+ const void *a,const void *b)
+{
+ return CMP_NUM((*((my_off_t*)a)), (*((my_off_t*)b)));
+}
+
+
+/* returns 1 if the search was finished (must-word wasn't found) */
+
+static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
+{
+ int r;
+ int subkeys=1;
+ my_bool can_go_down;
+ MARIA_HA *info=ftb->info;
+ uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength;
+ uchar *lastkey_buf= ftbw->word+ftbw->off;
+ MARIA_KEY key;
+ LINT_INIT(off);
+
+ if (ftbw->flags & FTB_FLAG_TRUNC)
+ lastkey_buf+=ftbw->len;
+
+ if (init_search)
+ {
+ ftbw->key_root=info->s->state.key_root[ftb->keynr];
+ ftbw->keyinfo=info->s->keyinfo+ftb->keynr;
+ key.keyinfo= ftbw->keyinfo;
+ key.data= ftbw->word;
+ key.data_length= ftbw->len;
+ key.ref_length= 0;
+ key.flag= 0;
+
+ r= _ma_search(info, &key, SEARCH_FIND | SEARCH_BIGGER, ftbw->key_root);
+ }
+ else
+ {
+ uint sflag= SEARCH_BIGGER;
+ my_off_t max_docid=0;
+ FTB_EXPR *tmp;
+
+ for (tmp= ftbw->max_docid_expr; tmp; tmp= tmp->up)
+ set_if_bigger(max_docid, tmp->max_docid);
+
+ if (ftbw->docid[0] < max_docid)
+ {
+ sflag|= SEARCH_SAME;
+ _ma_dpointer(info->s, (uchar*) (ftbw->word + ftbw->len + HA_FT_WLEN),
+ max_docid);
+ }
+
+ key.keyinfo= ftbw->keyinfo;
+ key.data= lastkey_buf;
+ key.data_length= USE_WHOLE_KEY;
+ key.ref_length= 0;
+ key.flag= 0;
+
+ r= _ma_search(info, &key, sflag, ftbw->key_root);
+ }
+
+ can_go_down=(!ftbw->off && (init_search || (ftbw->flags & FTB_FLAG_TRUNC)));
+ /* Skip rows inserted by concurrent insert */
+ while (!r)
+ {
+ if (can_go_down)
+ {
+ /* going down ? */
+ off= info->last_key.data_length + info->last_key.ref_length - extra;
+ subkeys=ft_sintXkorr(info->last_key.data + off);
+ }
+ if (subkeys<0 || info->cur_row.lastpos < info->state->data_file_length)
+ break;
+ r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, ftbw->key_root);
+ }
+
+ if (!r && !ftbw->off)
+ {
+ r= ha_compare_text(ftb->charset,
+ info->last_key.data+1,
+ info->last_key.data_length + info->last_key.ref_length-
+ extra-1,
+ (uchar*) ftbw->word+1,
+ ftbw->len-1,
+ (my_bool) (ftbw->flags & FTB_FLAG_TRUNC), 0);
+ }
+
+ if (r) /* not found */
+ {
+ if (!ftbw->off || !(ftbw->flags & FTB_FLAG_TRUNC))
+ {
+ ftbw->docid[0]=HA_OFFSET_ERROR;
+ if ((ftbw->flags & FTB_FLAG_YES) && ftbw->up->up==0)
+ {
+ /*
+ This word MUST BE present in every document returned,
+ so we can stop the search right now
+ */
+ ftb->state=INDEX_DONE;
+ return 1; /* search is done */
+ }
+ else
+ return 0;
+ }
+
+ /* going up to the first-level tree to continue search there */
+ _ma_dpointer(info->s, (lastkey_buf+HA_FT_WLEN), ftbw->key_root);
+ ftbw->key_root=info->s->state.key_root[ftb->keynr];
+ ftbw->keyinfo=info->s->keyinfo+ftb->keynr;
+ ftbw->off=0;
+ return _ft2_search(ftb, ftbw, 0);
+ }
+
+ /* matching key found */
+ memcpy(lastkey_buf, info->last_key.data,
+ info->last_key.data_length + info->last_key.ref_length);
+ if (lastkey_buf == ftbw->word)
+ ftbw->len= info->last_key.data_length + info->last_key.ref_length - extra;
+
+ /* going down ? */
+ if (subkeys<0)
+ {
+ /*
+ yep, going down, to the second-level tree
+ TODO here: subkey-based optimization
+ */
+ ftbw->off=off;
+ ftbw->key_root= info->cur_row.lastpos;
+ ftbw->keyinfo=& info->s->ft2_keyinfo;
+ r= _ma_search_first(info, ftbw->keyinfo, ftbw->key_root);
+ DBUG_ASSERT(r==0); /* found something */
+ memcpy(lastkey_buf+off, info->last_key.data,
+ info->last_key.data_length + info->last_key.ref_length);
+ }
+ ftbw->docid[0]= info->cur_row.lastpos;
+ if (ftbw->flags & FTB_FLAG_YES && !(ftbw->flags & FTB_FLAG_TRUNC))
+ ftbw->max_docid_expr->max_docid= info->cur_row.lastpos;
+ return 0;
+}
+
+static void _ftb_init_index_search(FT_INFO *ftb)
+{
+ int i;
+ FTB_WORD *ftbw;
+
+ if ((ftb->state != READY && ftb->state !=INDEX_DONE) ||
+ ftb->keynr == NO_SUCH_KEY)
+ return;
+ ftb->state=INDEX_SEARCH;
+
+ for (i=ftb->queue.elements; i; i--)
+ {
+ ftbw=(FTB_WORD *)(ftb->queue.root[i]);
+
+ if (ftbw->flags & FTB_FLAG_TRUNC)
+ {
+ /*
+ special treatment for truncation operator
+ 1. there are some (besides this) +words
+ | no need to search in the index, it can never ADD new rows
+ | to the result, and to remove half-matched rows we do scan anyway
+ 2. -trunc*
+ | same as 1.
+ 3. in 1 and 2, +/- need not be on the same expr. level,
+ but can be on any upper level, as in +word +(trunc1* trunc2*)
+ 4. otherwise
+ | We have to index-search for this prefix.
+ | It may cause duplicates, as in the index (sorted by <word,docid>)
+ | <aaaa,row1>
+ | <aabb,row2>
+ | <aacc,row1>
+ | Searching for "aa*" will find row1 twice...
+ */
+ FTB_EXPR *ftbe;
+ for (ftbe=(FTB_EXPR*)ftbw;
+ ftbe->up && !(ftbe->up->flags & FTB_FLAG_TRUNC);
+ ftbe->up->flags|= FTB_FLAG_TRUNC, ftbe=ftbe->up)
+ {
+ if (ftbe->flags & FTB_FLAG_NO || /* 2 */
+ ftbe->up->ythresh - ftbe->up->yweaks >
+ (uint) test(ftbe->flags & FTB_FLAG_YES)) /* 1 */
+ {
+ FTB_EXPR *top_ftbe=ftbe->up;
+ ftbw->docid[0]=HA_OFFSET_ERROR;
+ for (ftbe=(FTB_EXPR *)ftbw;
+ ftbe != top_ftbe && !(ftbe->flags & FTB_FLAG_NO);
+ ftbe=ftbe->up)
+ ftbe->up->yweaks++;
+ ftbe=0;
+ break;
+ }
+ }
+ if (!ftbe)
+ continue;
+ /* 4 */
+ if (!is_tree_inited(& ftb->no_dupes))
+ init_tree(& ftb->no_dupes,0,0,sizeof(my_off_t),
+ _ftb_no_dupes_cmp,0,0,0);
+ else
+ reset_tree(& ftb->no_dupes);
+ }
+
+ ftbw->off=0; /* in case of reinit */
+ if (_ft2_search(ftb, ftbw, 1))
+ return;
+ }
+ queue_fix(& ftb->queue);
+}
+
+
+FT_INFO * maria_ft_init_boolean_search(MARIA_HA *info, uint keynr,
+ uchar *query,
+ uint query_len, CHARSET_INFO *cs)
+{
+ FTB *ftb;
+ FTB_EXPR *ftbe;
+ FTB_WORD *ftbw;
+
+ if (!(ftb=(FTB *)my_malloc(sizeof(FTB), MYF(MY_WME))))
+ return 0;
+ ftb->please= (struct _ft_vft *) & _ma_ft_vft_boolean;
+ ftb->state=UNINITIALIZED;
+ ftb->info=info;
+ ftb->keynr=keynr;
+ ftb->charset=cs;
+ DBUG_ASSERT(keynr==NO_SUCH_KEY || cs == info->s->keyinfo[keynr].seg->charset);
+ ftb->with_scan=0;
+ ftb->lastpos=HA_OFFSET_ERROR;
+ bzero(& ftb->no_dupes, sizeof(TREE));
+ ftb->last_word= 0;
+
+ init_alloc_root(&ftb->mem_root, 1024, 1024);
+ ftb->queue.max_elements= 0;
+ if (!(ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR))))
+ goto err;
+ ftbe->weight=1;
+ ftbe->flags=FTB_FLAG_YES;
+ ftbe->nos=1;
+ ftbe->up=0;
+ ftbe->max_docid= ftbe->ythresh= ftbe->yweaks= 0;
+ ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
+ ftbe->phrase= NULL;
+ ftbe->document= 0;
+ ftb->root=ftbe;
+ if (unlikely(_ftb_parse_query(ftb, query, query_len,
+ keynr == NO_SUCH_KEY ? &ft_default_parser :
+ info->s->keyinfo[keynr].parser)))
+ goto err;
+ /*
+ Hack: instead of init_queue, we'll use reinit queue to be able
+ to alloc queue with alloc_root()
+ */
+ if (! (ftb->queue.root= (uchar **)alloc_root(&ftb->mem_root,
+ (ftb->queue.max_elements + 1) *
+ sizeof(void *))))
+ goto err;
+ reinit_queue(&ftb->queue, ftb->queue.max_elements, 0, 0,
+ (int (*)(void*, uchar*, uchar*))FTB_WORD_cmp, 0);
+ for (ftbw= ftb->last_word; ftbw; ftbw= ftbw->prev)
+ queue_insert(&ftb->queue, (uchar *)ftbw);
+ ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root,
+ sizeof(FTB_WORD *)*ftb->queue.elements);
+ memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements);
+ my_qsort2(ftb->list, ftb->queue.elements, sizeof(FTB_WORD *),
+ (qsort2_cmp)FTB_WORD_cmp_list, ftb->charset);
+ if (ftb->queue.elements<2) ftb->with_scan &= ~FTB_FLAG_TRUNC;
+ ftb->state=READY;
+ return ftb;
+err:
+ free_root(& ftb->mem_root, MYF(0));
+ my_free((uchar*)ftb,MYF(0));
+ return 0;
+}
+
+
+typedef struct st_my_ftb_phrase_param
+{
+ LIST *phrase;
+ LIST *document;
+ CHARSET_INFO *cs;
+ uint phrase_length;
+ uint document_length;
+ uint match;
+} MY_FTB_PHRASE_PARAM;
+
+
+static int ftb_phrase_add_word(MYSQL_FTPARSER_PARAM *param,
+ char *word, int word_len,
+ MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info __attribute__((unused)))
+{
+ MY_FTB_PHRASE_PARAM *phrase_param= param->mysql_ftparam;
+ FT_WORD *w= (FT_WORD *)phrase_param->document->data;
+ LIST *phrase, *document;
+ w->pos= (uchar*) word;
+ w->len= word_len;
+ phrase_param->document= phrase_param->document->prev;
+ if (phrase_param->phrase_length > phrase_param->document_length)
+ {
+ phrase_param->document_length++;
+ return 0;
+ }
+ /* TODO: rewrite phrase search to avoid
+ comparing the same word twice. */
+ for (phrase= phrase_param->phrase, document= phrase_param->document->next;
+ phrase; phrase= phrase->next, document= document->next)
+ {
+ FT_WORD *phrase_word= (FT_WORD *)phrase->data;
+ FT_WORD *document_word= (FT_WORD *)document->data;
+ if (my_strnncoll(phrase_param->cs, (uchar*) phrase_word->pos,
+ phrase_word->len,
+ (uchar*) document_word->pos, document_word->len))
+ return 0;
+ }
+ phrase_param->match++;
+ return 0;
+}
+
+
+static int ftb_check_phrase_internal(MYSQL_FTPARSER_PARAM *param,
+ char *document, int len)
+{
+ FT_WORD word;
+ MY_FTB_PHRASE_PARAM *phrase_param= param->mysql_ftparam;
+ const uchar *docend= (uchar*) document + len;
+ while (maria_ft_simple_get_word(phrase_param->cs, (uchar**) &document,
+ docend, &word, FALSE))
+ {
+ param->mysql_add_word(param, (char*) word.pos, word.len, 0);
+ if (phrase_param->match)
+ break;
+ }
+ return 0;
+}
+
+
+/*
+ Checks if given buffer matches phrase list.
+
+ SYNOPSIS
+ _ftb_check_phrase()
+ s0 start of buffer
+ e0 end of buffer
+ phrase broken into list phrase
+ cs charset info
+
+ RETURN VALUE
+ 1 is returned if phrase found, 0 else.
+ -1 is returned if error occurs.
+*/
+
+static int _ftb_check_phrase(FTB *ftb, const uchar *document, uint len,
+ FTB_EXPR *ftbe, struct st_mysql_ftparser *parser)
+{
+ MY_FTB_PHRASE_PARAM ftb_param;
+ MYSQL_FTPARSER_PARAM *param;
+ DBUG_ENTER("_ftb_check_phrase");
+ DBUG_ASSERT(parser);
+
+ if (! (param= maria_ftparser_call_initializer(ftb->info, ftb->keynr, 1)))
+ DBUG_RETURN(0);
+ ftb_param.phrase= ftbe->phrase;
+ ftb_param.document= ftbe->document;
+ ftb_param.cs= ftb->charset;
+ ftb_param.phrase_length= list_length(ftbe->phrase);
+ ftb_param.document_length= 1;
+ ftb_param.match= 0;
+
+ param->mysql_parse= ftb_check_phrase_internal;
+ param->mysql_add_word= ftb_phrase_add_word;
+ param->mysql_ftparam= (void *)&ftb_param;
+ param->cs= ftb->charset;
+ param->doc= (char *) document;
+ param->length= len;
+ param->flags= 0;
+ param->mode= MYSQL_FTPARSER_WITH_STOPWORDS;
+ if (unlikely(parser->parse(param)))
+ return -1;
+ DBUG_RETURN(ftb_param.match ? 1 : 0);
+}
+
+
+static int _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_orig)
+{
+ FT_SEG_ITERATOR ftsi;
+ FTB_EXPR *ftbe;
+ float weight=ftbw->weight;
+ int yn_flag= ftbw->flags, ythresh, mode=(ftsi_orig != 0);
+ my_off_t curdoc=ftbw->docid[mode];
+ struct st_mysql_ftparser *parser= ftb->keynr == NO_SUCH_KEY ?
+ &ft_default_parser :
+ ftb->info->s->keyinfo[ftb->keynr].parser;
+
+ for (ftbe=ftbw->up; ftbe; ftbe=ftbe->up)
+ {
+ ythresh = ftbe->ythresh - (mode ? 0 : ftbe->yweaks);
+ if (ftbe->docid[mode] != curdoc)
+ {
+ ftbe->cur_weight=0;
+ ftbe->yesses=ftbe->nos=0;
+ ftbe->docid[mode]=curdoc;
+ }
+ if (ftbe->nos)
+ break;
+ if (yn_flag & FTB_FLAG_YES)
+ {
+ weight /= ftbe->ythresh;
+ ftbe->cur_weight += weight;
+ if ((int) ++ftbe->yesses == ythresh)
+ {
+ yn_flag=ftbe->flags;
+ weight=ftbe->cur_weight*ftbe->weight;
+ if (mode && ftbe->phrase)
+ {
+ int found= 0;
+
+ memcpy(&ftsi, ftsi_orig, sizeof(ftsi));
+ while (_ma_ft_segiterator(&ftsi) && !found)
+ {
+ if (!ftsi.pos)
+ continue;
+ found= _ftb_check_phrase(ftb, ftsi.pos, ftsi.len, ftbe, parser);
+ if (unlikely(found < 0))
+ return 1;
+ }
+ if (!found)
+ break;
+ } /* ftbe->quot */
+ }
+ else
+ break;
+ }
+ else
+ if (yn_flag & FTB_FLAG_NO)
+ {
+ /*
+ NOTE: special sort function of queue assures that all
+ (yn_flag & FTB_FLAG_NO) != 0
+ events for every particular subexpression will
+ "auto-magically" happen BEFORE all the
+ (yn_flag & FTB_FLAG_YES) != 0 events. So no
+ already matched expression can become not-matched again.
+ */
+ ++ftbe->nos;
+ break;
+ }
+ else
+ {
+ if (ftbe->ythresh)
+ weight/=3;
+ ftbe->cur_weight += weight;
+ if ((int) ftbe->yesses < ythresh)
+ break;
+ if (!(yn_flag & FTB_FLAG_WONLY))
+ yn_flag= ((int) ftbe->yesses++ == ythresh) ? ftbe->flags : FTB_FLAG_WONLY ;
+ weight*= ftbe->weight;
+ }
+ }
+ return 0;
+}
+
+
+int maria_ft_boolean_read_next(FT_INFO *ftb, char *record)
+{
+ FTB_EXPR *ftbe;
+ FTB_WORD *ftbw;
+ MARIA_HA *info=ftb->info;
+ my_off_t curdoc;
+
+ if (ftb->state != INDEX_SEARCH && ftb->state != INDEX_DONE)
+ return -1;
+
+ /* black magic ON */
+ if ((int) _ma_check_index(info, ftb->keynr) < 0)
+ return my_errno;
+ if (_ma_readinfo(info, F_RDLCK, 1))
+ return my_errno;
+ /* black magic OFF */
+
+ if (!ftb->queue.elements)
+ return my_errno=HA_ERR_END_OF_FILE;
+
+ /* Attention!!! Address of a local variable is used here! See err: label */
+ ftb->queue.first_cmp_arg=(void *)&curdoc;
+
+ while (ftb->state == INDEX_SEARCH &&
+ (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) !=
+ HA_OFFSET_ERROR)
+ {
+ while (curdoc == (ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0])
+ {
+ if (unlikely(_ftb_climb_the_tree(ftb, ftbw, 0)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ goto err;
+ }
+
+ /* update queue */
+ _ft2_search(ftb, ftbw, 0);
+ queue_replaced(& ftb->queue);
+ }
+
+ ftbe=ftb->root;
+ if (ftbe->docid[0]==curdoc && ftbe->cur_weight>0 &&
+ ftbe->yesses>=(ftbe->ythresh-ftbe->yweaks) && !ftbe->nos)
+ {
+ /* curdoc matched ! */
+ if (is_tree_inited(&ftb->no_dupes) &&
+ tree_insert(&ftb->no_dupes, &curdoc, 0,
+ ftb->no_dupes.custom_arg)->count >1)
+ /* but it managed already to get past this line once */
+ continue;
+
+ info->cur_row.lastpos= curdoc;
+ /* Clear all states, except that the table was updated */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (!(*info->read_record)(info, (uchar *) record, curdoc))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ if (ftb->with_scan &&
+ maria_ft_boolean_find_relevance(ftb, (uchar *) record, 0)==0)
+ continue; /* no match */
+ my_errno=0;
+ goto err;
+ }
+ goto err;
+ }
+ }
+ ftb->state=INDEX_DONE;
+ my_errno=HA_ERR_END_OF_FILE;
+err:
+ ftb->queue.first_cmp_arg=(void *)0;
+ return my_errno;
+}
+
+
+typedef struct st_my_ftb_find_param
+{
+ FT_INFO *ftb;
+ FT_SEG_ITERATOR *ftsi;
+} MY_FTB_FIND_PARAM;
+
+
+static int ftb_find_relevance_add_word(MYSQL_FTPARSER_PARAM *param,
+ char *word, int len,
+ MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info __attribute__((unused)))
+{
+ MY_FTB_FIND_PARAM *ftb_param= param->mysql_ftparam;
+ FT_INFO *ftb= ftb_param->ftb;
+ FTB_WORD *ftbw;
+ int a, b, c;
+ for (a= 0, b= ftb->queue.elements, c= (a+b)/2; b-a>1; c= (a+b)/2)
+ {
+ ftbw= ftb->list[c];
+ if (ha_compare_text(ftb->charset, (uchar*)word, len,
+ (uchar*)ftbw->word+1, ftbw->len-1,
+ (my_bool)(ftbw->flags&FTB_FLAG_TRUNC), 0) > 0)
+ b= c;
+ else
+ a= c;
+ }
+ for (; c >= 0; c--)
+ {
+ ftbw= ftb->list[c];
+ if (ha_compare_text(ftb->charset, (uchar*)word, len,
+ (uchar*)ftbw->word + 1,ftbw->len - 1,
+ (my_bool)(ftbw->flags & FTB_FLAG_TRUNC), 0))
+ break;
+ if (ftbw->docid[1] == ftb->info->cur_row.lastpos)
+ continue;
+ ftbw->docid[1]= ftb->info->cur_row.lastpos;
+ if (unlikely(_ftb_climb_the_tree(ftb, ftbw, ftb_param->ftsi)))
+ return 1;
+ }
+ return(0);
+}
+
+
+static int ftb_find_relevance_parse(MYSQL_FTPARSER_PARAM *param,
+ char *doc, int len)
+{
+ MY_FTB_FIND_PARAM *ftb_param= param->mysql_ftparam;
+ FT_INFO *ftb= ftb_param->ftb;
+ uchar *end= (uchar*) doc + len;
+ FT_WORD w;
+ while (maria_ft_simple_get_word(ftb->charset, (uchar**) &doc,
+ end, &w, TRUE))
+ param->mysql_add_word(param, (char *) w.pos, w.len, 0);
+ return(0);
+}
+
+
+float maria_ft_boolean_find_relevance(FT_INFO *ftb, uchar *record, uint length)
+{
+ FTB_EXPR *ftbe;
+ FT_SEG_ITERATOR ftsi, ftsi2;
+ MARIA_RECORD_POS docid= ftb->info->cur_row.lastpos;
+ MY_FTB_FIND_PARAM ftb_param;
+ MYSQL_FTPARSER_PARAM *param;
+ struct st_mysql_ftparser *parser= ftb->keynr == NO_SUCH_KEY ?
+ &ft_default_parser :
+ ftb->info->s->keyinfo[ftb->keynr].parser;
+
+ if (docid == HA_OFFSET_ERROR)
+ return -2.0;
+ if (!ftb->queue.elements)
+ return 0;
+ if (! (param= maria_ftparser_call_initializer(ftb->info, ftb->keynr, 0)))
+ return 0;
+
+ if (ftb->state != INDEX_SEARCH && docid <= ftb->lastpos)
+ {
+ FTB_EXPR *x;
+ uint i;
+
+ for (i=0; i < ftb->queue.elements; i++)
+ {
+ ftb->list[i]->docid[1]=HA_OFFSET_ERROR;
+ for (x=ftb->list[i]->up; x; x=x->up)
+ x->docid[1]=HA_OFFSET_ERROR;
+ }
+ }
+
+ ftb->lastpos=docid;
+
+ if (ftb->keynr==NO_SUCH_KEY)
+ _ma_ft_segiterator_dummy_init(record, length, &ftsi);
+ else
+ _ma_ft_segiterator_init(ftb->info, ftb->keynr, record, &ftsi);
+ memcpy(&ftsi2, &ftsi, sizeof(ftsi));
+
+ ftb_param.ftb= ftb;
+ ftb_param.ftsi= &ftsi2;
+ param->mysql_parse= ftb_find_relevance_parse;
+ param->mysql_add_word= ftb_find_relevance_add_word;
+ param->mysql_ftparam= (void *)&ftb_param;
+ param->flags= 0;
+ param->cs= ftb->charset;
+ param->mode= MYSQL_FTPARSER_SIMPLE_MODE;
+
+ while (_ma_ft_segiterator(&ftsi))
+ {
+ if (!ftsi.pos)
+ continue;
+ param->doc= (char *)ftsi.pos;
+ param->length= ftsi.len;
+ if (unlikely(parser->parse(param)))
+ return 0;
+ }
+ ftbe=ftb->root;
+ if (ftbe->docid[1]==docid && ftbe->cur_weight>0 &&
+ ftbe->yesses>=ftbe->ythresh && !ftbe->nos)
+ { /* row matched ! */
+ return ftbe->cur_weight;
+ }
+ else
+ { /* match failed ! */
+ return 0.0;
+ }
+}
+
+
+void maria_ft_boolean_close_search(FT_INFO *ftb)
+{
+ if (is_tree_inited(& ftb->no_dupes))
+ {
+ delete_tree(& ftb->no_dupes);
+ }
+ free_root(& ftb->mem_root, MYF(0));
+ my_free((uchar*)ftb,MYF(0));
+}
+
+
+float maria_ft_boolean_get_relevance(FT_INFO *ftb)
+{
+ return ftb->root->cur_weight;
+}
+
+
+void maria_ft_boolean_reinit_search(FT_INFO *ftb)
+{
+ _ftb_init_index_search(ftb);
+}
diff --git a/storage/maria/ma_ft_eval.c b/storage/maria/ma_ft_eval.c
new file mode 100644
index 00000000000..5fc67c6c664
--- /dev/null
+++ b/storage/maria/ma_ft_eval.c
@@ -0,0 +1,254 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code
+ added support for long options (my_getopt) 22.5.2002 by Jani Tolonen */
+
+#include "ma_ftdefs.h"
+#include "maria_ft_eval.h"
+#include <stdarg.h>
+#include <my_getopt.h>
+
+static void print_error(int exit_code, const char *fmt,...);
+static void get_options(int argc, char *argv[]);
+static int create_record(char *pos, FILE *file);
+static void usage();
+
+static struct my_option my_long_options[] =
+{
+ {"", 's', "", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'q', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'S', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", '#', "", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'V', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", '?', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'h', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+int main(int argc, char *argv[])
+{
+ MARIA_HA *file;
+ int i,j;
+
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+ bzero((char*)recinfo,sizeof(recinfo));
+
+ maria_init();
+ /* First define 2 columns */
+ recinfo[0].type=FIELD_SKIP_ENDSPACE;
+ recinfo[0].length=docid_length;
+ recinfo[1].type=FIELD_BLOB;
+ recinfo[1].length= 4+portable_sizeof_char_ptr;
+
+ /* Define a key over the first column */
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].block_length= 0; /* Default block length */
+ keyinfo[0].seg[0].type= HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].flag= HA_BLOB_PART;
+ keyinfo[0].seg[0].start=recinfo[0].length;
+ keyinfo[0].seg[0].length=key_length;
+ keyinfo[0].seg[0].null_bit=0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].seg[0].bit_start=4;
+ keyinfo[0].seg[0].language=MY_CHARSET_CURRENT;
+ keyinfo[0].flag = HA_FULLTEXT;
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+ if (maria_create(filename,1,keyinfo,2,recinfo,0,NULL,(MARIA_CREATE_INFO*) 0,0))
+ goto err;
+ if (!(file=maria_open(filename,2,0)))
+ goto err;
+ if (!silent)
+ printf("Initializing stopwords\n");
+ maria_ft_init_stopwords(stopwordlist);
+
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ my_errno=0;
+ i=0;
+ while (create_record(record,df))
+ {
+ error=maria_write(file,record);
+ if (error)
+ printf("I= %2d maria_write: %d errno: %d\n",i,error,my_errno);
+ i++;
+ }
+ fclose(df);
+
+ if (maria_close(file)) goto err;
+ if (!silent)
+ printf("- Reopening file\n");
+ if (!(file=maria_open(filename,2,0))) goto err;
+ if (!silent)
+ printf("- Reading rows with key\n");
+ for (i=1;create_record(record,qf);i++)
+ {
+ FT_DOCLIST *result;
+ double w;
+ int t, err;
+
+ result=maria_ft_nlq_init_search(file,0,blob_record,(uint) strlen(blob_record),1);
+ if (!result)
+ {
+ printf("Query %d failed with errno %3d\n",i,my_errno);
+ goto err;
+ }
+ if (!silent)
+ printf("Query %d. Found: %d.\n",i,result->ndocs);
+ for (j=0;(err=maria_ft_nlq_read_next(result, read_record))==0;j++)
+ {
+ t=uint2korr(read_record);
+ w=maria_ft_nlq_get_relevance(result);
+ printf("%d %.*s %f\n",i,t,read_record+2,w);
+ }
+ if (err != HA_ERR_END_OF_FILE)
+ {
+ printf("maria_ft_read_next %d failed with errno %3d\n",j,my_errno);
+ goto err;
+ }
+ maria_ft_nlq_close_search(result);
+ }
+
+ if (maria_close(file)) goto err;
+ maria_end();
+ my_end(MY_CHECK_ERROR);
+
+ return (0);
+
+ err:
+ printf("got error: %3d when using maria-database\n",my_errno);
+ return 1; /* skip warning */
+
+}
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument)
+{
+ switch (optid) {
+ case 's':
+ if (stopwordlist && stopwordlist != maria_ft_precompiled_stopwords)
+ break;
+ {
+ FILE *f; char s[HA_FT_MAXLEN]; int i=0,n=SWL_INIT;
+
+ if (!(stopwordlist=(const char**) malloc(n*sizeof(char *))))
+ print_error(1,"malloc(%d)",n*sizeof(char *));
+ if (!(f=fopen(argument,"r")))
+ print_error(1,"fopen(%s)",argument);
+ while (!feof(f))
+ {
+ if (!(fgets(s,HA_FT_MAXLEN,f)))
+ print_error(1,"fgets(s,%d,%s)",HA_FT_MAXLEN,argument);
+ if (!(stopwordlist[i++]=strdup(s)))
+ print_error(1,"strdup(%s)",s);
+ if (i >= n)
+ {
+ n+=SWL_PLUS;
+ if (!(stopwordlist=(const char**) realloc((char*) stopwordlist,
+ n*sizeof(char *))))
+ print_error(1,"realloc(%d)",n*sizeof(char *));
+ }
+ }
+ fclose(f);
+ stopwordlist[i]=NULL;
+ break;
+ }
+ case 'q': silent=1; break;
+ case 'S': if (stopwordlist==maria_ft_precompiled_stopwords) stopwordlist=NULL; break;
+ case '#':
+ DBUG_PUSH (argument);
+ break;
+ case 'V':
+ case '?':
+ case 'h':
+ usage();
+ exit(1);
+ }
+ return 0;
+}
+
+
+static void get_options(int argc, char *argv[])
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ if (!(d_file=argv[optind])) print_error(1,"No d_file");
+ if (!(df=fopen(d_file,"r")))
+ print_error(1,"fopen(%s)",d_file);
+ if (!(q_file=argv[optind+1])) print_error(1,"No q_file");
+ if (!(qf=fopen(q_file,"r")))
+ print_error(1,"fopen(%s)",q_file);
+ return;
+} /* get options */
+
+
+static int create_record(char *pos, FILE *file)
+{
+ uint tmp; char *ptr;
+
+ bzero((char *)pos,MAX_REC_LENGTH);
+
+ /* column 1 - VARCHAR */
+ if (!(fgets(pos+2,MAX_REC_LENGTH-32,file)))
+ {
+ if (feof(file))
+ return 0;
+ else
+ print_error(1,"fgets(docid) - 1");
+ }
+ tmp=(uint) strlen(pos+2)-1;
+ int2store(pos,tmp);
+ pos+=recinfo[0].length;
+
+ /* column 2 - BLOB */
+
+ if (!(fgets(blob_record,MAX_BLOB_LENGTH,file)))
+ print_error(1,"fgets(docid) - 2");
+ tmp=(uint) strlen(blob_record);
+ int4store(pos,tmp);
+ ptr=blob_record;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ return 1;
+}
+
+/* VARARGS */
+
+static void print_error(int exit_code, const char *fmt,...)
+{
+ va_list args;
+
+ va_start(args,fmt);
+ fprintf(stderr,"%s: error: ",my_progname);
+ VOID(vfprintf(stderr, fmt, args));
+ VOID(fputc('\n',stderr));
+ fflush(stderr);
+ va_end(args);
+ exit(exit_code);
+}
+
+
+static void usage()
+{
+ printf("%s [options]\n", my_progname);
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
diff --git a/storage/maria/ma_ft_eval.h b/storage/maria/ma_ft_eval.h
new file mode 100644
index 00000000000..481943dfb0b
--- /dev/null
+++ b/storage/maria/ma_ft_eval.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2006 MySQL AB & Sergei A. Golubchik
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+const char **stopwordlist=maria_ft_precompiled_stopwords;
+
+#define MAX_REC_LENGTH 128
+#define MAX_BLOB_LENGTH 60000
+char record[MAX_REC_LENGTH], read_record[MAX_REC_LENGTH+MAX_BLOB_LENGTH];
+char blob_record[MAX_BLOB_LENGTH+20*20];
+
+char *filename= (char*) "EVAL";
+
+int silent=0, error=0;
+
+uint key_length=MAX_BLOB_LENGTH,docid_length=32;
+char *d_file, *q_file;
+FILE *df,*qf;
+
+MARIA_COLUMNDEF recinfo[3];
+MARIA_KEYDEF keyinfo[2];
+HA_KEYSEG keyseg[10];
+
+#define SWL_INIT 500
+#define SWL_PLUS 50
+
+#define MAX_LINE_LENGTH 128
+char line[MAX_LINE_LENGTH];
diff --git a/storage/maria/ma_ft_nlq_search.c b/storage/maria/ma_ft_nlq_search.c
new file mode 100644
index 00000000000..53ff9d5c47d
--- /dev/null
+++ b/storage/maria/ma_ft_nlq_search.c
@@ -0,0 +1,377 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+#define FT_CORE
+#include "ma_ftdefs.h"
+
+/* search with natural language queries */
+
+typedef struct ft_doc_rec
+{
+ my_off_t dpos;
+ double weight;
+} FT_DOC;
+
+struct st_ft_info
+{
+ struct _ft_vft *please;
+ MARIA_HA *info;
+ int ndocs;
+ int curdoc;
+ FT_DOC doc[1];
+};
+
+typedef struct st_all_in_one
+{
+ MARIA_HA *info;
+ uint keynr;
+ CHARSET_INFO *charset;
+ uchar *keybuff;
+ TREE dtree;
+} ALL_IN_ONE;
+
+typedef struct st_ft_superdoc
+{
+ FT_DOC doc;
+ FT_WORD *word_ptr;
+ double tmp_weight;
+} FT_SUPERDOC;
+
+static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)),
+ FT_SUPERDOC *p1, FT_SUPERDOC *p2)
+{
+ if (p1->doc.dpos < p2->doc.dpos)
+ return -1;
+ if (p1->doc.dpos == p2->doc.dpos)
+ return 0;
+ return 1;
+}
+
+static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
+{
+ int subkeys, r;
+ uint doc_cnt;
+ FT_SUPERDOC sdoc, *sptr;
+ TREE_ELEMENT *selem;
+ double gweight=1;
+ MARIA_HA *info= aio->info;
+ uchar *keybuff= (uchar*) aio->keybuff;
+ MARIA_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr;
+ my_off_t key_root=info->s->state.key_root[aio->keynr];
+ uint extra=HA_FT_WLEN+info->s->base.rec_reflength;
+ MARIA_KEY key;
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+ float tmp_weight;
+#else
+#error
+#endif
+ DBUG_ENTER("walk_and_match");
+
+ word->weight=LWS_FOR_QUERY;
+
+ _ma_ft_make_key(info, &key, aio->keynr, keybuff, word, 0);
+ key.data_length-= HA_FT_WLEN;
+ doc_cnt=0;
+
+ /* Skip rows inserted by current inserted */
+ for (r= _ma_search(info, &key, SEARCH_FIND, key_root) ;
+ !r &&
+ (subkeys=ft_sintXkorr(info->last_key.data +
+ info->last_key.data_length +
+ info->last_key.ref_length - extra)) > 0 &&
+ info->cur_row.lastpos >= info->state->data_file_length ;
+ r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, key_root))
+ ;
+
+ info->update|= HA_STATE_AKTIV; /* for _ma_test_if_changed() */
+
+ /* The following should be safe, even if we compare doubles */
+ while (!r && gweight)
+ {
+
+ if (key.data_length &&
+ ha_compare_text(aio->charset,
+ info->last_key.data+1,
+ info->last_key.data_length +
+ info->last_key.ref_length - extra - 1,
+ key.data+1, key.data_length-1, 0, 0))
+ break;
+
+ if (subkeys<0)
+ {
+ if (doc_cnt)
+ DBUG_RETURN(1); /* index is corrupted */
+ /*
+ TODO here: unsafe optimization, should this word
+ be skipped (based on subkeys) ?
+ */
+ keybuff+= key.data_length;
+ keyinfo= &info->s->ft2_keyinfo;
+ key_root= info->cur_row.lastpos;
+ key.data_length= 0;
+ r= _ma_search_first(info, keyinfo, key_root);
+ goto do_skip;
+ }
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+ tmp_weight=*(float*)&subkeys;
+#else
+#error
+#endif
+ /* The following should be safe, even if we compare doubles */
+ if (tmp_weight==0)
+ DBUG_RETURN(doc_cnt); /* stopword, doc_cnt should be 0 */
+
+ sdoc.doc.dpos= info->cur_row.lastpos;
+
+ /* saving document matched into dtree */
+ if (!(selem=tree_insert(&aio->dtree, &sdoc, 0, aio->dtree.custom_arg)))
+ DBUG_RETURN(1);
+
+ sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem);
+
+ if (selem->count==1) /* document's first match */
+ sptr->doc.weight=0;
+ else
+ sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight;
+
+ sptr->word_ptr=word;
+ sptr->tmp_weight=tmp_weight;
+
+ doc_cnt++;
+
+ gweight=word->weight*GWS_IN_USE;
+ if (gweight < 0 || doc_cnt > 2000000)
+ gweight=0;
+
+ if (_ma_test_if_changed(info) == 0)
+ r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, key_root);
+ else
+ r= _ma_search(info, &info->last_key, SEARCH_BIGGER, key_root);
+do_skip:
+ while ((subkeys=ft_sintXkorr(info->last_key.data +
+ info->last_key.data_length +
+ info->last_key.ref_length - extra)) > 0 &&
+ !r && info->cur_row.lastpos >= info->state->data_file_length)
+ r= _ma_search_next(info, &info->last_key, SEARCH_BIGGER, key_root);
+
+ }
+ word->weight=gweight;
+
+ DBUG_RETURN(0);
+}
+
+
+static int walk_and_copy(FT_SUPERDOC *from,
+ uint32 count __attribute__((unused)), FT_DOC **to)
+{
+ DBUG_ENTER("walk_and_copy");
+ from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
+ (*to)->dpos=from->doc.dpos;
+ (*to)->weight=from->doc.weight;
+ (*to)++;
+ DBUG_RETURN(0);
+}
+
+static int walk_and_push(FT_SUPERDOC *from,
+ uint32 count __attribute__((unused)), QUEUE *best)
+{
+ DBUG_ENTER("walk_and_copy");
+ from->doc.weight+=from->tmp_weight*from->word_ptr->weight;
+ set_if_smaller(best->elements, ft_query_expansion_limit-1);
+ queue_insert(best, (uchar *)& from->doc);
+ DBUG_RETURN(0);
+}
+
+
+static int FT_DOC_cmp(void *unused __attribute__((unused)),
+ FT_DOC *a, FT_DOC *b)
+{
+ return sgn(b->weight - a->weight);
+}
+
+
+FT_INFO *maria_ft_init_nlq_search(MARIA_HA *info, uint keynr, uchar *query,
+ uint query_len, uint flags, uchar *record)
+{
+ TREE wtree;
+ ALL_IN_ONE aio;
+ FT_DOC *dptr;
+ FT_INFO *dlist=NULL;
+ MARIA_RECORD_POS saved_lastpos= info->cur_row.lastpos;
+ struct st_mysql_ftparser *parser;
+ MYSQL_FTPARSER_PARAM *ftparser_param;
+ DBUG_ENTER("maria_ft_init_nlq_search");
+
+ /* black magic ON */
+ if ((int) (keynr = _ma_check_index(info,keynr)) < 0)
+ DBUG_RETURN(NULL);
+ if (_ma_readinfo(info,F_RDLCK,1))
+ DBUG_RETURN(NULL);
+ /* black magic OFF */
+
+ aio.info=info;
+ aio.keynr=keynr;
+ aio.charset=info->s->keyinfo[keynr].seg->charset;
+ aio.keybuff= info->lastkey_buff2;
+ parser= info->s->keyinfo[keynr].parser;
+ if (! (ftparser_param= maria_ftparser_call_initializer(info, keynr, 0)))
+ goto err;
+
+ bzero(&wtree,sizeof(wtree));
+
+ init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0,
+ NULL, NULL);
+
+ maria_ft_parse_init(&wtree, aio.charset);
+ ftparser_param->flags= 0;
+ if (maria_ft_parse(&wtree, query, query_len, parser, ftparser_param,
+ &wtree.mem_root))
+ goto err;
+
+ if (tree_walk(&wtree, (tree_walk_action)&walk_and_match, &aio,
+ left_root_right))
+ goto err;
+
+ if (flags & FT_EXPAND && ft_query_expansion_limit)
+ {
+ QUEUE best;
+ init_queue(&best,ft_query_expansion_limit,0,0, (queue_compare) &FT_DOC_cmp,
+ 0);
+ tree_walk(&aio.dtree, (tree_walk_action) &walk_and_push,
+ &best, left_root_right);
+ while (best.elements)
+ {
+ my_off_t docid=((FT_DOC *)queue_remove(& best, 0))->dpos;
+ if (!(*info->read_record)(info, record, docid))
+ {
+ info->update|= HA_STATE_AKTIV;
+ ftparser_param->flags= MYSQL_FTFLAGS_NEED_COPY;
+ if (unlikely(_ma_ft_parse(&wtree, info, keynr, record, ftparser_param,
+ &wtree.mem_root)))
+ {
+ delete_queue(&best);
+ goto err;
+ }
+ }
+ }
+ delete_queue(&best);
+ reset_tree(&aio.dtree);
+ if (tree_walk(&wtree, (tree_walk_action)&walk_and_match, &aio,
+ left_root_right))
+ goto err;
+
+ }
+
+ /*
+ If ndocs == 0, this will not allocate RAM for FT_INFO.doc[],
+ so if ndocs == 0, FT_INFO.doc[] must not be accessed.
+ */
+ dlist=(FT_INFO *)my_malloc(sizeof(FT_INFO)+
+ sizeof(FT_DOC)*
+ (int)(aio.dtree.elements_in_tree-1),
+ MYF(0));
+ if (!dlist)
+ goto err;
+
+ dlist->please= (struct _ft_vft *) & _ma_ft_vft_nlq;
+ dlist->ndocs=aio.dtree.elements_in_tree;
+ dlist->curdoc=-1;
+ dlist->info=aio.info;
+ dptr=dlist->doc;
+
+ tree_walk(&aio.dtree, (tree_walk_action) &walk_and_copy,
+ &dptr, left_root_right);
+
+ if (flags & FT_SORTED)
+ my_qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC),
+ (qsort2_cmp)&FT_DOC_cmp, 0);
+
+err:
+ delete_tree(&aio.dtree);
+ delete_tree(&wtree);
+ info->cur_row.lastpos= saved_lastpos;
+ DBUG_RETURN(dlist);
+}
+
+
+int maria_ft_nlq_read_next(FT_INFO *handler, char *record)
+{
+ MARIA_HA *info= (MARIA_HA *) handler->info;
+
+ if (++handler->curdoc >= handler->ndocs)
+ {
+ --handler->curdoc;
+ return HA_ERR_END_OF_FILE;
+ }
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ info->cur_row.lastpos= handler->doc[handler->curdoc].dpos;
+ if (!(*info->read_record)(info, (uchar *) record, info->cur_row.lastpos))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ return 0;
+ }
+ return my_errno;
+}
+
+
+float maria_ft_nlq_find_relevance(FT_INFO *handler,
+ uchar *record __attribute__((unused)),
+ uint length __attribute__((unused)))
+{
+ int a,b,c;
+ FT_DOC *docs=handler->doc;
+ MARIA_RECORD_POS docid= handler->info->cur_row.lastpos;
+
+ if (docid == HA_POS_ERROR)
+ return -5.0;
+
+ /* Assuming docs[] is sorted by dpos... */
+
+ for (a=0, b=handler->ndocs, c=(a+b)/2; b-a>1; c=(a+b)/2)
+ {
+ if (docs[c].dpos > docid)
+ b=c;
+ else
+ a=c;
+ }
+ /* bounds check to avoid accessing unallocated handler->doc */
+ if (a < handler->ndocs && docs[a].dpos == docid)
+ return (float) docs[a].weight;
+ else
+ return 0.0;
+}
+
+
+void maria_ft_nlq_close_search(FT_INFO *handler)
+{
+ my_free((uchar*)handler,MYF(0));
+}
+
+
+float maria_ft_nlq_get_relevance(FT_INFO *handler)
+{
+ return (float) handler->doc[handler->curdoc].weight;
+}
+
+
+void maria_ft_nlq_reinit_search(FT_INFO *handler)
+{
+ handler->curdoc=-1;
+}
+
diff --git a/storage/maria/ma_ft_parser.c b/storage/maria/ma_ft_parser.c
new file mode 100644
index 00000000000..25704f1af5a
--- /dev/null
+++ b/storage/maria/ma_ft_parser.c
@@ -0,0 +1,433 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+#include "ma_ftdefs.h"
+
+typedef struct st_maria_ft_docstat {
+ FT_WORD *list;
+ uint uniq;
+ double sum;
+} FT_DOCSTAT;
+
+
+typedef struct st_my_maria_ft_parser_param
+{
+ TREE *wtree;
+ MEM_ROOT *mem_root;
+} MY_FT_PARSER_PARAM;
+
+
+static int FT_WORD_cmp(CHARSET_INFO* cs, FT_WORD *w1, FT_WORD *w2)
+{
+ return ha_compare_text(cs, (uchar*) w1->pos, w1->len,
+ (uchar*) w2->pos, w2->len, 0, 0);
+}
+
+static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat)
+{
+ word->weight=LWS_IN_USE;
+ docstat->sum+=word->weight;
+ memcpy_fixed((docstat->list)++,word,sizeof(FT_WORD));
+ return 0;
+}
+
+/* transforms tree of words into the array, applying normalization */
+
+FT_WORD * maria_ft_linearize(TREE *wtree, MEM_ROOT *mem_root)
+{
+ FT_WORD *wlist,*p;
+ FT_DOCSTAT docstat;
+ DBUG_ENTER("maria_ft_linearize");
+
+ if ((wlist=(FT_WORD *) alloc_root(mem_root, sizeof(FT_WORD)*
+ (1+wtree->elements_in_tree))))
+ {
+ docstat.list=wlist;
+ docstat.uniq=wtree->elements_in_tree;
+ docstat.sum=0;
+ tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right);
+ }
+ delete_tree(wtree);
+ if (!wlist)
+ DBUG_RETURN(NULL);
+
+ docstat.list->pos=NULL;
+
+ for (p=wlist;p->pos;p++)
+ {
+ p->weight=PRENORM_IN_USE;
+ }
+
+ for (p=wlist;p->pos;p++)
+ {
+ p->weight/=NORM_IN_USE;
+ }
+
+ DBUG_RETURN(wlist);
+}
+
+my_bool maria_ft_boolean_check_syntax_string(const uchar *str)
+{
+ uint i, j;
+
+ if (!str ||
+ (strlen((const char *) str) + 1 != sizeof(ft_boolean_syntax)) ||
+ (str[0] != ' ' && str[1] != ' '))
+ return 1;
+ for (i=0; i<sizeof(ft_boolean_syntax); i++)
+ {
+ /* limiting to 7-bit ascii only */
+ if ((unsigned char)(str[i]) > 127 ||
+ my_isalnum(default_charset_info, str[i]))
+ return 1;
+ for (j=0; j<i; j++)
+ if (str[i] == str[j] && (i != 11 || j != 10))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ RETURN VALUE
+ 0 - eof
+ 1 - word found
+ 2 - left bracket
+ 3 - right bracket
+ 4 - stopword found
+*/
+uchar maria_ft_get_word(CHARSET_INFO *cs, uchar **start, uchar *end,
+ FT_WORD *word, MYSQL_FTPARSER_BOOLEAN_INFO *param)
+{
+ uchar *doc=*start;
+ int ctype;
+ uint mwc, length;
+ int mbl;
+
+ param->yesno=(FTB_YES==' ') ? 1 : (param->quot != 0);
+ param->weight_adjust= param->wasign= 0;
+ param->type= FT_TOKEN_EOF;
+
+ while (doc<end)
+ {
+ for (; doc < end; doc+= (mbl > 0 ? mbl : (mbl < 0 ? -mbl : 1)))
+ {
+ mbl= cs->cset->ctype(cs, &ctype, (uchar*)doc, (uchar*)end);
+ if (true_word_char(ctype, *doc))
+ break;
+ if (*doc == FTB_RQUOT && param->quot)
+ {
+ param->quot= (char *) doc;
+ *start=doc+1;
+ param->type= FT_TOKEN_RIGHT_PAREN;
+ goto ret;
+ }
+ if (!param->quot)
+ {
+ if (*doc == FTB_LBR || *doc == FTB_RBR || *doc == FTB_LQUOT)
+ {
+ /* param->prev=' '; */
+ *start=doc+1;
+ if (*doc == FTB_LQUOT)
+ param->quot= (char *) *start;
+ param->type= (*doc == FTB_RBR ? FT_TOKEN_RIGHT_PAREN : FT_TOKEN_LEFT_PAREN);
+ goto ret;
+ }
+ if (param->prev == ' ')
+ {
+ if (*doc == FTB_YES ) { param->yesno=+1; continue; } else
+ if (*doc == FTB_EGAL) { param->yesno= 0; continue; } else
+ if (*doc == FTB_NO ) { param->yesno=-1; continue; } else
+ if (*doc == FTB_INC ) { param->weight_adjust++; continue; } else
+ if (*doc == FTB_DEC ) { param->weight_adjust--; continue; } else
+ if (*doc == FTB_NEG ) { param->wasign= !param->wasign; continue; }
+ }
+ }
+ param->prev=*doc;
+ param->yesno=(FTB_YES==' ') ? 1 : (param->quot != 0);
+ param->weight_adjust= param->wasign= 0;
+ }
+
+ mwc=length=0;
+ for (word->pos= doc; doc < end; length++,
+ doc+= (mbl > 0 ? mbl : (mbl < 0 ? -mbl : 1)))
+ {
+ mbl= cs->cset->ctype(cs, &ctype, (uchar*)doc, (uchar*)end);
+ if (true_word_char(ctype, *doc))
+ mwc=0;
+ else if (!misc_word_char(*doc) || mwc)
+ break;
+ else
+ mwc++;
+ }
+ param->prev='A'; /* be sure *prev is true_word_char */
+ word->len= (uint)(doc-word->pos) - mwc;
+ if ((param->trunc=(doc<end && *doc == FTB_TRUNC)))
+ doc++;
+
+ if (((length >= ft_min_word_len && !is_stopword((char *) word->pos,
+ word->len))
+ || param->trunc) && length < ft_max_word_len)
+ {
+ *start=doc;
+ param->type= FT_TOKEN_WORD;
+ goto ret;
+ }
+ else if (length) /* make sure length > 0 (if start contains spaces only) */
+ {
+ *start= doc;
+ param->type= FT_TOKEN_STOPWORD;
+ goto ret;
+ }
+ }
+ if (param->quot)
+ {
+ param->quot= (char *)(*start= doc);
+ param->type= 3; /* FT_RBR */
+ goto ret;
+ }
+ret:
+ return param->type;
+}
+
+uchar maria_ft_simple_get_word(CHARSET_INFO *cs, uchar **start,
+ const uchar *end, FT_WORD *word,
+ my_bool skip_stopwords)
+{
+ uchar *doc= *start;
+ uint mwc, length;
+ int ctype, mbl;
+ DBUG_ENTER("maria_ft_simple_get_word");
+
+ do
+ {
+ for (;; doc+= (mbl > 0 ? mbl : (mbl < 0 ? -mbl : 1)))
+ {
+ if (doc >= end)
+ DBUG_RETURN(0);
+ mbl= cs->cset->ctype(cs, &ctype, doc, end);
+ if (true_word_char(ctype, *doc))
+ break;
+ }
+
+ mwc= length= 0;
+ for (word->pos= doc; doc < end; length++,
+ doc+= (mbl > 0 ? mbl : (mbl < 0 ? -mbl : 1)))
+ {
+ mbl= cs->cset->ctype(cs, &ctype, doc, end);
+ if (true_word_char(ctype, *doc))
+ mwc= 0;
+ else if (!misc_word_char(*doc) || mwc)
+ break;
+ else
+ mwc++;
+ }
+
+ word->len= (uint)(doc-word->pos) - mwc;
+
+ if (skip_stopwords == FALSE ||
+ (length >= ft_min_word_len && length < ft_max_word_len &&
+ !is_stopword((char *) word->pos, word->len)))
+ {
+ *start= doc;
+ DBUG_RETURN(1);
+ }
+ } while (doc < end);
+ DBUG_RETURN(0);
+}
+
+void maria_ft_parse_init(TREE *wtree, CHARSET_INFO *cs)
+{
+ DBUG_ENTER("maria_ft_parse_init");
+ if (!is_tree_inited(wtree))
+ init_tree(wtree,0,0,sizeof(FT_WORD),(qsort_cmp2)&FT_WORD_cmp,0,NULL, cs);
+ DBUG_VOID_RETURN;
+}
+
+
+static int maria_ft_add_word(MYSQL_FTPARSER_PARAM *param,
+ char *word, int word_len,
+ MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info __attribute__((unused)))
+{
+ TREE *wtree;
+ FT_WORD w;
+ MY_FT_PARSER_PARAM *ft_param=param->mysql_ftparam;
+ DBUG_ENTER("maria_ft_add_word");
+ wtree= ft_param->wtree;
+ if (param->flags & MYSQL_FTFLAGS_NEED_COPY)
+ {
+ uchar *ptr;
+ DBUG_ASSERT(wtree->with_delete == 0);
+ ptr= (uchar *)alloc_root(ft_param->mem_root, word_len);
+ memcpy(ptr, word, word_len);
+ w.pos= ptr;
+ }
+ else
+ w.pos= (uchar *) word;
+ w.len= word_len;
+ if (!tree_insert(wtree, &w, 0, wtree->custom_arg))
+ {
+ delete_tree(wtree);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+static int maria_ft_parse_internal(MYSQL_FTPARSER_PARAM *param,
+ char *doc_arg, int doc_len)
+{
+ uchar *doc= (uchar*) doc_arg;
+ uchar *end= doc + doc_len;
+ MY_FT_PARSER_PARAM *ft_param=param->mysql_ftparam;
+ TREE *wtree= ft_param->wtree;
+ FT_WORD w;
+ DBUG_ENTER("maria_ft_parse_internal");
+
+ while (maria_ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE))
+ if (param->mysql_add_word(param, (char *) w.pos, w.len, 0))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+int maria_ft_parse(TREE *wtree, uchar *doc, int doclen,
+ struct st_mysql_ftparser *parser,
+ MYSQL_FTPARSER_PARAM *param, MEM_ROOT *mem_root)
+{
+ MY_FT_PARSER_PARAM my_param;
+ DBUG_ENTER("maria_ft_parse");
+ DBUG_ASSERT(parser);
+ my_param.wtree= wtree;
+ my_param.mem_root= mem_root;
+
+ param->mysql_parse= maria_ft_parse_internal;
+ param->mysql_add_word= maria_ft_add_word;
+ param->mysql_ftparam= &my_param;
+ param->cs= wtree->custom_arg;
+ param->doc= (char *) doc;
+ param->length= doclen;
+ param->mode= MYSQL_FTPARSER_SIMPLE_MODE;
+ DBUG_RETURN(parser->parse(param));
+}
+
+
+#define MAX_PARAM_NR 2
+MYSQL_FTPARSER_PARAM *maria_ftparser_call_initializer(MARIA_HA *info,
+ uint keynr, uint paramnr)
+{
+ uint32 ftparser_nr;
+ struct st_mysql_ftparser *parser;
+ if (! info->ftparser_param)
+ {
+ /* info->ftparser_param can not be zero after the initialization,
+ because it always includes built-in fulltext parser. And built-in
+ parser can be called even if the table has no fulltext indexes and
+ no varchar/text fields. */
+ if (! info->s->ftparsers)
+ {
+ /* It's ok that modification to shared structure is done w/o mutex
+ locks, because all threads would set the same variables to the
+ same values. */
+ uint i, j, keys= info->s->state.header.keys, ftparsers= 1;
+ for (i= 0; i < keys; i++)
+ {
+ MARIA_KEYDEF *keyinfo= &info->s->keyinfo[i];
+ if (keyinfo->flag & HA_FULLTEXT)
+ {
+ for (j= 0;; j++)
+ {
+ if (j == i)
+ {
+ keyinfo->ftparser_nr= ftparsers++;
+ break;
+ }
+ if (info->s->keyinfo[j].flag & HA_FULLTEXT &&
+ keyinfo->parser == info->s->keyinfo[j].parser)
+ {
+ keyinfo->ftparser_nr= info->s->keyinfo[j].ftparser_nr;
+ break;
+ }
+ }
+ }
+ }
+ info->s->ftparsers= ftparsers;
+ }
+ /*
+ We have to allocate two MYSQL_FTPARSER_PARAM structures per plugin
+ because in a boolean search a parser is called recursively
+ ftb_find_relevance* calls ftb_check_phrase*
+ (MAX_PARAM_NR=2)
+ */
+ info->ftparser_param= (MYSQL_FTPARSER_PARAM *)
+ my_malloc(MAX_PARAM_NR * sizeof(MYSQL_FTPARSER_PARAM) *
+ info->s->ftparsers, MYF(MY_WME|MY_ZEROFILL));
+ init_alloc_root(&info->ft_memroot, FTPARSER_MEMROOT_ALLOC_SIZE, 0);
+ if (! info->ftparser_param)
+ return 0;
+ }
+ if (keynr == NO_SUCH_KEY)
+ {
+ ftparser_nr= 0;
+ parser= &ft_default_parser;
+ }
+ else
+ {
+ ftparser_nr= info->s->keyinfo[keynr].ftparser_nr;
+ parser= info->s->keyinfo[keynr].parser;
+ }
+ DBUG_ASSERT(paramnr < MAX_PARAM_NR);
+ ftparser_nr= ftparser_nr*MAX_PARAM_NR + paramnr;
+ if (! info->ftparser_param[ftparser_nr].mysql_add_word)
+ {
+ /* Note, that mysql_add_word is used here as a flag:
+ mysql_add_word == 0 - parser is not initialized
+ mysql_add_word != 0 - parser is initialized, or no
+ initialization needed. */
+ info->ftparser_param[ftparser_nr].mysql_add_word=
+ (int (*)(struct st_mysql_ftparser_param *, char *, int,
+ MYSQL_FTPARSER_BOOLEAN_INFO *)) 1;
+ if (parser->init && parser->init(&info->ftparser_param[ftparser_nr]))
+ return 0;
+ }
+ return &info->ftparser_param[ftparser_nr];
+}
+
+
+void maria_ftparser_call_deinitializer(MARIA_HA *info)
+{
+ uint i, j, keys= info->s->state.header.keys;
+ free_root(&info->ft_memroot, MYF(0));
+ if (! info->ftparser_param)
+ return;
+ for (i= 0; i < keys; i++)
+ {
+ MARIA_KEYDEF *keyinfo= &info->s->keyinfo[i];
+ for (j=0; j < MAX_PARAM_NR; j++)
+ {
+ MYSQL_FTPARSER_PARAM *ftparser_param=
+ &info->ftparser_param[keyinfo->ftparser_nr*MAX_PARAM_NR + j];
+ if (keyinfo->flag & HA_FULLTEXT && ftparser_param->mysql_add_word)
+ {
+ if (keyinfo->parser->deinit)
+ keyinfo->parser->deinit(ftparser_param);
+ ftparser_param->mysql_add_word= 0;
+ }
+ else
+ break;
+ }
+ }
+}
diff --git a/storage/maria/ma_ft_stem.c b/storage/maria/ma_ft_stem.c
new file mode 100644
index 00000000000..06fc0b2df6c
--- /dev/null
+++ b/storage/maria/ma_ft_stem.c
@@ -0,0 +1,18 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/* mulitingual stem */
diff --git a/storage/maria/ma_ft_test1.c b/storage/maria/ma_ft_test1.c
new file mode 100644
index 00000000000..4c98e766234
--- /dev/null
+++ b/storage/maria/ma_ft_test1.c
@@ -0,0 +1,317 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code
+ added support for long options (my_getopt) 22.5.2002 by Jani Tolonen */
+
+#include "ma_ftdefs.h"
+#include "maria_ft_test1.h"
+#include <my_getopt.h>
+
+static int key_field=FIELD_VARCHAR,extra_field=FIELD_SKIP_ENDSPACE;
+static uint key_length=200,extra_length=50;
+static int key_type=HA_KEYTYPE_TEXT;
+static int verbose=0,silent=0,skip_update=0,
+ no_keys=0,no_stopwords=0,no_search=0,no_fulltext=0;
+static int create_flag=0,error=0;
+
+#define MAX_REC_LENGTH 300
+static char record[MAX_REC_LENGTH],read_record[MAX_REC_LENGTH];
+
+static int run_test(const char *filename);
+static void get_options(int argc, char *argv[]);
+static void create_record(char *, int);
+static void usage();
+
+static struct my_option my_long_options[] =
+{
+ {"", 'v', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", '?', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'h', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'V', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'v', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 's', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'N', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'S', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'K', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'F', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", 'U', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"", '#', "", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+int main(int argc, char *argv[])
+{
+ MY_INIT(argv[0]);
+
+ get_options(argc,argv);
+ maria_init();
+
+ exit(run_test("FT1"));
+}
+
+static MARIA_COLUMNDEF recinfo[3];
+static MARIA_KEYDEF keyinfo[2];
+static HA_KEYSEG keyseg[10];
+
+static int run_test(const char *filename)
+{
+ MARIA_HA *file;
+ int i,j;
+ my_off_t pos;
+
+ bzero((char*) recinfo,sizeof(recinfo));
+
+ /* First define 2 columns */
+ recinfo[0].type=extra_field;
+ recinfo[0].length= (extra_field == FIELD_BLOB ? 4 + portable_sizeof_char_ptr :
+ extra_length);
+ if (extra_field == FIELD_VARCHAR)
+ recinfo[0].length+= HA_VARCHAR_PACKLENGTH(extra_length);
+ recinfo[1].type=key_field;
+ recinfo[1].length= (key_field == FIELD_BLOB ? 4+portable_sizeof_char_ptr :
+ key_length);
+ if (key_field == FIELD_VARCHAR)
+ recinfo[1].length+= HA_VARCHAR_PACKLENGTH(key_length);
+
+ /* Define a key over the first column */
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].block_length= 0; /* Default block length */
+ keyinfo[0].seg[0].type= key_type;
+ keyinfo[0].seg[0].flag= (key_field == FIELD_BLOB) ? HA_BLOB_PART:
+ (key_field == FIELD_VARCHAR) ? HA_VAR_LENGTH_PART:0;
+ keyinfo[0].seg[0].start=recinfo[0].length;
+ keyinfo[0].seg[0].length=key_length;
+ keyinfo[0].seg[0].null_bit= 0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].seg[0].language= default_charset_info->number;
+ keyinfo[0].flag = (no_fulltext?HA_PACK_KEY:HA_FULLTEXT);
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+ if (maria_create(filename,(no_keys?0:1),keyinfo,2,recinfo,0,NULL,
+ (MARIA_CREATE_INFO*) 0, create_flag))
+ goto err;
+ if (!(file=maria_open(filename,2,0)))
+ goto err;
+
+ if (!silent)
+ printf("- %s stopwords\n",no_stopwords?"Skipping":"Initializing");
+ maria_ft_init_stopwords(no_stopwords?NULL:maria_ft_precompiled_stopwords);
+
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ my_errno=0;
+ for (i=NUPD ; i<NDATAS; i++ )
+ {
+ create_record(record,i);
+ error=maria_write(file,record);
+ if (verbose || error)
+ printf("I= %2d maria_write: %d errno: %d, record: %s\n",
+ i,error,my_errno,data[i].f0);
+ }
+
+ if (!skip_update)
+ {
+ if (!silent)
+ printf("- Updating rows\n");
+
+ /* Read through all rows and update them */
+ pos=(ha_rows) 0;
+ i=0;
+ while ((error=maria_rrnd(file,read_record,pos)) == 0)
+ {
+ create_record(record,NUPD-i-1);
+ if (maria_update(file,read_record,record))
+ {
+ printf("Can't update row: %.*s, error: %d\n",
+ keyinfo[0].seg[0].length,record,my_errno);
+ }
+ if(++i == NUPD) break;
+ pos=HA_OFFSET_ERROR;
+ }
+ if (i != NUPD)
+ printf("Found %d of %d rows\n", i,NUPD);
+ }
+
+ if (maria_close(file)) goto err;
+ if(no_search) return 0;
+ if (!silent)
+ printf("- Reopening file\n");
+ if (!(file=maria_open(filename,2,0))) goto err;
+ if (!silent)
+ printf("- Reading rows with key\n");
+ for (i=0 ; i < NQUERIES ; i++)
+ {
+ FT_DOCLIST *result;
+ result=maria_ft_nlq_init_search(file,0,(char*) query[i],strlen(query[i]),1);
+ if(!result)
+ {
+ printf("Query %d: `%s' failed with errno %3d\n",i,query[i],my_errno);
+ continue;
+ }
+ printf("Query %d: `%s'. Found: %d. Top five documents:\n",
+ i,query[i],result->ndocs);
+ for (j=0;j<5;j++)
+ {
+ double w; int err;
+ err= maria_ft_nlq_read_next(result, read_record);
+ if (err==HA_ERR_END_OF_FILE)
+ {
+ printf("No more matches!\n");
+ break;
+ }
+ else if (err)
+ {
+ printf("maria_ft_read_next %d failed with errno %3d\n",j,my_errno);
+ break;
+ }
+ w=maria_ft_nlq_get_relevance(result);
+ if (key_field == FIELD_VARCHAR)
+ {
+ uint l;
+ char *p;
+ p=recinfo[0].length+read_record;
+ l=uint2korr(p);
+ printf("%10.7f: %.*s\n",w,(int) l,p+2);
+ }
+ else
+ printf("%10.7f: %.*s\n",w,recinfo[1].length,
+ recinfo[0].length+read_record);
+ }
+ maria_ft_nlq_close_search(result);
+ }
+
+ if (maria_close(file)) goto err;
+ maria_end();
+ my_end(MY_CHECK_ERROR);
+
+ return (0);
+err:
+ printf("got error: %3d when using maria-database\n",my_errno);
+ return 1; /* skip warning */
+}
+
+static char blob_key[MAX_REC_LENGTH];
+/* static char blob_record[MAX_REC_LENGTH+20*20]; */
+
+void create_record(char *pos, int n)
+{
+ bzero((char*) pos,MAX_REC_LENGTH);
+ if (recinfo[0].type == FIELD_BLOB)
+ {
+ uint tmp;
+ char *ptr;
+ strnmov(blob_key,data[n].f0,keyinfo[0].seg[0].length);
+ tmp=strlen(blob_key);
+ int4store(pos,tmp);
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ pos+=recinfo[0].length;
+ }
+ else if (recinfo[0].type == FIELD_VARCHAR)
+ {
+ uint tmp;
+ /* -1 is here because pack_length is stored in seg->length */
+ uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1);
+ strnmov(pos+pack_length,data[n].f0,keyinfo[0].seg[0].length);
+ tmp=strlen(pos+pack_length);
+ if (pack_length == 1)
+ *pos= (char) tmp;
+ else
+ int2store(pos,tmp);
+ pos+=recinfo[0].length;
+ }
+ else
+ {
+ strnmov(pos,data[n].f0,keyinfo[0].seg[0].length);
+ pos+=recinfo[0].length;
+ }
+ if (recinfo[1].type == FIELD_BLOB)
+ {
+ uint tmp;
+ char *ptr;
+ strnmov(blob_key,data[n].f2,keyinfo[0].seg[0].length);
+ tmp=strlen(blob_key);
+ int4store(pos,tmp);
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ pos+=recinfo[1].length;
+ }
+ else if (recinfo[1].type == FIELD_VARCHAR)
+ {
+ uint tmp;
+ /* -1 is here because pack_length is stored in seg->length */
+ uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1);
+ strnmov(pos+pack_length,data[n].f2,keyinfo[0].seg[0].length);
+ tmp=strlen(pos+1);
+ if (pack_length == 1)
+ *pos= (char) tmp;
+ else
+ int2store(pos,tmp);
+ pos+=recinfo[1].length;
+ }
+ else
+ {
+ strnmov(pos,data[n].f2,keyinfo[0].seg[0].length);
+ pos+=recinfo[1].length;
+ }
+}
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument)
+{
+ switch(optid) {
+ case 'v': verbose=1; break;
+ case 's': silent=1; break;
+ case 'F': no_fulltext=1; no_search=1;
+ case 'U': skip_update=1; break;
+ case 'K': no_keys=no_search=1; break;
+ case 'N': no_search=1; break;
+ case 'S': no_stopwords=1; break;
+ case '#':
+ DBUG_PUSH (argument);
+ break;
+ case 'V':
+ case '?':
+ case 'h':
+ usage();
+ exit(1);
+ }
+ return 0;
+}
+
+/* Read options */
+
+static void get_options(int argc,char *argv[])
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+ exit(ho_error);
+ return;
+} /* get options */
+
+
+static void usage()
+{
+ printf("%s [options]\n", my_progname);
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
diff --git a/storage/maria/ma_ft_test1.h b/storage/maria/ma_ft_test1.h
new file mode 100644
index 00000000000..5883c42f5c5
--- /dev/null
+++ b/storage/maria/ma_ft_test1.h
@@ -0,0 +1,420 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+#define NUPD 20
+#define NDATAS 389
+struct { const char *f0, *f2; } data[NDATAS] = {
+ {"1", "General Information about MySQL"},
+ {"1.1", "What is MySQL?"},
+ {"1.2", "About this manual"},
+ {"1.3", "History of MySQL"},
+ {"1.4", "The main features of MySQL"},
+ {"1.5", "General SQL information and tutorials"},
+ {"1.6", "Useful MySQL-related links"},
+ {"1.7", "What are stored procedures and triggers and so on?"},
+ {"2", "MySQL mailing lists and how to ask questions/give error (bug) reports"},
+ {"2.1", "Subscribing to/un-subscribing from the MySQL mailing list"},
+ {"2.2", "Asking questions or reporting bugs"},
+ {"2.3", "I think I have found a bug. What information do you need to help me?"},
+ {"2.3.1", "MySQL keeps crashing"},
+ {"2.4", "Guidelines for answering questions on the mailing list"},
+ {"3", "Licensing or When do I have/want to pay for MySQL?"},
+ {"3.1", "How much does MySQL cost?"},
+ {"3.2", "How do I get commercial support?"},
+ {"3.2.1", "Types of commercial support"},
+ {"3.2.1.1", "Basic email support"},
+ {"3.2.1.2", "Extended email support"},
+/*------------------------------- NUPD=20 -------------------------------*/
+ {"3.2.1.3", "Asking: Login support"},
+ {"3.2.1.4", "Extended login support"},
+ {"3.3", "How do I pay for licenses/support?"},
+ {"3.4", "Who do I contact when I want more information about licensing/support?"},
+ {"3.5", "What Copyright does MySQL use?"},
+ {"3.6", "When may I distribute MySQL commercially without a fee?"},
+ {"3.7", "I want to sell a product that can be configured to use MySQL"},
+ {"3.8", "I am running a commercial web server using MySQL"},
+ {"3.9", "Do I need a license to sell commercial Perl/tcl/PHP/Web+ etc applications?"},
+ {"3.10", "Possible future changes in the licensing"},
+ {"4", "Compiling and installing MySQL"},
+ {"4.1", "How do I get MySQL?"},
+ {"4.2", "Which MySQL version should I use?"},
+ {"4.3", "How/when will you release updates?"},
+ {"4.4", "What operating systems does MySQL support?"},
+ {"4.5", "Compiling MySQL from source code"},
+ {"4.5.1", "Quick installation overview"},
+ {"4.5.2", "Usual configure switches"},
+ {"4.5.3", "Applying a patch"},
+ {"4.6", "Problems compiling?"},
+ {"4.7", "General compilation notes"},
+ {"4.8", "MIT-pthreads notes (FreeBSD)"},
+ {"4.9", "Perl installation comments"},
+ {"4.10", "Special things to consider for some machine/OS combinations"},
+ {"4.10.1", "Solaris notes"},
+ {"4.10.2", "SunOS 4 notes"},
+ {"4.10.3", "Linux notes for all versions"},
+ {"4.10.3.1", "Linux-x86 notes"},
+ {"4.10.3.2", "RedHat 5.0"},
+ {"4.10.3.3", "RedHat 5.1"},
+ {"4.10.3.4", "Linux-Sparc notes"},
+ {"4.10.3.5", "Linux-Alpha notes"},
+ {"4.10.3.6", "MkLinux notes"},
+ {"4.10.4", "Alpha-DEC-Unix notes"},
+ {"4.10.5", "Alpha-DEC-OSF1 notes"},
+ {"4.10.6", "SGI-IRIX notes"},
+ {"4.10.7", "FreeBSD notes"},
+ {"4.10.7.1", "FreeBSD-3.0 notes"},
+ {"4.10.8", "BSD/OS 2.# notes"},
+ {"4.10.8.1", "BSD/OS 3.# notes"},
+ {"4.10.9", "SCO notes"},
+ {"4.10.10", "SCO Unixware 7.0 notes"},
+ {"4.10.11", "IBM-AIX notes"},
+ {"4.10.12", "HP-UX notes"},
+ {"4.11", "TcX binaries"},
+ {"4.12", "Win32 notes"},
+ {"4.13", "Installation instructions for MySQL binary releases"},
+ {"4.13.1", "How to get MySQL Perl support working"},
+ {"4.13.2", "Linux notes"},
+ {"4.13.3", "HP-UX notes"},
+ {"4.13.4", "Linking client libraries"},
+ {"4.14", "Problems running mysql_install_db"},
+ {"4.15", "Problems starting MySQL"},
+ {"4.16", "Automatic start/stop of MySQL"},
+ {"4.17", "Option files"},
+ {"5", "How standards-compatible is MySQL?"},
+ {"5.1", "What extensions has MySQL to ANSI SQL92?"},
+ {"5.2", "What functionality is missing in MySQL?"},
+ {"5.2.1", "Sub-selects"},
+ {"5.2.2", "SELECT INTO TABLE"},
+ {"5.2.3", "Transactions"},
+ {"5.2.4", "Triggers"},
+ {"5.2.5", "Foreign Keys"},
+ {"5.2.5.1", "Some reasons NOT to use FOREIGN KEYS"},
+ {"5.2.6", "Views"},
+ {"5.2.7", "-- as start of a comment"},
+ {"5.3", "What standards does MySQL follow?"},
+ {"5.4", "What functions exist only for compatibility?"},
+ {"5.5", "Limitations of BLOB and TEXT types"},
+ {"5.6", "How to cope without COMMIT-ROLLBACK"},
+ {"6", "The MySQL access privilege system"},
+ {"6.1", "What the privilege system does"},
+ {"6.2", "Connecting to the MySQL server"},
+ {"6.2.1", "Keeping your password secure"},
+ {"6.3", "Privileges provided by MySQL"},
+ {"6.4", "How the privilege system works"},
+ {"6.5", "The privilege tables"},
+ {"6.6", "Setting up the initial MySQL privileges"},
+ {"6.7", "Adding new user privileges to MySQL"},
+ {"6.8", "An example permission setup"},
+ {"6.9", "Causes of Access denied errors"},
+ {"6.10", "How to make MySQL secure against crackers"},
+ {"7", "MySQL language reference"},
+ {"7.1", "Literals: how to write strings and numbers"},
+ {"7.1.1", "Strings"},
+ {"7.1.2", "Numbers"},
+ {"7.1.3", "NULL values"},
+ {"7.1.4", "Database, table, index, column and alias names"},
+ {"7.1.4.1", "Case sensitivity in names"},
+ {"7.2", "Column types"},
+ {"7.2.1", "Column type storage requirements"},
+ {"7.2.5", "Numeric types"},
+ {"7.2.6", "Date and time types"},
+ {"7.2.6.1", "The DATE type"},
+ {"7.2.6.2", "The TIME type"},
+ {"7.2.6.3", "The DATETIME type"},
+ {"7.2.6.4", "The TIMESTAMP type"},
+ {"7.2.6.5", "The YEAR type"},
+ {"7.2.6.6", "Miscellaneous date and time properties"},
+ {"7.2.7", "String types"},
+ {"7.2.7.1", "The CHAR and VARCHAR types"},
+ {"7.2.7.2", "The BLOB and TEXT types"},
+ {"7.2.7.3", "The ENUM type"},
+ {"7.2.7.4", "The SET type"},
+ {"7.2.8", "Choosing the right type for a column"},
+ {"7.2.9", "Column indexes"},
+ {"7.2.10", "Multiple-column indexes"},
+ {"7.2.11", "Using column types from other database engines"},
+ {"7.3", "Functions for use in SELECT and WHERE clauses"},
+ {"7.3.1", "Grouping functions"},
+ {"7.3.2", "Normal arithmetic operations"},
+ {"7.3.3", "Bit functions"},
+ {"7.3.4", "Logical operations"},
+ {"7.3.5", "Comparison operators"},
+ {"7.3.6", "String comparison functions"},
+ {"7.3.7", "Control flow functions"},
+ {"7.3.8", "Mathematical functions"},
+ {"7.3.9", "String functions"},
+ {"7.3.10", "Date and time functions"},
+ {"7.3.11", "Miscellaneous functions"},
+ {"7.3.12", "Functions for use with GROUP BY clauses"},
+ {"7.4", "CREATE DATABASE syntax"},
+ {"7.5", "DROP DATABASE syntax"},
+ {"7.6", "CREATE TABLE syntax"},
+ {"7.7", "ALTER TABLE syntax"},
+ {"7.8", "OPTIMIZE TABLE syntax"},
+ {"7.9", "DROP TABLE syntax"},
+ {"7.10", "DELETE syntax"},
+ {"7.11", "SELECT syntax"},
+ {"7.12", "JOIN syntax"},
+ {"7.13", "INSERT syntax"},
+ {"7.14", "REPLACE syntax"},
+ {"7.15", "LOAD DATA INFILE syntax"},
+ {"7.16", "UPDATE syntax"},
+ {"7.17", "USE syntax"},
+ {"7.18", "SHOW syntax (Get information about tables, columns...)"},
+ {"7.19", "EXPLAIN syntax (Get information about a SELECT)"},
+ {"7.20", "DESCRIBE syntax (Get information about columns)"},
+ {"7.21", "LOCK TABLES/UNLOCK TABLES syntax"},
+ {"7.22", "SET OPTION syntax"},
+ {"7.23", "GRANT syntax (Compatibility function)"},
+ {"7.24", "CREATE INDEX syntax (Compatibility function)"},
+ {"7.25", "DROP INDEX syntax (Compatibility function)"},
+ {"7.26", "Comment syntax"},
+ {"7.27", "CREATE FUNCTION/DROP FUNCTION syntax"},
+ {"7.28", "Is MySQL picky about reserved words?"},
+ {"8", "Example SQL queries"},
+ {"8.1", "Queries from twin project"},
+ {"8.1.1", "Find all non-distributed twins"},
+ {"8.1.2", "Show a table on twin pair status"},
+ {"9", "How safe/stable is MySQL?"},
+ {"9.1", "How stable is MySQL?"},
+ {"9.2", "Why are there is so many releases of MySQL?"},
+ {"9.3", "Checking a table for errors"},
+ {"9.4", "How to repair tables"},
+ {"9.5", "Is there anything special to do when upgrading/downgrading MySQL?"},
+ {"9.5.1", "Upgrading from a 3.21 version to 3.22"},
+ {"9.5.2", "Upgrading from a 3.20 version to 3.21"},
+ {"9.5.3", "Upgrading to another architecture"},
+ {"9.6", "Year 2000 compliance"},
+ {"10", "MySQL Server functions"},
+ {"10.1", "What languages are supported by MySQL?"},
+ {"10.1.1", "Character set used for data &#38; sorting"},
+ {"10.2", "The update log"},
+ {"10.3", "How big can MySQL tables be?"},
+ {"11", "Getting maximum performance from MySQL"},
+ {"11.1", "How does one change the size of MySQL buffers?"},
+ {"11.2", "How compiling and linking affects the speed of MySQL"},
+ {"11.3", "How does MySQL use memory?"},
+ {"11.4", "How does MySQL use indexes?"},
+ {"11.5", "What optimizations are done on WHERE clauses?"},
+ {"11.6", "How does MySQL open &#38; close tables?"},
+ {"11.6.0.1", "What are the drawbacks of creating possibly thousands of tables in a database?"},
+ {"11.7", "How does MySQL lock tables?"},
+ {"11.8", "How should I arrange my table to be as fast/small as possible?"},
+ {"11.9", "What affects the speed of INSERT statements?"},
+ {"11.10", "What affects the speed DELETE statements?"},
+ {"11.11", "How do I get MySQL to run at full speed?"},
+ {"11.12", "What are the different row formats? Or, when should VARCHAR/CHAR be used?"},
+ {"11.13", "Why so many open tables?"},
+ {"12", "MySQL benchmark suite"},
+ {"13", "MySQL Utilites"},
+ {"13.1", "Overview of the different MySQL programs"},
+ {"13.2", "The MySQL table check, optimize and repair program"},
+ {"13.2.1", "isamchk memory use"},
+ {"13.2.2", "Getting low-level table information"},
+ {"13.3", "The MySQL compressed read-only table generator"},
+ {"14", "Adding new functions to MySQL"},
+ {"15", "MySQL ODBC Support"},
+ {"15.1", "Operating systems supported by MyODBC"},
+ {"15.2", "How to report problems with MyODBC"},
+ {"15.3", "Programs known to work with MyODBC"},
+ {"15.4", "How to fill in the various fields in the ODBC administrator program"},
+ {"15.5", "How to get the value of an AUTO_INCREMENT column in ODBC"},
+ {"16", "Problems and common errors"},
+ {"16.1", "Some common errors when using MySQL"},
+ {"16.1.1", "MySQL server has gone away error"},
+ {"16.1.2", "Can't connect to local MySQL server error"},
+ {"16.1.3", "Out of memory error"},
+ {"16.1.4", "Packet too large error"},
+ {"16.1.5", "The table is full error"},
+ {"16.1.6", "Commands out of sync error in client"},
+ {"16.1.7", "Removing user error"},
+ {"16.2", "How MySQL handles a full disk"},
+ {"16.3", "How to run SQL commands from a text file"},
+ {"16.4", "Where MySQL stores temporary files"},
+ {"16.5", "Access denied error"},
+ {"16.6", "How to run MySQL as a normal user"},
+ {"16.7", "Problems with file permissions"},
+ {"16.8", "File not found"},
+ {"16.9", "Problems using DATE columns"},
+ {"16.10", "Case sensitivity in searches"},
+ {"16.11", "Problems with NULL values"},
+ {"17", "Solving some common problems with MySQL"},
+ {"17.1", "Database replication"},
+ {"17.2", "Database backups"},
+ {"18", "MySQL client tools and API's"},
+ {"18.1", "MySQL C API"},
+ {"18.2", "C API datatypes"},
+ {"18.3", "C API function overview"},
+ {"18.4", "C API function descriptions"},
+ {"18.4.1", "mysql_affected_rows()"},
+ {"18.4.2", "mysql_close()"},
+ {"18.4.3", "mysql_connect()"},
+ {"18.4.4", "mysql_create_db()"},
+ {"18.4.5", "mysql_data_seek()"},
+ {"18.4.6", "mysql_debug()"},
+ {"18.4.7", "mysql_drop_db()"},
+ {"18.4.8", "mysql_dump_debug_info()"},
+ {"18.4.9", "mysql_eof()"},
+ {"18.4.10", "mysql_errno()"},
+ {"18.4.11", "mysql_error()"},
+ {"18.4.12", "mysql_escape_string()"},
+ {"18.4.13", "mysql_fetch_field()"},
+ {"18.4.14", "mysql_fetch_fields()"},
+ {"18.4.15", "mysql_fetch_field_direct()"},
+ {"18.4.16", "mysql_fetch_lengths()"},
+ {"18.4.17", "mysql_fetch_row()"},
+ {"18.4.18", "mysql_field_seek()"},
+ {"18.4.19", "mysql_field_tell()"},
+ {"18.4.20", "mysql_free_result()"},
+ {"18.4.21", "mysql_get_client_info()"},
+ {"18.4.22", "mysql_get_host_info()"},
+ {"18.4.23", "mysql_get_proto_info()"},
+ {"18.4.24", "mysql_get_server_info()"},
+ {"18.4.25", "mysql_info()"},
+ {"18.4.26", "mysql_init()"},
+ {"18.4.27", "mysql_insert_id()"},
+ {"18.4.28", "mysql_kill()"},
+ {"18.4.29", "mysql_list_dbs()"},
+ {"18.4.30", "mysql_list_fields()"},
+ {"18.4.31", "mysql_list_processes()"},
+ {"18.4.32", "mysql_list_tables()"},
+ {"18.4.33", "mysql_num_fields()"},
+ {"18.4.34", "mysql_num_rows()"},
+ {"18.4.35", "mysql_query()"},
+ {"18.4.36", "mysql_real_connect()"},
+ {"18.4.37", "mysql_real_query()"},
+ {"18.4.38", "mysql_reload()"},
+ {"18.4.39", "mysql_row_tell()"},
+ {"18.4.40", "mysql_select_db()"},
+ {"18.4.41", "mysql_shutdown()"},
+ {"18.4.42", "mysql_stat()"},
+ {"18.4.43", "mysql_store_result()"},
+ {"18.4.44", "mysql_thread_id()"},
+ {"18.4.45", "mysql_use_result()"},
+ {"18.4.46", "Why is it that after mysql_query() returns success, mysql_store_result() sometimes returns NULL?"},
+ {"18.4.47", "What results can I get from a query?"},
+ {"18.4.48", "How can I get the unique ID for the last inserted row?"},
+ {"18.4.49", "Problems linking with the C API"},
+ {"18.4.50", "How to make a thread-safe client"},
+ {"18.5", "MySQL Perl API's"},
+ {"18.5.1", "DBI with DBD::mysql"},
+ {"18.5.1.1", "The DBI interface"},
+ {"18.5.1.2", "More DBI/DBD information"},
+ {"18.6", "MySQL Java connectivity (JDBC)"},
+ {"18.7", "MySQL PHP API's"},
+ {"18.8", "MySQL C++ API's"},
+ {"18.9", "MySQL Python API's"},
+ {"18.10", "MySQL TCL API's"},
+ {"19", "How MySQL compares to other databases"},
+ {"19.1", "How MySQL compares to mSQL"},
+ {"19.1.1", "How to convert mSQL tools for MySQL"},
+ {"19.1.2", "How mSQL and MySQL client/server communications protocols differ"},
+ {"19.1.3", "How mSQL 2.0 SQL syntax differs from MySQL"},
+ {"19.2", "How MySQL compares to PostgreSQL"},
+ {"A", "Some users of MySQL"},
+ {"B", "Contributed programs"},
+ {"C", "Contributors to MySQL"},
+ {"D", "MySQL change history"},
+ {"19.3", "Changes in release 3.22.x (Alpha version)"},
+ {"19.3.1", "Changes in release 3.22.7"},
+ {"19.3.2", "Changes in release 3.22.6"},
+ {"19.3.3", "Changes in release 3.22.5"},
+ {"19.3.4", "Changes in release 3.22.4"},
+ {"19.3.5", "Changes in release 3.22.3"},
+ {"19.3.6", "Changes in release 3.22.2"},
+ {"19.3.7", "Changes in release 3.22.1"},
+ {"19.3.8", "Changes in release 3.22.0"},
+ {"19.4", "Changes in release 3.21.x"},
+ {"19.4.1", "Changes in release 3.21.33"},
+ {"19.4.2", "Changes in release 3.21.32"},
+ {"19.4.3", "Changes in release 3.21.31"},
+ {"19.4.4", "Changes in release 3.21.30"},
+ {"19.4.5", "Changes in release 3.21.29"},
+ {"19.4.6", "Changes in release 3.21.28"},
+ {"19.4.7", "Changes in release 3.21.27"},
+ {"19.4.8", "Changes in release 3.21.26"},
+ {"19.4.9", "Changes in release 3.21.25"},
+ {"19.4.10", "Changes in release 3.21.24"},
+ {"19.4.11", "Changes in release 3.21.23"},
+ {"19.4.12", "Changes in release 3.21.22"},
+ {"19.4.13", "Changes in release 3.21.21a"},
+ {"19.4.14", "Changes in release 3.21.21"},
+ {"19.4.15", "Changes in release 3.21.20"},
+ {"19.4.16", "Changes in release 3.21.19"},
+ {"19.4.17", "Changes in release 3.21.18"},
+ {"19.4.18", "Changes in release 3.21.17"},
+ {"19.4.19", "Changes in release 3.21.16"},
+ {"19.4.20", "Changes in release 3.21.15"},
+ {"19.4.21", "Changes in release 3.21.14b"},
+ {"19.4.22", "Changes in release 3.21.14a"},
+ {"19.4.23", "Changes in release 3.21.13"},
+ {"19.4.24", "Changes in release 3.21.12"},
+ {"19.4.25", "Changes in release 3.21.11"},
+ {"19.4.26", "Changes in release 3.21.10"},
+ {"19.4.27", "Changes in release 3.21.9"},
+ {"19.4.28", "Changes in release 3.21.8"},
+ {"19.4.29", "Changes in release 3.21.7"},
+ {"19.4.30", "Changes in release 3.21.6"},
+ {"19.4.31", "Changes in release 3.21.5"},
+ {"19.4.32", "Changes in release 3.21.4"},
+ {"19.4.33", "Changes in release 3.21.3"},
+ {"19.4.34", "Changes in release 3.21.2"},
+ {"19.4.35", "Changes in release 3.21.0"},
+ {"19.5", "Changes in release 3.20.x"},
+ {"19.5.1", "Changes in release 3.20.18"},
+ {"19.5.2", "Changes in release 3.20.17"},
+ {"19.5.3", "Changes in release 3.20.16"},
+ {"19.5.4", "Changes in release 3.20.15"},
+ {"19.5.5", "Changes in release 3.20.14"},
+ {"19.5.6", "Changes in release 3.20.13"},
+ {"19.5.7", "Changes in release 3.20.11"},
+ {"19.5.8", "Changes in release 3.20.10"},
+ {"19.5.9", "Changes in release 3.20.9"},
+ {"19.5.10", "Changes in release 3.20.8"},
+ {"19.5.11", "Changes in release 3.20.7"},
+ {"19.5.12", "Changes in release 3.20.6"},
+ {"19.5.13", "Changes in release 3.20.3"},
+ {"19.5.14", "Changes in release 3.20.0"},
+ {"19.6", "Changes in release 3.19.x"},
+ {"19.6.1", "Changes in release 3.19.5"},
+ {"19.6.2", "Changes in release 3.19.4"},
+ {"19.6.3", "Changes in release 3.19.3"},
+ {"E", "Known errors and design deficiencies in MySQL"},
+ {"F", "List of things we want to add to MySQL in the future (The TODO)"},
+ {"19.7", "Things that must done in the real near future"},
+ {"19.8", "Things that have to be done sometime"},
+ {"19.9", "Some things we don't have any plans to do"},
+ {"G", "Comments on porting to other systems"},
+ {"19.10", "Debugging MySQL"},
+ {"19.11", "Comments about RTS threads"},
+ {"19.12", "What is the difference between different thread packages?"},
+ {"H", "Description of MySQL regular expression syntax"},
+ {"I", "What is Unireg?"},
+ {"J", "The MySQL server license"},
+ {"K", "The MySQL license for Microsoft operating systems"},
+ {"*", "SQL command, type and function index"},
+ {"*", "Concept Index"}
+};
+
+#define NQUERIES 5
+const char *query[NQUERIES]={
+ "mysql information and manual",
+ "upgrading from previous version",
+ "column indexes",
+ "against about after more right the with/without", /* stopwords test */
+ "mysql license and copyright"
+};
diff --git a/storage/maria/ma_ft_update.c b/storage/maria/ma_ft_update.c
new file mode 100644
index 00000000000..567eb4dec13
--- /dev/null
+++ b/storage/maria/ma_ft_update.c
@@ -0,0 +1,373 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/* functions to work with full-text indices */
+
+#include "ma_ftdefs.h"
+#include <math.h>
+
+void _ma_ft_segiterator_init(MARIA_HA *info, uint keynr, const uchar *record,
+ FT_SEG_ITERATOR *ftsi)
+{
+ DBUG_ENTER("_ma_ft_segiterator_init");
+
+ ftsi->num=info->s->keyinfo[keynr].keysegs;
+ ftsi->seg=info->s->keyinfo[keynr].seg;
+ ftsi->rec=record;
+ DBUG_VOID_RETURN;
+}
+
+void _ma_ft_segiterator_dummy_init(const uchar *record, uint len,
+ FT_SEG_ITERATOR *ftsi)
+{
+ DBUG_ENTER("_ma_ft_segiterator_dummy_init");
+
+ ftsi->num=1;
+ ftsi->seg=0;
+ ftsi->pos=record;
+ ftsi->len=len;
+ DBUG_VOID_RETURN;
+}
+
+/*
+ This function breaks convention "return 0 in success"
+ but it's easier to use like this
+
+ while(_ma_ft_segiterator())
+
+ so "1" means "OK", "0" means "EOF"
+*/
+
+uint _ma_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
+{
+ DBUG_ENTER("_ma_ft_segiterator");
+
+ if (!ftsi->num)
+ DBUG_RETURN(0);
+
+ ftsi->num--;
+ if (!ftsi->seg)
+ DBUG_RETURN(1);
+
+ ftsi->seg--;
+
+ if (ftsi->seg->null_bit &&
+ (ftsi->rec[ftsi->seg->null_pos] & ftsi->seg->null_bit))
+ {
+ ftsi->pos=0;
+ DBUG_RETURN(1);
+ }
+ ftsi->pos= ftsi->rec+ftsi->seg->start;
+ if (ftsi->seg->flag & HA_VAR_LENGTH_PART)
+ {
+ uint pack_length= (ftsi->seg->bit_start);
+ ftsi->len= (pack_length == 1 ? (uint) * ftsi->pos :
+ uint2korr(ftsi->pos));
+ ftsi->pos+= pack_length; /* Skip VARCHAR length */
+ DBUG_RETURN(1);
+ }
+ if (ftsi->seg->flag & HA_BLOB_PART)
+ {
+ ftsi->len= _ma_calc_blob_length(ftsi->seg->bit_start,ftsi->pos);
+ memcpy_fixed((char*) &ftsi->pos, ftsi->pos+ftsi->seg->bit_start,
+ sizeof(char*));
+ DBUG_RETURN(1);
+ }
+ ftsi->len=ftsi->seg->length;
+ DBUG_RETURN(1);
+}
+
+
+/* parses a document i.e. calls maria_ft_parse for every keyseg */
+
+uint _ma_ft_parse(TREE *parsed, MARIA_HA *info, uint keynr, const uchar *record,
+ MYSQL_FTPARSER_PARAM *param, MEM_ROOT *mem_root)
+{
+ FT_SEG_ITERATOR ftsi;
+ struct st_mysql_ftparser *parser;
+ DBUG_ENTER("_ma_ft_parse");
+
+ _ma_ft_segiterator_init(info, keynr, record, &ftsi);
+
+ maria_ft_parse_init(parsed, info->s->keyinfo[keynr].seg->charset);
+ parser= info->s->keyinfo[keynr].parser;
+ while (_ma_ft_segiterator(&ftsi))
+ {
+ /** @todo this casts ftsi.pos (const) to non-const */
+ if (ftsi.pos)
+ if (maria_ft_parse(parsed, (uchar *)ftsi.pos, ftsi.len, parser, param,
+ mem_root))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+FT_WORD * _ma_ft_parserecord(MARIA_HA *info, uint keynr, const uchar *record,
+ MEM_ROOT *mem_root)
+{
+ TREE ptree;
+ MYSQL_FTPARSER_PARAM *param;
+ DBUG_ENTER("_ma_ft_parserecord");
+ if (! (param= maria_ftparser_call_initializer(info, keynr, 0)))
+ DBUG_RETURN(NULL);
+ bzero((char*) &ptree, sizeof(ptree));
+ param->flags= 0;
+ if (_ma_ft_parse(&ptree, info, keynr, record, param, mem_root))
+ DBUG_RETURN(NULL);
+
+ DBUG_RETURN(maria_ft_linearize(&ptree, mem_root));
+}
+
+static int _ma_ft_store(MARIA_HA *info, uint keynr, uchar *keybuf,
+ FT_WORD *wlist, my_off_t filepos)
+{
+ DBUG_ENTER("_ma_ft_store");
+
+ for (; wlist->pos; wlist++)
+ {
+ MARIA_KEY key;
+ _ma_ft_make_key(info, &key, keynr, keybuf, wlist, filepos);
+ if (_ma_ck_write(info, &key))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+static int _ma_ft_erase(MARIA_HA *info, uint keynr, uchar *keybuf,
+ FT_WORD *wlist, my_off_t filepos)
+{
+ uint err=0;
+ DBUG_ENTER("_ma_ft_erase");
+
+ for (; wlist->pos; wlist++)
+ {
+ MARIA_KEY key;
+ _ma_ft_make_key(info, &key, keynr, keybuf, wlist, filepos);
+ if (_ma_ck_delete(info, &key))
+ err=1;
+ }
+ DBUG_RETURN(err);
+}
+
+/*
+ Compares an appropriate parts of two WORD_KEY keys directly out of records
+ returns 1 if they are different
+*/
+
+#define THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT 1
+#define GEE_THEY_ARE_ABSOLUTELY_IDENTICAL 0
+
+int _ma_ft_cmp(MARIA_HA *info, uint keynr, const uchar *rec1, const uchar *rec2)
+{
+ FT_SEG_ITERATOR ftsi1, ftsi2;
+ CHARSET_INFO *cs=info->s->keyinfo[keynr].seg->charset;
+ DBUG_ENTER("_ma_ft_cmp");
+
+ _ma_ft_segiterator_init(info, keynr, rec1, &ftsi1);
+ _ma_ft_segiterator_init(info, keynr, rec2, &ftsi2);
+
+ while (_ma_ft_segiterator(&ftsi1) && _ma_ft_segiterator(&ftsi2))
+ {
+ if ((ftsi1.pos != ftsi2.pos) &&
+ (!ftsi1.pos || !ftsi2.pos ||
+ ha_compare_text(cs, ftsi1.pos,ftsi1.len,
+ ftsi2.pos,ftsi2.len,0,0)))
+ DBUG_RETURN(THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT);
+ }
+ DBUG_RETURN(GEE_THEY_ARE_ABSOLUTELY_IDENTICAL);
+}
+
+
+/* update a document entry */
+
+int _ma_ft_update(MARIA_HA *info, uint keynr, uchar *keybuf,
+ const uchar *oldrec, const uchar *newrec, my_off_t pos)
+{
+ int error= -1;
+ FT_WORD *oldlist,*newlist, *old_word, *new_word;
+ CHARSET_INFO *cs=info->s->keyinfo[keynr].seg->charset;
+ int cmp, cmp2;
+ DBUG_ENTER("_ma_ft_update");
+
+ if (!(old_word=oldlist=_ma_ft_parserecord(info, keynr, oldrec,
+ &info->ft_memroot)) ||
+ !(new_word=newlist=_ma_ft_parserecord(info, keynr, newrec,
+ &info->ft_memroot)))
+ goto err;
+
+ error=0;
+ while(old_word->pos && new_word->pos)
+ {
+ cmp= ha_compare_text(cs, (uchar*) old_word->pos,old_word->len,
+ (uchar*) new_word->pos,new_word->len,0,0);
+ cmp2= cmp ? 0 : (fabs(old_word->weight - new_word->weight) > 1.e-5);
+
+ if (cmp < 0 || cmp2)
+ {
+ MARIA_KEY key;
+ _ma_ft_make_key(info, &key, keynr, keybuf, old_word, pos);
+ if ((error= _ma_ck_delete(info, &key)))
+ goto err;
+ }
+ if (cmp > 0 || cmp2)
+ {
+ MARIA_KEY key;
+ _ma_ft_make_key(info, &key, keynr, keybuf, new_word,pos);
+ if ((error= _ma_ck_write(info, &key)))
+ goto err;
+ }
+ if (cmp<=0) old_word++;
+ if (cmp>=0) new_word++;
+ }
+ if (old_word->pos)
+ error= _ma_ft_erase(info,keynr,keybuf,old_word,pos);
+ else if (new_word->pos)
+ error= _ma_ft_store(info,keynr,keybuf,new_word,pos);
+
+err:
+ free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
+ DBUG_RETURN(error);
+}
+
+
+/* adds a document to the collection */
+
+int _ma_ft_add(MARIA_HA *info, uint keynr, uchar *keybuf, const uchar *record,
+ my_off_t pos)
+{
+ int error= -1;
+ FT_WORD *wlist;
+ DBUG_ENTER("_ma_ft_add");
+ DBUG_PRINT("enter",("keynr: %d",keynr));
+
+ if ((wlist= _ma_ft_parserecord(info, keynr, record, &info->ft_memroot)))
+ error= _ma_ft_store(info,keynr,keybuf,wlist,pos);
+ free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
+ DBUG_PRINT("exit",("Return: %d",error));
+ DBUG_RETURN(error);
+}
+
+
+/* removes a document from the collection */
+
+int _ma_ft_del(MARIA_HA *info, uint keynr, uchar *keybuf, const uchar *record,
+ my_off_t pos)
+{
+ int error= -1;
+ FT_WORD *wlist;
+ DBUG_ENTER("_ma_ft_del");
+ DBUG_PRINT("enter",("keynr: %d",keynr));
+
+ if ((wlist= _ma_ft_parserecord(info, keynr, record, &info->ft_memroot)))
+ error= _ma_ft_erase(info,keynr,keybuf,wlist,pos);
+ free_root(&info->ft_memroot, MYF(MY_MARK_BLOCKS_FREE));
+ DBUG_PRINT("exit",("Return: %d",error));
+ DBUG_RETURN(error);
+}
+
+
+MARIA_KEY *_ma_ft_make_key(MARIA_HA *info, MARIA_KEY *key, uint keynr,
+ uchar *keybuf,
+ FT_WORD *wptr, my_off_t filepos)
+{
+ uchar buf[HA_FT_MAXBYTELEN+16];
+ DBUG_ENTER("_ma_ft_make_key");
+
+#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
+ {
+ float weight=(float) ((filepos==HA_OFFSET_ERROR) ? 0 : wptr->weight);
+ mi_float4store(buf,weight);
+ }
+#else
+#error
+#endif
+
+ int2store(buf+HA_FT_WLEN,wptr->len);
+ memcpy(buf+HA_FT_WLEN+2,wptr->pos,wptr->len);
+ /* Can't be spatial so it's ok to call _ma_make_key directly here */
+ DBUG_RETURN(_ma_make_key(info, key, keynr, keybuf, buf, filepos, 0));
+}
+
+
+/*
+ convert key value to ft2
+*/
+
+uint _ma_ft_convert_to_ft2(MARIA_HA *info, MARIA_KEY *key)
+{
+ MARIA_SHARE *share= info->s;
+ my_off_t root;
+ DYNAMIC_ARRAY *da=info->ft1_to_ft2;
+ MARIA_KEYDEF *keyinfo=&share->ft2_keyinfo;
+ uchar *key_ptr= (uchar*) dynamic_array_ptr(da, 0), *end;
+ uint length, key_length;
+ MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
+ MARIA_KEY tmp_key;
+ DBUG_ENTER("_ma_ft_convert_to_ft2");
+
+ /* we'll generate one pageful at once, and insert the rest one-by-one */
+ /* calculating the length of this page ...*/
+ length=(keyinfo->block_length-2) / keyinfo->keylength;
+ set_if_smaller(length, da->elements);
+ length=length * keyinfo->keylength;
+
+ get_key_full_length_rdonly(key_length, key->data);
+ while (_ma_ck_delete(info, key) == 0)
+ {
+ /*
+ nothing to do here.
+ _ma_ck_delete() will populate info->ft1_to_ft2 with deleted keys
+ */
+ }
+
+ /* creating pageful of keys */
+ bzero(info->buff, share->keypage_header);
+ _ma_store_keynr(share, info->buff, keyinfo->key_nr);
+ _ma_store_page_used(share, info->buff, length + share->keypage_header);
+ memcpy(info->buff + share->keypage_header, key_ptr, length);
+ info->keyread_buff_used= info->page_changed=1; /* info->buff is used */
+ /**
+ @todo RECOVERY BUG this is not logged yet. Ok as this code is never
+ called, but soon it will be.
+ */
+ if ((root= _ma_new(info, DFLT_INIT_HITS, &page_link)) == HA_OFFSET_ERROR ||
+ _ma_write_keypage(info, keyinfo, root, page_link->write_lock,
+ DFLT_INIT_HITS, info->buff))
+ DBUG_RETURN(-1);
+
+ /* inserting the rest of key values */
+ end= (uchar*) dynamic_array_ptr(da, da->elements);
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data_length= keyinfo->keylength;
+ tmp_key.ref_length= 0;
+ tmp_key.flag= 0;
+ for (key_ptr+=length; key_ptr < end; key_ptr+=keyinfo->keylength)
+ {
+ tmp_key.data= key_ptr;
+ if (_ma_ck_real_write_btree(info, key, &root, SEARCH_SAME))
+ DBUG_RETURN(-1);
+ }
+
+ /* now, writing the word key entry */
+ ft_intXstore(key->data + key_length, - (int) da->elements);
+ _ma_dpointer(share, key->data + key_length + HA_FT_WLEN, root);
+
+ DBUG_RETURN(_ma_ck_real_write_btree(info, key,
+ &share->state.key_root[key->keyinfo->
+ key_nr],
+ SEARCH_SAME));
+}
diff --git a/storage/maria/ma_ftdefs.h b/storage/maria/ma_ftdefs.h
new file mode 100644
index 00000000000..bd5309ea265
--- /dev/null
+++ b/storage/maria/ma_ftdefs.h
@@ -0,0 +1,153 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/* some definitions for full-text indices */
+
+#include "ma_fulltext.h"
+#include <m_ctype.h>
+#include <my_tree.h>
+#include <queues.h>
+#include <mysql/plugin.h>
+
+#define true_word_char(ctype, character) \
+ ((ctype) & (_MY_U | _MY_L | _MY_NMR) || \
+ (character) == '_')
+#define misc_word_char(X) 0
+
+#define FT_MAX_WORD_LEN_FOR_SORT 31
+
+#define FTPARSER_MEMROOT_ALLOC_SIZE 65536
+
+#define COMPILE_STOPWORDS_IN
+
+/* Interested readers may consult SMART
+ (ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z)
+ for an excellent implementation of vector space model we use.
+ It also demonstrate the usage of different weghting techniques.
+ This code, though, is completely original and is not based on the
+ SMART code but was in some cases inspired by it.
+
+ NORM_PIVOT was taken from the article
+ A.Singhal, C.Buckley, M.Mitra, "Pivoted Document Length Normalization",
+ ACM SIGIR'96, 21-29, 1996
+ */
+
+#define LWS_FOR_QUERY LWS_TF
+#define LWS_IN_USE LWS_LOG
+#define PRENORM_IN_USE PRENORM_AVG
+#define NORM_IN_USE NORM_PIVOT
+#define GWS_IN_USE GWS_PROB
+/*==============================================================*/
+#define LWS_TF (count)
+#define LWS_BINARY (count>0)
+#define LWS_SQUARE (count*count)
+#define LWS_LOG (count?(log( (double) count)+1):0)
+/*--------------------------------------------------------------*/
+#define PRENORM_NONE (p->weight)
+#define PRENORM_MAX (p->weight/docstat.max)
+#define PRENORM_AUG (0.4+0.6*p->weight/docstat.max)
+#define PRENORM_AVG (p->weight/docstat.sum*docstat.uniq)
+#define PRENORM_AVGLOG ((1+log(p->weight))/(1+log(docstat.sum/docstat.uniq)))
+/*--------------------------------------------------------------*/
+#define NORM_NONE (1)
+#define NORM_SUM (docstat.nsum)
+#define NORM_COS (sqrt(docstat.nsum2))
+
+#define PIVOT_VAL (0.0115)
+#define NORM_PIVOT (1+PIVOT_VAL*docstat.uniq)
+/*---------------------------------------------------------------*/
+#define GWS_NORM (1/sqrt(sum2))
+#define GWS_GFIDF (sum/doc_cnt)
+/* Mysterious, but w/o (double) GWS_IDF performs better :-o */
+#define GWS_IDF log(aio->info->state->records/doc_cnt)
+#define GWS_IDF1 log((double)aio->info->state->records/doc_cnt)
+#define GWS_PROB ((aio->info->state->records > doc_cnt) ? log(((double)(aio->info->state->records-doc_cnt))/doc_cnt) : 0 )
+#define GWS_FREQ (1.0/doc_cnt)
+#define GWS_SQUARED pow(log((double)aio->info->state->records/doc_cnt),2)
+#define GWS_CUBIC pow(log((double)aio->info->state->records/doc_cnt),3)
+#define GWS_ENTROPY (1-(suml/sum-log(sum))/log(aio->info->state->records))
+/*=================================================================*/
+
+/* Boolean search operators */
+#define FTB_YES (ft_boolean_syntax[0])
+#define FTB_EGAL (ft_boolean_syntax[1])
+#define FTB_NO (ft_boolean_syntax[2])
+#define FTB_INC (ft_boolean_syntax[3])
+#define FTB_DEC (ft_boolean_syntax[4])
+#define FTB_LBR (ft_boolean_syntax[5])
+#define FTB_RBR (ft_boolean_syntax[6])
+#define FTB_NEG (ft_boolean_syntax[7])
+#define FTB_TRUNC (ft_boolean_syntax[8])
+#define FTB_LQUOT (ft_boolean_syntax[10])
+#define FTB_RQUOT (ft_boolean_syntax[11])
+
+typedef struct st_maria_ft_word {
+ uchar * pos;
+ uint len;
+ double weight;
+} FT_WORD;
+
+int is_stopword(char *word, uint len);
+
+MARIA_KEY *_ma_ft_make_key(MARIA_HA *, MARIA_KEY *, uint , uchar *, FT_WORD *,
+ my_off_t);
+
+uchar maria_ft_get_word(CHARSET_INFO *, uchar **, uchar *, FT_WORD *,
+ MYSQL_FTPARSER_BOOLEAN_INFO *);
+uchar maria_ft_simple_get_word(CHARSET_INFO *, uchar **, const uchar *,
+ FT_WORD *, my_bool);
+
+typedef struct _st_maria_ft_seg_iterator {
+ uint num, len;
+ HA_KEYSEG *seg;
+ const uchar *rec, *pos;
+} FT_SEG_ITERATOR;
+
+void _ma_ft_segiterator_init(MARIA_HA *, uint, const uchar *, FT_SEG_ITERATOR *);
+void _ma_ft_segiterator_dummy_init(const uchar *, uint, FT_SEG_ITERATOR *);
+uint _ma_ft_segiterator(FT_SEG_ITERATOR *);
+
+void maria_ft_parse_init(TREE *, CHARSET_INFO *);
+int maria_ft_parse(TREE *, uchar *, int, struct st_mysql_ftparser *parser,
+ MYSQL_FTPARSER_PARAM *, MEM_ROOT *);
+FT_WORD * maria_ft_linearize(TREE *, MEM_ROOT *);
+FT_WORD * _ma_ft_parserecord(MARIA_HA *, uint, const uchar *, MEM_ROOT *);
+uint _ma_ft_parse(TREE *, MARIA_HA *, uint, const uchar *,
+ MYSQL_FTPARSER_PARAM *, MEM_ROOT *);
+
+FT_INFO *maria_ft_init_nlq_search(MARIA_HA *, uint, uchar *, uint, uint, uchar *);
+FT_INFO *maria_ft_init_boolean_search(MARIA_HA *, uint, uchar *, uint, CHARSET_INFO *);
+
+extern const struct _ft_vft _ma_ft_vft_nlq;
+int maria_ft_nlq_read_next(FT_INFO *, char *);
+float maria_ft_nlq_find_relevance(FT_INFO *, uchar *, uint);
+void maria_ft_nlq_close_search(FT_INFO *);
+float maria_ft_nlq_get_relevance(FT_INFO *);
+my_off_t maria_ft_nlq_get_docid(FT_INFO *);
+void maria_ft_nlq_reinit_search(FT_INFO *);
+
+extern const struct _ft_vft _ma_ft_vft_boolean;
+int maria_ft_boolean_read_next(FT_INFO *, char *);
+float maria_ft_boolean_find_relevance(FT_INFO *, uchar *, uint);
+void maria_ft_boolean_close_search(FT_INFO *);
+float maria_ft_boolean_get_relevance(FT_INFO *);
+my_off_t maria_ft_boolean_get_docid(FT_INFO *);
+void maria_ft_boolean_reinit_search(FT_INFO *);
+extern MYSQL_FTPARSER_PARAM *maria_ftparser_call_initializer(MARIA_HA *info,
+ uint keynr,
+ uint paramnr);
+extern void maria_ftparser_call_deinitializer(MARIA_HA *info);
diff --git a/storage/maria/ma_fulltext.h b/storage/maria/ma_fulltext.h
new file mode 100644
index 00000000000..bc94bb9c0e5
--- /dev/null
+++ b/storage/maria/ma_fulltext.h
@@ -0,0 +1,27 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/* some definitions for full-text indices */
+
+#include "maria_def.h"
+#include "ft_global.h"
+
+int _ma_ft_cmp(MARIA_HA *, uint, const uchar *, const uchar *);
+int _ma_ft_add(MARIA_HA *, uint, uchar *, const uchar *, my_off_t);
+int _ma_ft_del(MARIA_HA *, uint, uchar *, const uchar *, my_off_t);
+
+uint _ma_ft_convert_to_ft2(MARIA_HA *, MARIA_KEY *);
diff --git a/storage/maria/ma_info.c b/storage/maria/ma_info.c
new file mode 100644
index 00000000000..1bbfa3cbf7e
--- /dev/null
+++ b/storage/maria/ma_info.c
@@ -0,0 +1,142 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Return useful base information for an open table */
+
+#include "maria_def.h"
+#ifdef __WIN__
+#include <sys/stat.h>
+#endif
+
+ /* Get position to last record */
+
+MARIA_RECORD_POS maria_position(MARIA_HA *info)
+{
+ return info->cur_row.lastpos;
+}
+
+
+/* Get information about the table */
+/* if flag == 2 one get current info (no sync from database */
+
+int maria_status(MARIA_HA *info, register MARIA_INFO *x, uint flag)
+{
+ MY_STAT state;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_status");
+
+ x->recpos= info->cur_row.lastpos;
+ if (flag == HA_STATUS_POS)
+ DBUG_RETURN(0); /* Compatible with ISAM */
+ if (!(flag & HA_STATUS_NO_LOCK))
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ VOID(_ma_readinfo(info,F_RDLCK,0));
+ fast_ma_writeinfo(info);
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ if (flag & HA_STATUS_VARIABLE)
+ {
+ x->records = info->state->records;
+ x->deleted = share->state.state.del;
+ x->delete_length = share->state.state.empty;
+ x->data_file_length = share->state.state.data_file_length;
+ x->index_file_length= share->state.state.key_file_length;
+
+ x->keys = share->state.header.keys;
+ x->check_time = share->state.check_time;
+ x->mean_reclength = x->records ?
+ (ulong) ((x->data_file_length - x->delete_length) /x->records) :
+ (ulong) share->min_pack_length;
+ }
+ if (flag & HA_STATUS_ERRKEY)
+ {
+ x->errkey= info->errkey;
+ x->dup_key_pos= info->dup_key_pos;
+ }
+ if (flag & HA_STATUS_CONST)
+ {
+ x->reclength = share->base.reclength;
+ x->max_data_file_length=share->base.max_data_file_length;
+ x->max_index_file_length=info->s->base.max_key_file_length;
+ x->filenr = info->dfile.file;
+ x->options = share->options;
+ x->create_time=share->state.create_time;
+ x->reflength= maria_get_pointer_length(share->base.max_data_file_length,
+ maria_data_pointer_size);
+ x->record_offset= (info->s->data_file_type == STATIC_RECORD ?
+ share->base.pack_reclength: 0);
+ x->sortkey= -1; /* No clustering */
+ x->rec_per_key = share->state.rec_per_key_part;
+ x->key_map = share->state.key_map;
+ x->data_file_name = share->data_file_name.str;
+ x->index_file_name = share->index_file_name.str;
+ x->data_file_type = share->data_file_type;
+ }
+ if ((flag & HA_STATUS_TIME) && !my_fstat(info->dfile.file, &state, MYF(0)))
+ x->update_time=state.st_mtime;
+ else
+ x->update_time=0;
+ if (flag & HA_STATUS_AUTO)
+ {
+ x->auto_increment= share->state.auto_increment+1;
+ if (!x->auto_increment) /* This shouldn't happen */
+ x->auto_increment= ~(ulonglong) 0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Write a message to the error log.
+
+ SYNOPSIS
+ _ma_report_error()
+ file_name Name of table file (e.g. index_file_name).
+ errcode Error number.
+
+ DESCRIPTION
+ This function supplies my_error() with a table name. Most error
+ messages need one. Since string arguments in error messages are limited
+ to 64 characters by convention, we ensure that in case of truncation,
+ that the end of the index file path is in the message. This contains
+ the most valuable information (the table name and the database name).
+
+ RETURN
+ void
+*/
+
+void _ma_report_error(int errcode, const LEX_STRING *name)
+{
+ size_t length;
+ const char *file_name= name->str;
+ DBUG_ENTER("_ma_report_error");
+ DBUG_PRINT("enter",("errcode %d, table '%s'", errcode, file_name));
+
+ if ((length= name->length) > 64)
+ {
+ /* we first remove the directory */
+ size_t dir_length= dirname_length(file_name);
+ file_name+= dir_length;
+ if ((length-= dir_length) > 64)
+ {
+ /* still too long, chop start of table name */
+ file_name+= length - 64;
+ }
+ }
+
+ my_error(errcode, MYF(ME_NOREFRESH), file_name);
+ DBUG_VOID_RETURN;
+}
diff --git a/storage/maria/ma_init.c b/storage/maria/ma_init.c
new file mode 100644
index 00000000000..1f2eddd7e30
--- /dev/null
+++ b/storage/maria/ma_init.c
@@ -0,0 +1,104 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Initialize an maria-database */
+
+#include "maria_def.h"
+#include <ft_global.h>
+#include "ma_blockrec.h"
+#include "trnman_public.h"
+#include "ma_checkpoint.h"
+#include <hash.h>
+
+void history_state_free(MARIA_STATE_HISTORY_CLOSED *closed_history)
+{
+ MARIA_STATE_HISTORY *history, *next;
+
+ /*
+ Free all active history
+ In case of maria_open() this list should be empty as the history is moved
+ to handler->share.
+ */
+ for (history= closed_history->state_history; history ; history= next)
+ {
+ next= history->next;
+ my_free(history, MYF(0));
+ }
+ my_free(closed_history, MYF(0));
+}
+
+
+/*
+ Initialize maria
+
+ SYNOPSIS
+ maria_init()
+
+ TODO
+ Open log files and do recovery if need
+
+ RETURN
+ 0 ok
+ # error number
+*/
+
+int maria_init(void)
+{
+ DBUG_ASSERT(maria_block_size &&
+ maria_block_size % MARIA_MIN_KEY_BLOCK_LENGTH == 0);
+ if (!maria_inited)
+ {
+ maria_inited= TRUE;
+ pthread_mutex_init(&THR_LOCK_maria,MY_MUTEX_INIT_SLOW);
+ _ma_init_block_record_data();
+ trnman_end_trans_hook= _ma_trnman_end_trans_hook;
+ my_handler_error_register();
+ }
+ hash_init(&maria_stored_state, &my_charset_bin, 32,
+ 0, sizeof(LSN), 0, (hash_free_key) history_state_free, 0);
+ DBUG_PRINT("info",("dummy_transaction_object: %p",
+ &dummy_transaction_object));
+ return 0;
+}
+
+
+void maria_end(void)
+{
+ if (maria_inited)
+ {
+ TrID trid;
+ maria_inited= maria_multi_threaded= FALSE;
+ ft_free_stopwords();
+ ma_checkpoint_end();
+ if ((trid= trnman_get_max_trid()) > max_trid_in_control_file)
+ {
+ /*
+ Store max transaction id into control file, in case logs are removed
+ by user, or maria_chk wants to check tables (it cannot access max trid
+ from the log, as it cannot process REDOs).
+ */
+ (void)ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
+ trid, recovery_failures);
+ }
+ trnman_destroy();
+ if (translog_status == TRANSLOG_OK)
+ translog_destroy();
+ end_pagecache(maria_log_pagecache, TRUE);
+ end_pagecache(maria_pagecache, TRUE);
+ ma_control_file_end();
+ pthread_mutex_destroy(&THR_LOCK_maria);
+ hash_free(&maria_stored_state);
+ }
+}
diff --git a/storage/maria/ma_key.c b/storage/maria/ma_key.c
new file mode 100644
index 00000000000..08702a9109e
--- /dev/null
+++ b/storage/maria/ma_key.c
@@ -0,0 +1,733 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions to handle keys */
+
+#include "maria_def.h"
+#include "m_ctype.h"
+#include "ma_sp_defs.h"
+#include "ma_blockrec.h" /* For ROW_FLAG_TRANSID */
+#include "trnman.h"
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
+#define CHECK_KEYS /* Enable safety checks */
+
+static int _ma_put_key_in_record(MARIA_HA *info,uint keynr,uchar *record);
+
+#define FIX_LENGTH(cs, pos, length, char_length) \
+ do { \
+ if (length > char_length) \
+ char_length= (uint) my_charpos(cs, pos, pos+length, char_length); \
+ set_if_smaller(char_length,length); \
+ } while(0)
+
+
+/**
+ Store trid in a packed format as part of a key
+
+ @fn transid_store_packed
+ @param info Maria handler
+ @param to End of key to which we should store a packed transid
+ @param trid Trid to be stored
+
+ @notes
+
+ Keys that have a transid has the lowest bit set for the last byte of the key
+ This function sets this bit for the key.
+
+ Trid is max 6 bytes long
+
+ First Trid it's converted to a smaller number by using
+ trid= trid - create_trid.
+ Then trid is then shifted up one bit so that we can use the
+ lowest bit as a marker if it's followed by another trid.
+
+ Trid is then stored as follows:
+
+ if trid < 256-12
+ one byte
+ else
+ one byte prefix length_of_trid_in_bytes + 249 followed by data
+ in high-byte-first order
+
+ Prefix bytes 244 to 249 are reserved for negative transid, that can be used
+ when we pack transid relative to each other on a key block.
+
+ We have to store transid in high-byte-first order so that we can compare
+ them unpacked byte per byte and as soon we find a difference we know
+ which is smaller.
+
+ For example, assuming we the following data:
+
+ key_data: 1 (4 byte integer)
+ pointer_to_row: 2 << 8 + 3 = 515 (page 2, row 3)
+ table_create_transid 1000 Defined at create table time and
+ stored in table definition
+ transid 1010 Transaction that created row
+ delete_transid 2011 Transaction that deleted row
+
+ In addition we assume the table is created with a data pointer length
+ of 4 bytes (this is automatically calculated based on the medium
+ length of rows and the given max number of rows)
+
+ The binary data for the key would then look like this in hex:
+
+ 00 00 00 01 Key data (1 stored high byte first)
+ 00 00 00 47 (515 << 1) + 1 ; The last 1 is marker that key cont.
+ 15 ((1010-1000) << 1) + 1 ; The last 1 is marker that key cont.
+ FB 07 E6 Length byte (FE = 249 + 2 means 2 bytes) and
+ ((2011 - 1000) << 1) = 07 E6
+*/
+
+uint transid_store_packed(MARIA_HA *info, uchar *to, ulonglong trid)
+{
+ uchar *start;
+ uint length;
+ uchar buff[8];
+ DBUG_ASSERT(trid < (LL(1) << (MARIA_MAX_PACK_TRANSID_SIZE*8)));
+ DBUG_ASSERT(trid >= info->s->state.create_trid);
+
+ trid= (trid - info->s->state.create_trid) << 1;
+
+ /* Mark that key contains transid */
+ to[-1]|= 1;
+
+ if (trid < MARIA_MIN_TRANSID_PACK_OFFSET)
+ {
+ to[0]= (uchar) trid;
+ return 1;
+ }
+ start= to;
+
+ /* store things in low-byte-first-order in buff */
+ to= buff;
+ do
+ {
+ *to++= (uchar) trid;
+ trid= trid>>8;
+ } while (trid);
+
+ length= (uint) (to - buff);
+ /* Store length prefix */
+ start[0]= (uchar) (length + MARIA_TRANSID_PACK_OFFSET);
+ start++;
+ /* Copy things in high-byte-first order to output buffer */
+ do
+ {
+ *start++= *--to;
+ } while (to != buff);
+ return length+1;
+}
+
+
+/**
+ Read packed transid
+
+ @fn transid_get_packed
+ @param info Maria handler
+ @param from Transid is stored here
+
+ See transid_store_packed() for how transid is packed
+
+*/
+
+ulonglong transid_get_packed(MARIA_SHARE *share, const uchar *from)
+{
+ ulonglong value;
+ uint length;
+
+ if (from[0] < MARIA_MIN_TRANSID_PACK_OFFSET)
+ value= (ulonglong) from[0];
+ else
+ {
+ value= 0;
+ for (length= (uint) (from[0] - MARIA_TRANSID_PACK_OFFSET),
+ value= (ulonglong) from[1], from+=2;
+ --length ;
+ from++)
+ value= (value << 8) + ((ulonglong) *from);
+ }
+ return (value >> 1) + share->state.create_trid;
+}
+
+
+/*
+ Make a normal (not spatial or fulltext) intern key from a record
+
+ SYNOPSIS
+ _ma_make_key()
+ info MyiSAM handler
+ int_key Store created key here
+ keynr key number
+ key Buffer used to store key data
+ record Record
+ filepos Position to record in the data file
+
+ NOTES
+ This is used to generate keys from the record on insert, update and delete
+
+ RETURN
+ key
+*/
+
+MARIA_KEY *_ma_make_key(MARIA_HA *info, MARIA_KEY *int_key, uint keynr,
+ uchar *key, const uchar *record,
+ MARIA_RECORD_POS filepos, ulonglong trid)
+{
+ const uchar *pos;
+ reg1 HA_KEYSEG *keyseg;
+ my_bool is_ft;
+ DBUG_ENTER("_ma_make_key");
+
+ int_key->data= key;
+ int_key->flag= 0; /* Always return full key */
+ int_key->keyinfo= info->s->keyinfo + keynr;
+
+ is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
+ for (keyseg= int_key->keyinfo->seg ; keyseg->type ;keyseg++)
+ {
+ enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
+ uint length=keyseg->length;
+ uint char_length;
+ CHARSET_INFO *cs=keyseg->charset;
+
+ if (keyseg->null_bit)
+ {
+ if (record[keyseg->null_pos] & keyseg->null_bit)
+ {
+ *key++= 0; /* NULL in key */
+ continue;
+ }
+ *key++=1; /* Not NULL */
+ }
+
+ char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
+ length);
+
+ pos= record+keyseg->start;
+ if (type == HA_KEYTYPE_BIT)
+ {
+ if (keyseg->bit_length)
+ {
+ uchar bits= get_rec_bits(record + keyseg->bit_pos,
+ keyseg->bit_start, keyseg->bit_length);
+ *key++= (char) bits;
+ length--;
+ }
+ memcpy(key, pos, length);
+ key+= length;
+ continue;
+ }
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ if (type != HA_KEYTYPE_NUM)
+ {
+ length= (uint) cs->cset->lengthsp(cs, (const char*)pos, length);
+ }
+ else
+ {
+ const uchar *end= pos + length;
+ while (pos < end && pos[0] == ' ')
+ pos++;
+ length= (uint) (end-pos);
+ }
+ FIX_LENGTH(cs, pos, length, char_length);
+ store_key_length_inc(key,char_length);
+ memcpy(key, pos, (size_t) char_length);
+ key+=char_length;
+ continue;
+ }
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
+ {
+ uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
+ uint tmp_length= (pack_length == 1 ? (uint) *pos :
+ uint2korr(pos));
+ pos+= pack_length; /* Skip VARCHAR length */
+ set_if_smaller(length,tmp_length);
+ FIX_LENGTH(cs, pos, length, char_length);
+ store_key_length_inc(key,char_length);
+ memcpy(key,pos,(size_t) char_length);
+ key+= char_length;
+ continue;
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ uint tmp_length= _ma_calc_blob_length(keyseg->bit_start,pos);
+ uchar *blob_pos;
+ memcpy_fixed(&blob_pos, pos+keyseg->bit_start,sizeof(char*));
+ set_if_smaller(length,tmp_length);
+ FIX_LENGTH(cs, blob_pos, length, char_length);
+ store_key_length_inc(key,char_length);
+ memcpy(key, blob_pos, (size_t) char_length);
+ key+= char_length;
+ continue;
+ }
+ else if (keyseg->flag & HA_SWAP_KEY)
+ { /* Numerical column */
+#ifdef HAVE_ISNAN
+ if (type == HA_KEYTYPE_FLOAT)
+ {
+ float nr;
+ float4get(nr,pos);
+ if (isnan(nr))
+ {
+ /* Replace NAN with zero */
+ bzero(key,length);
+ key+=length;
+ continue;
+ }
+ }
+ else if (type == HA_KEYTYPE_DOUBLE)
+ {
+ double nr;
+ float8get(nr,pos);
+ if (isnan(nr))
+ {
+ bzero(key,length);
+ key+=length;
+ continue;
+ }
+ }
+#endif
+ pos+=length;
+ while (length--)
+ {
+ *key++ = *--pos;
+ }
+ continue;
+ }
+ FIX_LENGTH(cs, pos, length, char_length);
+ memcpy(key, pos, char_length);
+ if (length > char_length)
+ cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
+ key+= length;
+ }
+ _ma_dpointer(info->s, key, filepos);
+ int_key->data_length= (key - int_key->data);
+ int_key->ref_length= info->s->rec_reflength;
+ int_key->flag= 0;
+ if (_ma_have_versioning(info) && trid)
+ {
+ int_key->ref_length+= transid_store_packed(info,
+ key + int_key->ref_length,
+ (TrID) trid);
+ int_key->flag|= SEARCH_USER_KEY_HAS_TRANSID;
+ }
+
+ DBUG_PRINT("exit",("keynr: %d",keynr));
+ DBUG_DUMP_KEY("key", int_key);
+ DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, int_key););
+ DBUG_RETURN(int_key);
+} /* _ma_make_key */
+
+
+/*
+ Pack a key to intern format from given format (c_rkey)
+
+ SYNOPSIS
+ _ma_pack_key()
+ info MARIA handler
+ int_key Store key here
+ keynr key number
+ key Buffer for key data
+ old Original not packed key
+ keypart_map bitmap of used keyparts
+ last_used_keyseg out parameter. May be NULL
+
+ RETURN
+ int_key
+
+ last_use_keyseg Store pointer to the keyseg after the last used one
+*/
+
+MARIA_KEY *_ma_pack_key(register MARIA_HA *info, MARIA_KEY *int_key,
+ uint keynr, uchar *key,
+ const uchar *old, key_part_map keypart_map,
+ HA_KEYSEG **last_used_keyseg)
+{
+ HA_KEYSEG *keyseg;
+ my_bool is_ft;
+ DBUG_ENTER("_ma_pack_key");
+
+ int_key->data= key;
+ int_key->keyinfo= info->s->keyinfo + keynr;
+
+ /* "one part" rtree key is 2*SPDIMS part key in Maria */
+ if (int_key->keyinfo->key_alg == HA_KEY_ALG_RTREE)
+ keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
+
+ /* only key prefixes are supported */
+ DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
+
+ is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
+ for (keyseg=int_key->keyinfo->seg ; keyseg->type && keypart_map;
+ old+= keyseg->length, keyseg++)
+ {
+ enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
+ uint length= keyseg->length;
+ uint char_length;
+ const uchar *pos;
+ CHARSET_INFO *cs=keyseg->charset;
+
+ keypart_map>>= 1;
+ if (keyseg->null_bit)
+ {
+ if (!(*key++= (char) 1-*old++)) /* Copy null marker */
+ {
+ if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
+ old+= 2;
+ continue; /* Found NULL */
+ }
+ }
+ char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
+ length);
+ pos= old;
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ const uchar *end= pos + length;
+ if (type == HA_KEYTYPE_NUM)
+ {
+ while (pos < end && pos[0] == ' ')
+ pos++;
+ }
+ else if (type != HA_KEYTYPE_BINARY)
+ {
+ while (end > pos && end[-1] == ' ')
+ end--;
+ }
+ length=(uint) (end-pos);
+ FIX_LENGTH(cs, pos, length, char_length);
+ store_key_length_inc(key,char_length);
+ memcpy(key,pos,(size_t) char_length);
+ key+= char_length;
+ continue;
+ }
+ else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
+ {
+ /* Length of key-part used with maria_rkey() always 2 */
+ uint tmp_length=uint2korr(pos);
+ pos+=2;
+ set_if_smaller(length,tmp_length); /* Safety */
+ FIX_LENGTH(cs, pos, length, char_length);
+ store_key_length_inc(key,char_length);
+ old+=2; /* Skip length */
+ memcpy(key, pos,(size_t) char_length);
+ key+= char_length;
+ continue;
+ }
+ else if (keyseg->flag & HA_SWAP_KEY)
+ { /* Numerical column */
+ pos+=length;
+ while (length--)
+ *key++ = *--pos;
+ continue;
+ }
+ FIX_LENGTH(cs, pos, length, char_length);
+ memcpy(key, pos, char_length);
+ if (length > char_length)
+ cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
+ key+= length;
+ }
+ if (last_used_keyseg)
+ *last_used_keyseg= keyseg;
+
+ /* set flag to SEARCH_PART_KEY if we are not using all key parts */
+ int_key->flag= keyseg->type ? SEARCH_PART_KEY : 0;
+ int_key->ref_length= 0;
+ int_key->data_length= (key - int_key->data);
+
+ DBUG_PRINT("exit", ("length: %u", int_key->data_length));
+ DBUG_RETURN(int_key);
+} /* _ma_pack_key */
+
+
+/**
+ Copy a key
+*/
+
+void _ma_copy_key(MARIA_KEY *to, const MARIA_KEY *from)
+{
+ memcpy(to->data, from->data, from->data_length + from->ref_length);
+ to->keyinfo= from->keyinfo;
+ to->data_length= from->data_length;
+ to->ref_length= from->ref_length;
+ to->flag= from->flag;
+}
+
+
+/*
+ Store found key in record
+
+ SYNOPSIS
+ _ma_put_key_in_record()
+ info MARIA handler
+ keynr Key number that was used
+ record Store key here
+
+ Last read key is in info->lastkey
+
+ NOTES
+ Used when only-keyread is wanted
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+static int _ma_put_key_in_record(register MARIA_HA *info, uint keynr,
+ uchar *record)
+{
+ reg2 uchar *key;
+ uchar *pos,*key_end;
+ reg1 HA_KEYSEG *keyseg;
+ uchar *blob_ptr;
+ DBUG_ENTER("_ma_put_key_in_record");
+
+ blob_ptr= info->lastkey_buff2; /* Place to put blob parts */
+ key= info->last_key.data; /* Key that was read */
+ key_end= key + info->last_key.data_length;
+ for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
+ {
+ if (keyseg->null_bit)
+ {
+ if (!*key++)
+ {
+ record[keyseg->null_pos]|= keyseg->null_bit;
+ continue;
+ }
+ record[keyseg->null_pos]&= ~keyseg->null_bit;
+ }
+ if (keyseg->type == HA_KEYTYPE_BIT)
+ {
+ uint length= keyseg->length;
+
+ if (keyseg->bit_length)
+ {
+ uchar bits= *key++;
+ set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
+ keyseg->bit_length);
+ length--;
+ }
+ else
+ {
+ clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
+ keyseg->bit_length);
+ }
+ memcpy(record + keyseg->start, key, length);
+ key+= length;
+ continue;
+ }
+ if (keyseg->flag & HA_SPACE_PACK)
+ {
+ uint length;
+ get_key_length(length,key);
+#ifdef CHECK_KEYS
+ if (length > keyseg->length || key+length > key_end)
+ goto err;
+#endif
+ pos= record+keyseg->start;
+ if (keyseg->type != (int) HA_KEYTYPE_NUM)
+ {
+ memcpy(pos,key,(size_t) length);
+ keyseg->charset->cset->fill(keyseg->charset,
+ (char*) pos + length,
+ keyseg->length - length,
+ ' ');
+ }
+ else
+ {
+ bfill(pos,keyseg->length-length,' ');
+ memcpy(pos+keyseg->length-length,key,(size_t) length);
+ }
+ key+=length;
+ continue;
+ }
+
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
+ {
+ uint length;
+ get_key_length(length,key);
+#ifdef CHECK_KEYS
+ if (length > keyseg->length || key+length > key_end)
+ goto err;
+#endif
+ /* Store key length */
+ if (keyseg->bit_start == 1)
+ *(uchar*) (record+keyseg->start)= (uchar) length;
+ else
+ int2store(record+keyseg->start, length);
+ /* And key data */
+ memcpy(record+keyseg->start + keyseg->bit_start, key, length);
+ key+= length;
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ uint length;
+ get_key_length(length,key);
+#ifdef CHECK_KEYS
+ if (length > keyseg->length || key+length > key_end)
+ goto err;
+#endif
+ memcpy(record+keyseg->start+keyseg->bit_start,
+ (char*) &blob_ptr,sizeof(char*));
+ memcpy(blob_ptr,key,length);
+ blob_ptr+=length;
+
+ /* The above changed info->lastkey2. Inform maria_rnext_same(). */
+ info->update&= ~HA_STATE_RNEXT_SAME;
+
+ _ma_store_blob_length(record+keyseg->start,
+ (uint) keyseg->bit_start,length);
+ key+=length;
+ }
+ else if (keyseg->flag & HA_SWAP_KEY)
+ {
+ uchar *to= record+keyseg->start+keyseg->length;
+ uchar *end= key+keyseg->length;
+#ifdef CHECK_KEYS
+ if (end > key_end)
+ goto err;
+#endif
+ do
+ {
+ *--to= *key++;
+ } while (key != end);
+ continue;
+ }
+ else
+ {
+#ifdef CHECK_KEYS
+ if (key+keyseg->length > key_end)
+ goto err;
+#endif
+ memcpy(record+keyseg->start, key, (size_t) keyseg->length);
+ key+= keyseg->length;
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1); /* Crashed row */
+} /* _ma_put_key_in_record */
+
+
+ /* Here when key reads are used */
+
+int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
+{
+ fast_ma_writeinfo(info);
+ if (filepos != HA_OFFSET_ERROR)
+ {
+ if (info->lastinx >= 0)
+ { /* Read only key */
+ if (_ma_put_key_in_record(info,(uint) info->lastinx,buf))
+ {
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ return -1;
+ }
+ info->update|= HA_STATE_AKTIV; /* We should find a record */
+ return 0;
+ }
+ my_errno=HA_ERR_WRONG_INDEX;
+ }
+ return(-1); /* Wrong data to read */
+}
+
+
+/*
+ Retrieve auto_increment info
+
+ SYNOPSIS
+ retrieve_auto_increment()
+ key Auto-increment key
+ key_type Key's type
+
+ NOTE
+ 'key' should in "record" format, that is, how it is packed in a record
+ (this matters with HA_SWAP_KEY).
+
+ IMPLEMENTATION
+ For signed columns we don't retrieve the auto increment value if it's
+ less than zero.
+*/
+
+ulonglong ma_retrieve_auto_increment(const uchar *key, uint8 key_type)
+{
+ ulonglong value= 0; /* Store unsigned values here */
+ longlong s_value= 0; /* Store signed values here */
+
+ switch (key_type) {
+ case HA_KEYTYPE_INT8:
+ s_value= (longlong) *(const char*)key;
+ break;
+ case HA_KEYTYPE_BINARY:
+ value=(ulonglong) *key;
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ s_value= (longlong) sint2korr(key);
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ value=(ulonglong) uint2korr(key);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ s_value= (longlong) sint4korr(key);
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ value=(ulonglong) uint4korr(key);
+ break;
+ case HA_KEYTYPE_INT24:
+ s_value= (longlong) sint3korr(key);
+ break;
+ case HA_KEYTYPE_UINT24:
+ value=(ulonglong) uint3korr(key);
+ break;
+ case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
+ {
+ float f_1;
+ float4get(f_1,key);
+ /* Ignore negative values */
+ value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
+ break;
+ }
+ case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
+ {
+ double f_1;
+ float8get(f_1,key);
+ /* Ignore negative values */
+ value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
+ break;
+ }
+ case HA_KEYTYPE_LONGLONG:
+ s_value= sint8korr(key);
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ value= uint8korr(key);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ value=0; /* Error */
+ break;
+ }
+
+ /*
+ The following code works becasue if s_value < 0 then value is 0
+ and if s_value == 0 then value will contain either s_value or the
+ correct value.
+ */
+ return (s_value > 0) ? (ulonglong) s_value : value;
+}
diff --git a/storage/maria/ma_key_recover.c b/storage/maria/ma_key_recover.c
new file mode 100644
index 00000000000..c4fe6613bb8
--- /dev/null
+++ b/storage/maria/ma_key_recover.c
@@ -0,0 +1,1300 @@
+/* Copyright (C) 2007 Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Redo of index */
+
+#include "maria_def.h"
+#include "ma_blockrec.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+#include "ma_rt_index.h"
+
+/****************************************************************************
+ Some helper functions used both by key page loggin and block page loggin
+****************************************************************************/
+
+/**
+ @brief Unpin all pinned pages
+
+ @fn _ma_unpin_all_pages()
+ @param info Maria handler
+ @param undo_lsn LSN for undo pages. LSN_IMPOSSIBLE if we shouldn't write
+ undo (like on duplicate key errors)
+
+ info->pinned_pages is the list of pages to unpin. Each member of the list
+ must have its 'changed' saying if the page was changed or not.
+
+ @note
+ We unpin pages in the reverse order as they where pinned; This is not
+ necessary now, but may simplify things in the future.
+
+ @return
+ @retval 0 ok
+ @retval 1 error (fatal disk error)
+*/
+
+void _ma_unpin_all_pages(MARIA_HA *info, LSN undo_lsn)
+{
+ MARIA_PINNED_PAGE *page_link= ((MARIA_PINNED_PAGE*)
+ dynamic_array_ptr(&info->pinned_pages, 0));
+ MARIA_PINNED_PAGE *pinned_page= page_link + info->pinned_pages.elements;
+ DBUG_ENTER("_ma_unpin_all_pages");
+ DBUG_PRINT("info", ("undo_lsn: %lu", (ulong) undo_lsn));
+
+ if (!info->s->now_transactional)
+ DBUG_ASSERT(undo_lsn == LSN_IMPOSSIBLE || maria_in_recovery);
+
+ while (pinned_page-- != page_link)
+ {
+ /*
+ Note this assert fails if we got a disk error or the record file
+ is corrupted, which means we should have this enabled only in debug
+ builds.
+ */
+#ifdef EXTRA_DEBUG
+ DBUG_ASSERT(!pinned_page->changed ||
+ undo_lsn != LSN_IMPOSSIBLE || !info->s->now_transactional);
+#endif
+ pagecache_unlock_by_link(info->s->pagecache, pinned_page->link,
+ pinned_page->unlock, PAGECACHE_UNPIN,
+ info->trn->rec_lsn, undo_lsn,
+ pinned_page->changed, FALSE);
+ }
+
+ info->pinned_pages.elements= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+my_bool _ma_write_clr(MARIA_HA *info, LSN undo_lsn,
+ enum translog_record_type undo_type,
+ my_bool store_checksum, ha_checksum checksum,
+ LSN *res_lsn, void *extra_msg)
+{
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE + CLR_TYPE_STORE_SIZE +
+ HA_CHECKSUM_STORE_SIZE+ KEY_NR_STORE_SIZE + PAGE_STORE_SIZE];
+ uchar *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ struct st_msg_to_write_hook_for_clr_end msg;
+ my_bool res;
+ DBUG_ENTER("_ma_write_clr");
+
+ /* undo_lsn must be first for compression to work */
+ lsn_store(log_data, undo_lsn);
+ clr_type_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE, undo_type);
+ log_pos= log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE + CLR_TYPE_STORE_SIZE;
+
+ /* Extra_msg is handled in write_hook_for_clr_end() */
+ msg.undone_record_type= undo_type;
+ msg.previous_undo_lsn= undo_lsn;
+ msg.extra_msg= extra_msg;
+ msg.checksum_delta= 0;
+
+ if (store_checksum)
+ {
+ msg.checksum_delta= checksum;
+ ha_checksum_store(log_pos, checksum);
+ log_pos+= HA_CHECKSUM_STORE_SIZE;
+ }
+ else if (undo_type == LOGREC_UNDO_KEY_INSERT_WITH_ROOT ||
+ undo_type == LOGREC_UNDO_KEY_DELETE_WITH_ROOT)
+ {
+ /* Key root changed. Store new key root */
+ struct st_msg_to_write_hook_for_undo_key *undo_msg= extra_msg;
+ pgcache_page_no_t page;
+ key_nr_store(log_pos, undo_msg->keynr);
+ page= (undo_msg->value == HA_OFFSET_ERROR ? IMPOSSIBLE_PAGE_NO :
+ undo_msg->value / info->s->block_size);
+ page_store(log_pos + KEY_NR_STORE_SIZE, page);
+ log_pos+= KEY_NR_STORE_SIZE + PAGE_STORE_SIZE;
+ }
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos - log_data);
+
+
+ /*
+ We need intern_lock mutex for calling _ma_state_info_write in the trigger.
+ We do it here to have the same sequence of mutexes locking everywhere
+ (first intern_lock then transactional log buffer lock)
+ */
+ if (undo_type == LOGREC_UNDO_BULK_INSERT)
+ pthread_mutex_lock(&info->s->intern_lock);
+
+ res= translog_write_record(res_lsn, LOGREC_CLR_END,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length,
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data + LSN_STORE_SIZE, &msg);
+ if (undo_type == LOGREC_UNDO_BULK_INSERT)
+ pthread_mutex_unlock(&info->s->intern_lock);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Sets transaction's undo_lsn, first_undo_lsn if needed
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_clr_end(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn __attribute__ ((unused)),
+ void *hook_arg)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ struct st_msg_to_write_hook_for_clr_end *msg=
+ (struct st_msg_to_write_hook_for_clr_end *)hook_arg;
+ my_bool error= FALSE;
+ DBUG_ENTER("write_hook_for_clr_end");
+ DBUG_ASSERT(trn->trid != 0);
+ trn->undo_lsn= msg->previous_undo_lsn;
+
+ switch (msg->undone_record_type) {
+ case LOGREC_UNDO_ROW_DELETE:
+ share->state.state.records++;
+ share->state.state.checksum+= msg->checksum_delta;
+ break;
+ case LOGREC_UNDO_ROW_INSERT:
+ share->state.state.records--;
+ share->state.state.checksum+= msg->checksum_delta;
+ break;
+ case LOGREC_UNDO_ROW_UPDATE:
+ share->state.state.checksum+= msg->checksum_delta;
+ break;
+ case LOGREC_UNDO_KEY_INSERT_WITH_ROOT:
+ case LOGREC_UNDO_KEY_DELETE_WITH_ROOT:
+ {
+ /* Update key root */
+ struct st_msg_to_write_hook_for_undo_key *extra_msg=
+ (struct st_msg_to_write_hook_for_undo_key *) msg->extra_msg;
+ *extra_msg->root= extra_msg->value;
+ break;
+ }
+ case LOGREC_UNDO_KEY_INSERT:
+ case LOGREC_UNDO_KEY_DELETE:
+ break;
+ case LOGREC_UNDO_BULK_INSERT:
+ safe_mutex_assert_owner(&share->intern_lock);
+ error= (maria_enable_indexes(tbl_info) ||
+ /* we enabled indices, need '2' below */
+ _ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO));
+ /* no need for _ma_reset_status(): REDO_DELETE_ALL is just before us */
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ if (trn->undo_lsn == LSN_IMPOSSIBLE) /* has fully rolled back */
+ trn->first_undo_lsn= LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
+ DBUG_RETURN(error);
+}
+
+
+/**
+ @brief write hook for undo key
+*/
+
+my_bool write_hook_for_undo_key(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ struct st_msg_to_write_hook_for_undo_key *msg=
+ (struct st_msg_to_write_hook_for_undo_key *) hook_arg;
+
+ *msg->root= msg->value;
+ _ma_fast_unlock_key_del(tbl_info);
+ return write_hook_for_undo(type, trn, tbl_info, lsn, 0);
+}
+
+
+/**
+ Updates "auto_increment" and calls the generic UNDO_KEY hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_key_insert(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ struct st_msg_to_write_hook_for_undo_key *msg=
+ (struct st_msg_to_write_hook_for_undo_key *) hook_arg;
+ MARIA_SHARE *share= tbl_info->s;
+ if (msg->auto_increment > 0)
+ {
+ /*
+ Only reason to set it here is to have a mutex protect from checkpoint
+ reading at the same time (would see a corrupted value).
+
+ The purpose of the following code is to set auto_increment if the row
+ has a with auto_increment value higher than the current one. We also
+ want to be able to restore the old value, in case of rollback,
+ if no one else has tried to set the value.
+
+ The logic used is that we only restore the auto_increment value if
+ tbl_info->last_auto_increment == share->last_auto_increment
+ when it's time to do the rollback.
+ */
+ DBUG_PRINT("info",("auto_inc: %lu new auto_inc: %lu",
+ (ulong)share->state.auto_increment,
+ (ulong)msg->auto_increment));
+ if (share->state.auto_increment < msg->auto_increment)
+ {
+ /* Remember the original value, in case of rollback */
+ tbl_info->last_auto_increment= share->last_auto_increment=
+ share->state.auto_increment;
+ share->state.auto_increment= msg->auto_increment;
+ }
+ else
+ {
+ /*
+ If the current value would have affected the original auto_increment
+ value, set it to an impossible value so that it's not restored on
+ rollback
+ */
+ if (msg->auto_increment > share->last_auto_increment)
+ share->last_auto_increment= ~(ulonglong) 0;
+ }
+ }
+ return write_hook_for_undo_key(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/**
+ @brief Updates "share->auto_increment" in case of abort and calls
+ generic UNDO_KEY hook
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_undo_key_delete(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg)
+{
+ struct st_msg_to_write_hook_for_undo_key *msg=
+ (struct st_msg_to_write_hook_for_undo_key *) hook_arg;
+ MARIA_SHARE *share= tbl_info->s;
+ if (msg->auto_increment > 0) /* If auto increment key */
+ {
+ /* Restore auto increment if no one has changed it in between */
+ if (share->last_auto_increment == tbl_info->last_auto_increment &&
+ tbl_info->last_auto_increment != ~(ulonglong) 0)
+ share->state.auto_increment= tbl_info->last_auto_increment;
+ }
+ return write_hook_for_undo_key(type, trn, tbl_info, lsn, hook_arg);
+}
+
+
+/*****************************************************************************
+ Functions for logging of key page changes
+*****************************************************************************/
+
+/**
+ @brief
+ Write log entry for page that has got data added or deleted at start of page
+*/
+
+my_bool _ma_log_prefix(MARIA_HA *info, my_off_t page,
+ uchar *buff, uint changed_length,
+ int move_length)
+{
+ uint translog_parts;
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 7 + 7 + 2], *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
+ DBUG_ENTER("_ma_log_prefix");
+ DBUG_PRINT("enter", ("page: %lu changed_length: %u move_length: %d",
+ (ulong) page, changed_length, move_length));
+
+ page/= info->s->block_size;
+ log_pos= log_data + FILEID_STORE_SIZE;
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+
+ /* Store keypage_flag */
+ *log_pos++= KEY_OP_SET_PAGEFLAG;
+ *log_pos++= buff[KEYPAGE_TRANSFLAG_OFFSET];
+
+ if (move_length < 0)
+ {
+ /* Delete prefix */
+ log_pos[0]= KEY_OP_DEL_PREFIX;
+ int2store(log_pos+1, -move_length);
+ log_pos+= 3;
+ if (changed_length)
+ {
+ /*
+ We don't need a KEY_OP_OFFSET as KEY_OP_DEL_PREFIX has an implicit
+ offset
+ */
+ log_pos[0]= KEY_OP_CHANGE;
+ int2store(log_pos+1, changed_length);
+ log_pos+= 3;
+ }
+ }
+ else
+ {
+ /* Add prefix */
+ DBUG_ASSERT(changed_length >0 && (int) changed_length >= move_length);
+ log_pos[0]= KEY_OP_ADD_PREFIX;
+ int2store(log_pos+1, move_length);
+ int2store(log_pos+3, changed_length);
+ log_pos+= 5;
+ }
+
+ translog_parts= 1;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
+ log_data);
+ if (changed_length)
+ {
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (buff +
+ info->s->keypage_header);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= changed_length;
+ translog_parts= 2;
+ }
+
+#ifdef EXTRA_DEBUG_KEY_CHANGES
+ {
+ int page_length= _ma_get_page_used(info->s, buff);
+ ha_checksum crc;
+ crc= my_checksum(0, buff + LSN_STORE_SIZE, page_length - LSN_STORE_SIZE);
+ log_pos[0]= KEY_OP_CHECK;
+ int2store(log_pos+1, page_length);
+ int4store(log_pos+3, crc);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= log_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= 7;
+ changed_length+= 7;
+ translog_parts++;
+ }
+#endif
+
+ DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + changed_length,
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL));
+}
+
+
+/**
+ @brief
+ Write log entry for page that has got data added or deleted at end of page
+*/
+
+my_bool _ma_log_suffix(MARIA_HA *info, my_off_t page,
+ uchar *buff, uint org_length, uint new_length)
+{
+ LSN lsn;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 10 + 7 + 2], *log_pos;
+ int diff;
+ uint translog_parts, extra_length;
+ DBUG_ENTER("_ma_log_suffix");
+ DBUG_PRINT("enter", ("page: %lu org_length: %u new_length: %u",
+ (ulong) page, org_length, new_length));
+
+ page/= info->s->block_size;
+
+ log_pos= log_data + FILEID_STORE_SIZE;
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+
+ /* Store keypage_flag */
+ *log_pos++= KEY_OP_SET_PAGEFLAG;
+ *log_pos++= buff[KEYPAGE_TRANSFLAG_OFFSET];
+
+ if ((diff= (int) (new_length - org_length)) < 0)
+ {
+ log_pos[0]= KEY_OP_DEL_SUFFIX;
+ int2store(log_pos+1, -diff);
+ log_pos+= 3;
+ translog_parts= 1;
+ extra_length= 0;
+ }
+ else
+ {
+ log_pos[0]= KEY_OP_ADD_SUFFIX;
+ int2store(log_pos+1, diff);
+ log_pos+= 3;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= buff + org_length;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= (uint) diff;
+ translog_parts= 2;
+ extra_length= (uint) diff;
+ }
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
+ log_data);
+
+#ifdef EXTRA_DEBUG_KEY_CHANGES
+ {
+ ha_checksum crc;
+ crc= my_checksum(0, buff + LSN_STORE_SIZE, new_length - LSN_STORE_SIZE);
+ log_pos[0]= KEY_OP_CHECK;
+ int2store(log_pos+1, new_length);
+ int4store(log_pos+3, crc);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= log_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= 7;
+ extra_length+= 7;
+ translog_parts++;
+ }
+#endif
+
+ DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + extra_length,
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL));
+}
+
+
+/**
+ @brief Log that a key was added to the page
+
+ @param buff Page buffer
+ @param buff_length Original length of buff (before key was added)
+
+ @note
+ If handle_overflow is set, then we have to protect against
+ logging changes that is outside of the page.
+ This may happen during underflow() handling where the buffer
+ in memory temporary contains more data than block_size
+*/
+
+my_bool _ma_log_add(MARIA_HA *info, my_off_t page, uchar *buff,
+ uint buff_length, uchar *key_pos,
+ uint changed_length, int move_length,
+ my_bool handle_overflow __attribute__ ((unused)))
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 3 + 3 + 3 + 3 + 7 + 2];
+ uchar *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
+ uint offset= (uint) (key_pos - buff);
+ uint page_length= info->s->block_size - KEYPAGE_CHECKSUM_SIZE;
+ uint translog_parts;
+ DBUG_ENTER("_ma_log_add");
+ DBUG_PRINT("enter", ("page: %lu org_page_length: %u changed_length: %u "
+ "move_length: %d",
+ (ulong) page, buff_length, changed_length,
+ move_length));
+ DBUG_ASSERT(info->s->now_transactional);
+
+ /*
+ Write REDO entry that contains the logical operations we need
+ to do the page
+ */
+ log_pos= log_data + FILEID_STORE_SIZE;
+ page/= info->s->block_size;
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+
+ /* Store keypage_flag */
+ *log_pos++= KEY_OP_SET_PAGEFLAG;
+ *log_pos++= buff[KEYPAGE_TRANSFLAG_OFFSET];
+
+ if (buff_length + move_length > page_length)
+ {
+ /*
+ Overflow. Cut either key or data from page end so that key fits
+ The code that splits the too big page will ignore logging any
+ data over page_length
+ */
+ DBUG_ASSERT(handle_overflow);
+ if (offset + changed_length > page_length)
+ {
+ changed_length= page_length - offset;
+ move_length= 0;
+ }
+ else
+ {
+ uint diff= buff_length + move_length - page_length;
+ log_pos[0]= KEY_OP_DEL_SUFFIX;
+ int2store(log_pos+1, diff);
+ log_pos+= 3;
+ buff_length= page_length - move_length;
+ }
+ }
+
+ if (offset == buff_length)
+ log_pos[0]= KEY_OP_ADD_SUFFIX;
+ else
+ {
+ log_pos[0]= KEY_OP_OFFSET;
+ int2store(log_pos+1, offset);
+ log_pos+= 3;
+ if (move_length)
+ {
+ log_pos[0]= KEY_OP_SHIFT;
+ int2store(log_pos+1, move_length);
+ log_pos+= 3;
+ }
+ log_pos[0]= KEY_OP_CHANGE;
+ }
+ int2store(log_pos+1, changed_length);
+ log_pos+= 3;
+ translog_parts= 2;
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
+ log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= changed_length;
+
+#ifdef EXTRA_DEBUG_KEY_CHANGES
+ {
+ MARIA_SHARE *share= info->s;
+ ha_checksum crc;
+ uint save_page_length= _ma_get_page_used(share, buff);
+ uint new_length= buff_length + move_length;
+ _ma_store_page_used(share, buff, new_length);
+ crc= my_checksum(0, buff + LSN_STORE_SIZE, new_length - LSN_STORE_SIZE);
+ log_pos[0]= KEY_OP_CHECK;
+ int2store(log_pos+1, new_length);
+ int4store(log_pos+3, crc);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= log_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= 7;
+ changed_length+= 7;
+ translog_parts++;
+ _ma_store_page_used(share, buff, save_page_length);
+ }
+#endif
+
+ if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length +
+ changed_length,
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+
+/****************************************************************************
+ Redo of key pages
+****************************************************************************/
+
+/**
+ @brief Apply LOGREC_REDO_INDEX_NEW_PAGE
+
+ @param info Maria handler
+ @param header Header (without FILEID)
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+uint _ma_apply_redo_index_new_page(MARIA_HA *info, LSN lsn,
+ const uchar *header, uint length)
+{
+ pgcache_page_no_t root_page= page_korr(header);
+ pgcache_page_no_t free_page= page_korr(header + PAGE_STORE_SIZE);
+ uint key_nr= key_nr_korr(header + PAGE_STORE_SIZE * 2);
+ my_bool page_type_flag= header[PAGE_STORE_SIZE * 2 + KEY_NR_STORE_SIZE];
+ enum pagecache_page_lock unlock_method;
+ enum pagecache_page_pin unpin_method;
+ MARIA_PINNED_PAGE page_link;
+ my_off_t file_size;
+ uchar *buff;
+ uint result;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_apply_redo_index_new_page");
+ DBUG_PRINT("enter", ("root_page: %lu free_page: %lu",
+ (ulong) root_page, (ulong) free_page));
+
+ /* Set header to point at key data */
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_OPTIMIZED_KEYS |
+ STATE_NOT_SORTED_PAGES | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ header+= PAGE_STORE_SIZE * 2 + KEY_NR_STORE_SIZE + 1;
+ length-= PAGE_STORE_SIZE * 2 + KEY_NR_STORE_SIZE + 1;
+
+ file_size= (my_off_t) (root_page + 1) * share->block_size;
+ if (cmp_translog_addr(lsn, share->state.is_of_horizon) >= 0)
+ {
+ /* free_page is 0 if we shouldn't set key_del */
+ if (free_page)
+ {
+ if (free_page != IMPOSSIBLE_PAGE_NO)
+ share->state.key_del= (my_off_t) free_page * share->block_size;
+ else
+ share->state.key_del= HA_OFFSET_ERROR;
+ }
+ if (page_type_flag) /* root page */
+ share->state.key_root[key_nr]= file_size - share->block_size;
+ }
+
+ if (file_size > share->state.state.key_file_length)
+ {
+ share->state.state.key_file_length= file_size;
+ buff= info->keyread_buff;
+ info->keyread_buff_used= 1;
+ unlock_method= PAGECACHE_LOCK_WRITE;
+ unpin_method= PAGECACHE_PIN;
+ }
+ else
+ {
+ if (!(buff= pagecache_read(share->pagecache, &share->kfile,
+ root_page, 0, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
+ {
+ if (my_errno != HA_ERR_FILE_TOO_SHORT &&
+ my_errno != HA_ERR_WRONG_CRC)
+ {
+ result= 1;
+ goto err;
+ }
+ buff= pagecache_block_link_to_buffer(page_link.link);
+ }
+ else if (lsn_korr(buff) >= lsn)
+ {
+ /* Already applied */
+ DBUG_PRINT("info", ("Page is up to date, skipping redo"));
+ result= 0;
+ goto err;
+ }
+ unlock_method= PAGECACHE_LOCK_LEFT_WRITELOCKED;
+ unpin_method= PAGECACHE_PIN_LEFT_PINNED;
+ }
+
+ /* Write modified page */
+ bzero(buff, LSN_STORE_SIZE);
+ memcpy(buff + LSN_STORE_SIZE, header, length);
+ bzero(buff + LSN_STORE_SIZE + length,
+ share->block_size - LSN_STORE_SIZE - KEYPAGE_CHECKSUM_SIZE - length);
+ bfill(buff + share->block_size - KEYPAGE_CHECKSUM_SIZE,
+ KEYPAGE_CHECKSUM_SIZE, (uchar) 255);
+
+ result= 0;
+ if (unlock_method == PAGECACHE_LOCK_WRITE &&
+ pagecache_write(share->pagecache,
+ &share->kfile, root_page, 0,
+ buff, PAGECACHE_PLAIN_PAGE,
+ unlock_method, unpin_method,
+ PAGECACHE_WRITE_DELAY, &page_link.link,
+ LSN_IMPOSSIBLE))
+ result= 1;
+
+ /* Mark page to be unlocked and written at _ma_unpin_all_pages() */
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ DBUG_RETURN(result);
+
+err:
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ DBUG_RETURN(result);
+}
+
+
+/**
+ @brief Apply LOGREC_REDO_INDEX_FREE_PAGE
+
+ @param info Maria handler
+ @param header Header (without FILEID)
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+uint _ma_apply_redo_index_free_page(MARIA_HA *info,
+ LSN lsn,
+ const uchar *header)
+{
+ pgcache_page_no_t page= page_korr(header);
+ pgcache_page_no_t free_page= page_korr(header + PAGE_STORE_SIZE);
+ my_off_t old_link;
+ MARIA_PINNED_PAGE page_link;
+ MARIA_SHARE *share= info->s;
+ uchar *buff;
+ int result;
+ DBUG_ENTER("_ma_apply_redo_index_free_page");
+ DBUG_PRINT("enter", ("page: %lu free_page: %lu",
+ (ulong) page, (ulong) free_page));
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_OPTIMIZED_KEYS |
+ STATE_NOT_SORTED_PAGES | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+
+ if (cmp_translog_addr(lsn, share->state.is_of_horizon) >= 0)
+ share->state.key_del= (my_off_t) page * share->block_size;
+
+ old_link= ((free_page != IMPOSSIBLE_PAGE_NO) ?
+ (my_off_t) free_page * share->block_size :
+ HA_OFFSET_ERROR);
+ if (!(buff= pagecache_read(share->pagecache, &share->kfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
+ {
+ result= (uint) my_errno;
+ goto err;
+ }
+ if (lsn_korr(buff) >= lsn)
+ {
+ /* Already applied */
+ result= 0;
+ goto err;
+ }
+ /* Free page */
+ bzero(buff + LSN_STORE_SIZE, share->keypage_header - LSN_STORE_SIZE);
+ _ma_store_keynr(share, buff, (uchar) MARIA_DELETE_KEY_NR);
+ _ma_store_page_used(share, buff, share->keypage_header + 8);
+ mi_sizestore(buff + share->keypage_header, old_link);
+
+#ifdef IDENTICAL_PAGES_AFTER_RECOVERY
+ {
+ bzero(buff + share->keypage_header + 8,
+ share->block_size - share->keypage_header - 8 -
+ KEYPAGE_CHECKSUM_SIZE);
+ }
+#endif
+
+ /* Mark page to be unlocked and written at _ma_unpin_all_pages() */
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ DBUG_RETURN(0);
+
+err:
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ DBUG_RETURN(result);
+}
+
+
+/**
+ @brief Apply LOGREC_REDO_INDEX
+
+ @fn ma_apply_redo_index()
+ @param info Maria handler
+ @param header Header (without FILEID)
+
+ @notes
+ Data for this part is a set of logical instructions of how to
+ construct the key page.
+
+ Information of the layout of the components for REDO_INDEX:
+
+ Name Parameters (in byte) Information
+ KEY_OP_OFFSET 2 Set position for next operations
+ KEY_OP_SHIFT 2 (signed int) How much to shift down or up
+ KEY_OP_CHANGE 2 length, data Data to replace at 'pos'
+ KEY_OP_ADD_PREFIX 2 move-length How much data should be moved up
+ 2 change-length Data to be replaced at page start
+ KEY_OP_DEL_PREFIX 2 length Bytes to be deleted at page start
+ KEY_OP_ADD_SUFFIX 2 length, data Add data to end of page
+ KEY_OP_DEL_SUFFIX 2 length Reduce page length with this
+ Sets position to start of page
+ KEY_OP_CHECK 6 page_length[2},CRC Used only when debugging
+ KEY_OP_COMPACT_PAGE 6 transid
+ KEY_OP_SET_PAGEFLAG 1 flag for page
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+long my_counter= 0;
+
+uint _ma_apply_redo_index(MARIA_HA *info,
+ LSN lsn, const uchar *header, uint head_length)
+{
+ MARIA_SHARE *share= info->s;
+ pgcache_page_no_t page= page_korr(header);
+ MARIA_PINNED_PAGE page_link;
+ uchar *buff;
+ const uchar *header_end= header + head_length;
+ uint page_offset= 0;
+ uint nod_flag, page_length, keypage_header;
+ int result;
+ uint org_page_length;
+ DBUG_ENTER("_ma_apply_redo_index");
+ DBUG_PRINT("enter", ("page: %lu", (ulong) page));
+
+ /* Set header to point at key data */
+ header+= PAGE_STORE_SIZE;
+
+ if (!(buff= pagecache_read(share->pagecache, &share->kfile,
+ page, 0, 0,
+ PAGECACHE_PLAIN_PAGE, PAGECACHE_LOCK_WRITE,
+ &page_link.link)))
+ {
+ result= 1;
+ goto err;
+ }
+ if (lsn_korr(buff) >= lsn)
+ {
+ /* Already applied */
+ DBUG_PRINT("info", ("Page is up to date, skipping redo"));
+ result= 0;
+ goto err;
+ }
+
+ _ma_get_used_and_nod(share, buff, page_length, nod_flag);
+ keypage_header= share->keypage_header;
+ org_page_length= page_length;
+ DBUG_PRINT("redo", ("page_length: %u", page_length));
+
+ /* Apply modifications to page */
+ do
+ {
+ switch ((enum en_key_op) (*header++)) {
+ case KEY_OP_OFFSET: /* 1 */
+ page_offset= uint2korr(header);
+ header+= 2;
+ DBUG_PRINT("redo", ("key_op_offset: %u", page_offset));
+ DBUG_ASSERT(page_offset >= keypage_header && page_offset <= page_length);
+ break;
+ case KEY_OP_SHIFT: /* 2 */
+ {
+ int length= sint2korr(header);
+ header+= 2;
+ DBUG_PRINT("redo", ("key_op_shift: %d", length));
+ DBUG_ASSERT(page_offset != 0 && page_offset <= page_length &&
+ page_length + length < share->block_size);
+
+ if (length < 0)
+ bmove(buff + page_offset, buff + page_offset - length,
+ page_length - page_offset + length);
+ else
+ bmove_upp(buff + page_length + length, buff + page_length,
+ page_length - page_offset);
+ page_length+= length;
+ break;
+ }
+ case KEY_OP_CHANGE: /* 3 */
+ {
+ uint length= uint2korr(header);
+ DBUG_PRINT("redo", ("key_op_change: %u", length));
+ DBUG_ASSERT(page_offset != 0 && page_offset + length <= page_length);
+
+ memcpy(buff + page_offset, header + 2 , length);
+ header+= 2 + length;
+ break;
+ }
+ case KEY_OP_ADD_PREFIX: /* 4 */
+ {
+ uint insert_length= uint2korr(header);
+ uint changed_length= uint2korr(header+2);
+ DBUG_PRINT("redo", ("key_op_add_prefix: %u %u",
+ insert_length, changed_length));
+
+ DBUG_ASSERT(insert_length <= changed_length &&
+ page_length + changed_length <= share->block_size);
+
+ bmove_upp(buff + page_length + insert_length, buff + page_length,
+ page_length - keypage_header);
+ memcpy(buff + keypage_header, header + 4 , changed_length);
+ header+= 4 + changed_length;
+ page_length+= insert_length;
+ break;
+ }
+ case KEY_OP_DEL_PREFIX: /* 5 */
+ {
+ uint length= uint2korr(header);
+ header+= 2;
+ DBUG_PRINT("redo", ("key_op_del_prefix: %u", length));
+ DBUG_ASSERT(length <= page_length - keypage_header);
+
+ bmove(buff + keypage_header, buff + keypage_header +
+ length, page_length - keypage_header - length);
+ page_length-= length;
+
+ page_offset= keypage_header; /* Prepare for change */
+ break;
+ }
+ case KEY_OP_ADD_SUFFIX: /* 6 */
+ {
+ uint insert_length= uint2korr(header);
+ DBUG_PRINT("redo", ("key_op_add_prefix: %u", insert_length));
+ DBUG_ASSERT(page_length + insert_length <= share->block_size);
+ memcpy(buff + page_length, header+2, insert_length);
+
+ page_length+= insert_length;
+ header+= 2 + insert_length;
+ break;
+ }
+ case KEY_OP_DEL_SUFFIX: /* 7 */
+ {
+ uint del_length= uint2korr(header);
+ header+= 2;
+ DBUG_PRINT("redo", ("key_op_del_suffix: %u", del_length));
+ DBUG_ASSERT(page_length - del_length >= keypage_header);
+ page_length-= del_length;
+ break;
+ }
+ case KEY_OP_CHECK: /* 8 */
+ {
+#ifdef EXTRA_DEBUG_KEY_CHANGES
+ uint check_page_length;
+ ha_checksum crc;
+ check_page_length= uint2korr(header);
+ crc= uint4korr(header+2);
+ _ma_store_page_used(share, buff, page_length);
+ DBUG_ASSERT(check_page_length == page_length);
+ if (crc != (uint32) my_checksum(0, buff + LSN_STORE_SIZE,
+ page_length - LSN_STORE_SIZE))
+ {
+ DBUG_PRINT("error", ("page_length %u",page_length));
+ DBUG_DUMP("KEY_OP_CHECK bad page", buff, share->block_size);
+ DBUG_ASSERT("crc" == "failure in REDO_INDEX");
+ }
+#endif
+ DBUG_PRINT("redo", ("key_op_check"));
+ header+= 6;
+ break;
+ }
+ case KEY_OP_MULTI_COPY: /* 9 */
+ {
+ /*
+ List of fixed-len memcpy() operations with their source located inside
+ the page. The log record's piece looks like:
+ first the length 'full_length' to be used by memcpy()
+ then the number of bytes used by the list of (to,from) pairs
+ then the (to,from) pairs, so we do:
+ for (t,f) in [list of (to,from) pairs]:
+ memcpy(t, f, full_length).
+ */
+ uint full_length, log_memcpy_length;
+ const uchar *log_memcpy_end;
+
+ DBUG_PRINT("redo", ("key_op_multi_copy"));
+ full_length= uint2korr(header);
+ header+= 2;
+ log_memcpy_length= uint2korr(header);
+ header+= 2;
+ log_memcpy_end= header + log_memcpy_length;
+ DBUG_ASSERT(full_length < share->block_size);
+ while (header < log_memcpy_end)
+ {
+ uint to, from;
+ to= uint2korr(header);
+ header+= 2;
+ from= uint2korr(header);
+ header+= 2;
+ /* "from" is a place in the existing page */
+ DBUG_ASSERT(max(from, to) < share->block_size);
+ memcpy(buff + to, buff + from, full_length);
+ }
+ break;
+ }
+ case KEY_OP_SET_PAGEFLAG:
+ DBUG_PRINT("redo", ("key_op_set_pageflag"));
+ buff[KEYPAGE_TRANSFLAG_OFFSET]= *header++;
+ break;
+ case KEY_OP_COMPACT_PAGE:
+ {
+ TrID transid= transid_korr(header);
+ uint keynr= _ma_get_keynr(share, buff);
+
+ DBUG_PRINT("redo", ("key_op_compact_page"));
+ header+= TRANSID_SIZE;
+ if (_ma_compact_keypage(info, share->keyinfo + keynr, (my_off_t) 0,
+ buff, transid))
+ {
+ result= 1;
+ goto err;
+ }
+ }
+ case KEY_OP_NONE:
+ default:
+ DBUG_ASSERT(0);
+ result= 1;
+ goto err;
+ }
+ } while (header < header_end);
+ DBUG_ASSERT(header == header_end);
+
+ /* Write modified page */
+ _ma_store_page_used(share, buff, page_length);
+
+ /*
+ Clean old stuff up. Gives us better compression of we archive things
+ and makes things easer to debug
+ */
+ if (page_length < org_page_length)
+ bzero(buff + page_length, org_page_length-page_length);
+
+ /* Mark page to be unlocked and written at _ma_unpin_all_pages() */
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ DBUG_RETURN(0);
+
+err:
+ pagecache_unlock_by_link(share->pagecache, page_link.link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, LSN_IMPOSSIBLE,
+ LSN_IMPOSSIBLE, 0, FALSE);
+ if (result)
+ _ma_mark_file_crashed(share);
+ DBUG_RETURN(result);
+}
+
+
+/****************************************************************************
+ Undo of key block changes
+****************************************************************************/
+
+/**
+ @brief Undo of insert of key (ie, delete the inserted key)
+*/
+
+my_bool _ma_apply_undo_key_insert(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header, uint length)
+{
+ LSN lsn;
+ my_bool res;
+ uint keynr;
+ uchar key_buff[MARIA_MAX_KEY_BUFF];
+ MARIA_SHARE *share= info->s;
+ MARIA_KEY key;
+ my_off_t new_root;
+ struct st_msg_to_write_hook_for_undo_key msg;
+ DBUG_ENTER("_ma_apply_undo_key_insert");
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_OPTIMIZED_KEYS |
+ STATE_NOT_SORTED_PAGES | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+ keynr= key_nr_korr(header);
+ length-= KEY_NR_STORE_SIZE;
+
+ /* We have to copy key as _ma_ck_real_delete() may change it */
+ memcpy(key_buff, header + KEY_NR_STORE_SIZE, length);
+ DBUG_DUMP("key_buff", key_buff, length);
+
+ new_root= share->state.key_root[keynr];
+ /*
+ Change the key to an internal structure.
+ It's safe to have SEARCH_USER_KEY_HAS_TRANSID even if there isn't
+ a transaction id, as ha_key_cmp() will stop comparison when key length
+ is reached.
+ For index with transid flag, the ref_length of the key is not correct.
+ This should however be safe as long as this key is only used for
+ comparsion against other keys (not for packing or for read-next etc as
+ in this case we use data_length + ref_length, which is correct.
+ */
+ key.keyinfo= share->keyinfo + keynr;
+ key.data= key_buff;
+ key.data_length= length - share->rec_reflength;
+ key.ref_length= share->rec_reflength;
+ key.flag= SEARCH_USER_KEY_HAS_TRANSID;
+
+ res= ((share->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE) ?
+ maria_rtree_real_delete(info, &key, &new_root) :
+ _ma_ck_real_delete(info, &key, &new_root));
+ if (res)
+ _ma_mark_file_crashed(share);
+ msg.root= &share->state.key_root[keynr];
+ msg.value= new_root;
+ msg.keynr= keynr;
+
+ if (_ma_write_clr(info, undo_lsn, *msg.root == msg.value ?
+ LOGREC_UNDO_KEY_INSERT : LOGREC_UNDO_KEY_INSERT_WITH_ROOT,
+ 0, 0, &lsn, (void*) &msg))
+ res= 1;
+
+ _ma_fast_unlock_key_del(info);
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Undo of delete of key (ie, insert the deleted key)
+
+ @param with_root If the UNDO is UNDO_KEY_DELETE_WITH_ROOT
+*/
+
+my_bool _ma_apply_undo_key_delete(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header, uint length,
+ my_bool with_root)
+{
+ LSN lsn;
+ my_bool res;
+ uint keynr, skip_bytes;
+ uchar key_buff[MARIA_MAX_KEY_BUFF];
+ MARIA_SHARE *share= info->s;
+ my_off_t new_root;
+ struct st_msg_to_write_hook_for_undo_key msg;
+ MARIA_KEY key;
+ DBUG_ENTER("_ma_apply_undo_key_delete");
+
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_OPTIMIZED_KEYS |
+ STATE_NOT_SORTED_PAGES | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+ keynr= key_nr_korr(header);
+ skip_bytes= KEY_NR_STORE_SIZE + (with_root ? PAGE_STORE_SIZE : 0);
+ header+= skip_bytes;
+ length-= skip_bytes;
+
+ /* We have to copy key as _ma_ck_real_write_btree() may change it */
+ memcpy(key_buff, header, length);
+ DBUG_DUMP("key", key_buff, length);
+
+ key.keyinfo= share->keyinfo + keynr;
+ key.data= key_buff;
+ key.data_length= length - share->rec_reflength;
+ key.ref_length= share->rec_reflength;
+ key.flag= SEARCH_USER_KEY_HAS_TRANSID;
+
+ new_root= share->state.key_root[keynr];
+ res= (share->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE) ?
+ maria_rtree_insert_level(info, &key, -1, &new_root) :
+ _ma_ck_real_write_btree(info, &key, &new_root,
+ share->keyinfo[keynr].write_comp_flag |
+ key.flag);
+ if (res)
+ _ma_mark_file_crashed(share);
+
+ msg.root= &share->state.key_root[keynr];
+ msg.value= new_root;
+ msg.keynr= keynr;
+ if (_ma_write_clr(info, undo_lsn,
+ *msg.root == msg.value ?
+ LOGREC_UNDO_KEY_DELETE : LOGREC_UNDO_KEY_DELETE_WITH_ROOT,
+ 0, 0, &lsn,
+ (void*) &msg))
+ res= 1;
+
+ _ma_fast_unlock_key_del(info);
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+ DBUG_RETURN(res);
+}
+
+
+/****************************************************************************
+ Handle some local variables
+****************************************************************************/
+
+/**
+ @brief lock key_del for other threads usage
+
+ @fn _ma_lock_key_del()
+ @param info Maria handler
+ @param insert_at_end Set to 1 if we are doing an insert
+
+ @note
+ To allow higher concurrency in the common case where we do inserts
+ and we don't have any linked blocks we do the following:
+ - Mark in info->key_del_used that we are not using key_del
+ - Return at once (without marking key_del as used)
+
+ This is safe as we in this case don't write key_del_current into
+ the redo log and during recover we are not updating key_del.
+
+ @retval 1 Use page at end of file
+ @retval 0 Use page at share->key_del_current
+*/
+
+my_bool _ma_lock_key_del(MARIA_HA *info, my_bool insert_at_end)
+{
+ MARIA_SHARE *share= info->s;
+
+ /*
+ info->key_del_used is 0 initially.
+ If the caller needs a block (_ma_new()), we look at the free list:
+ - looks empty? then caller will create a new block at end of file and
+ remember (through info->key_del_used==2) that it will not change
+ state.key_del and does not need to wake up waiters as nobody will wait for
+ it.
+ - non-empty? then we wait for other users of the state.key_del list to
+ have finished, then we lock this list (through share->key_del_used==1)
+ because we need to prevent some other thread to also read state.key_del
+ and use the same page as ours. We remember through info->key_del_used==1
+ that we will have to set state.key_del at unlock time and wake up
+ waiters.
+ If the caller wants to free a block (_ma_dispose()), "empty" and
+ "non-empty" are treated as "non-empty" is treated above.
+ When we are ready to unlock, we copy share->key_del_current into
+ state.key_del. Unlocking happens when writing the UNDO log record, that
+ can make a long lock time.
+ Why we wrote "*looks* empty": because we are looking at state.key_del
+ which may be slightly old (share->key_del_current may be more recent and
+ exact): when we want a new page, we tolerate to treat "there was no free
+ page 1 millisecond ago" as "there is no free page". It's ok to non-pop
+ (_ma_new(), page will be found later anyway) but it's not ok to non-push
+ (_ma_dispose(), page would be lost).
+ When we leave this function, info->key_del_used is always 1 or 2.
+ */
+ if (info->key_del_used != 1)
+ {
+ pthread_mutex_lock(&share->key_del_lock);
+ if (share->state.key_del == HA_OFFSET_ERROR && insert_at_end)
+ {
+ pthread_mutex_unlock(&share->key_del_lock);
+ info->key_del_used= 2; /* insert-with-append */
+ return 1;
+ }
+#ifdef THREAD
+ while (share->key_del_used)
+ pthread_cond_wait(&share->key_del_cond, &share->key_del_lock);
+#endif
+ info->key_del_used= 1;
+ share->key_del_used= 1;
+ share->key_del_current= share->state.key_del;
+ pthread_mutex_unlock(&share->key_del_lock);
+ }
+ return share->key_del_current == HA_OFFSET_ERROR;
+}
+
+
+/**
+ @brief copy changes to key_del and unlock it
+
+ @notes
+ In case of many threads using the maria table, we always have a lock
+ on the translog when comming here.
+*/
+
+void _ma_unlock_key_del(MARIA_HA *info)
+{
+ DBUG_ASSERT(info->key_del_used);
+ if (info->key_del_used == 1) /* Ignore insert-with-append */
+ {
+ MARIA_SHARE *share= info->s;
+ pthread_mutex_lock(&share->key_del_lock);
+ share->key_del_used= 0;
+ share->state.key_del= share->key_del_current;
+ pthread_mutex_unlock(&share->key_del_lock);
+ pthread_cond_signal(&share->key_del_cond);
+ }
+ info->key_del_used= 0;
+}
diff --git a/storage/maria/ma_key_recover.h b/storage/maria/ma_key_recover.h
new file mode 100644
index 00000000000..2366d53f143
--- /dev/null
+++ b/storage/maria/ma_key_recover.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 2007 Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ When we have finished the write/update/delete of a row, we have cleanups to
+ do. For now it is signalling to Checkpoint that all dirtied pages have
+ their rec_lsn set and page LSN set (_ma_unpin_all_pages() has been called),
+ and that bitmap pages are correct (_ma_bitmap_release_unused() has been
+ called).
+*/
+
+/* Struct for clr_end */
+
+struct st_msg_to_write_hook_for_clr_end
+{
+ LSN previous_undo_lsn;
+ enum translog_record_type undone_record_type;
+ ha_checksum checksum_delta;
+ void *extra_msg;
+};
+
+struct st_msg_to_write_hook_for_undo_key
+{
+ my_off_t *root;
+ my_off_t value;
+ uint keynr;
+ ulonglong auto_increment;
+};
+
+
+/* Function definitions for some redo functions */
+
+my_bool _ma_write_clr(MARIA_HA *info, LSN undo_lsn,
+ enum translog_record_type undo_type,
+ my_bool store_checksum, ha_checksum checksum,
+ LSN *res_lsn, void *extra_msg);
+int _ma_write_undo_key_insert(MARIA_HA *info, const MARIA_KEY *key,
+ my_off_t *root, my_off_t new_root,
+ LSN *res_lsn);
+int _ma_write_undo_key_delete(MARIA_HA *info, const MARIA_KEY *key,
+ my_off_t new_root, LSN *res_lsn);
+my_bool write_hook_for_clr_end(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
+extern my_bool write_hook_for_undo_key(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+extern my_bool write_hook_for_undo_key_insert(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+extern my_bool write_hook_for_undo_key_delete(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ LSN *lsn, void *hook_arg);
+void _ma_unpin_all_pages(MARIA_HA *info, LSN undo_lsn);
+
+my_bool _ma_log_prefix(MARIA_HA *info, my_off_t page,
+ uchar *buff, uint changed_length,
+ int move_length);
+my_bool _ma_log_suffix(MARIA_HA *info, my_off_t page,
+ uchar *buff, uint org_length,
+ uint new_length);
+my_bool _ma_log_add(MARIA_HA *info, my_off_t page, uchar *buff,
+ uint buff_length, uchar *key_pos,
+ uint changed_length, int move_length,
+ my_bool handle_overflow);
+my_bool _ma_log_delete(MARIA_HA *info, my_off_t page, const uchar *buff,
+ const uchar *key_pos, uint changed_length,
+ uint move_length);
+my_bool _ma_log_change(MARIA_HA *info, my_off_t page, const uchar *buff,
+ const uchar *key_pos, uint length);
+my_bool _ma_log_new(MARIA_HA *info, my_off_t page, const uchar *buff,
+ uint page_length, uint key_nr, my_bool root_page);
+
+uint _ma_apply_redo_index_new_page(MARIA_HA *info, LSN lsn,
+ const uchar *header, uint length);
+uint _ma_apply_redo_index_free_page(MARIA_HA *info, LSN lsn,
+ const uchar *header);
+uint _ma_apply_redo_index(MARIA_HA *info,
+ LSN lsn, const uchar *header, uint length);
+
+my_bool _ma_apply_undo_key_insert(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header, uint length);
+my_bool _ma_apply_undo_key_delete(MARIA_HA *info, LSN undo_lsn,
+ const uchar *header, uint length,
+ my_bool with_root);
+
+static inline void _ma_finalize_row(MARIA_HA *info)
+{
+ info->trn->rec_lsn= LSN_IMPOSSIBLE;
+}
+
+/* unpinning is often the last operation before finalizing */
+
+static inline void _ma_unpin_all_pages_and_finalize_row(MARIA_HA *info,
+ LSN undo_lsn)
+{
+ _ma_unpin_all_pages(info, undo_lsn);
+ _ma_finalize_row(info);
+}
+
+extern my_bool _ma_lock_key_del(MARIA_HA *info, my_bool insert_at_end);
+extern void _ma_unlock_key_del(MARIA_HA *info);
+static inline void _ma_fast_unlock_key_del(MARIA_HA *info)
+{
+ if (info->key_del_used)
+ _ma_unlock_key_del(info);
+}
diff --git a/storage/maria/ma_keycache.c b/storage/maria/ma_keycache.c
new file mode 100644
index 00000000000..39fc7d421ae
--- /dev/null
+++ b/storage/maria/ma_keycache.c
@@ -0,0 +1,164 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Key cache assignments
+*/
+
+#include "maria_def.h"
+
+/*
+ Assign pages of the index file for a table to a key cache
+
+ SYNOPSIS
+ maria_assign_to_pagecache()
+ info open table
+ key_map map of indexes to assign to the key cache
+ pagecache_ptr pointer to the key cache handle
+ assign_lock Mutex to lock during assignment
+
+ PREREQUESTS
+ One must have a READ lock or a WRITE lock on the table when calling
+ the function to ensure that there is no other writers to it.
+
+ The caller must also ensure that one doesn't call this function from
+ two different threads with the same table.
+
+ NOTES
+ At present pages for all indexes must be assigned to the same key cache.
+ In future only pages for indexes specified in the key_map parameter
+ of the table will be assigned to the specified key cache.
+
+ RETURN VALUE
+ 0 If a success
+ # Error code
+*/
+
+int maria_assign_to_pagecache(MARIA_HA *info,
+ ulonglong key_map __attribute__((unused)),
+ PAGECACHE *pagecache)
+{
+ int error= 0;
+ MARIA_SHARE* share= info->s;
+ DBUG_ENTER("maria_assign_to_pagecache");
+ DBUG_PRINT("enter",
+ ("old_pagecache_handle: 0x%lx new_pagecache_handle: 0x%lx",
+ (long) share->pagecache, (long) pagecache));
+
+ /*
+ Skip operation if we didn't change key cache. This can happen if we
+ call this for all open instances of the same table
+ */
+ if (share->pagecache == pagecache)
+ DBUG_RETURN(0);
+
+ /*
+ First flush all blocks for the table in the old key cache.
+ This is to ensure that the disk is consistent with the data pages
+ in memory (which may not be the case if the table uses delayed_key_write)
+
+ Note that some other read thread may still fill in the key cache with
+ new blocks during this call and after, but this doesn't matter as
+ all threads will start using the new key cache for their next call to
+ maria library and we know that there will not be any changed blocks
+ in the old key cache.
+ */
+
+ if (flush_pagecache_blocks(share->pagecache, &share->kfile, FLUSH_RELEASE))
+ {
+ error= my_errno;
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_mark_crashed(info); /* Mark that table must be checked */
+ }
+
+ /*
+ Flush the new key cache for this file. This is needed to ensure
+ that there is no old blocks (with outdated data) left in the new key
+ cache from an earlier assign_to_keycache operation
+
+ (This can never fail as there is never any not written data in the
+ new key cache)
+ */
+ (void) flush_pagecache_blocks(pagecache, &share->kfile, FLUSH_RELEASE);
+
+ /*
+ ensure that setting the key cache and changing the multi_pagecache
+ is done atomicly
+ */
+ pthread_mutex_lock(&share->intern_lock);
+ /*
+ Tell all threads to use the new key cache
+ This should be seen at the lastes for the next call to an maria function.
+ */
+ share->pagecache= pagecache;
+
+ /* store the key cache in the global hash structure for future opens */
+ if (multi_pagecache_set((uchar*) share->unique_file_name.str,
+ share->unique_file_name.length,
+ share->pagecache))
+ error= my_errno;
+ pthread_mutex_unlock(&share->intern_lock);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Change all MARIA entries that uses one key cache to another key cache
+
+ SYNOPSIS
+ maria_change_pagecache()
+ old_pagecache Old key cache
+ new_pagecache New key cache
+
+ NOTES
+ This is used when we delete one key cache.
+
+ To handle the case where some other threads tries to open an MARIA
+ table associated with the to-be-deleted key cache while this operation
+ is running, we have to call 'multi_pagecache_change()' from this
+ function while we have a lock on the MARIA table list structure.
+
+ This is safe as long as it's only MARIA that is using this specific
+ key cache.
+*/
+
+
+void maria_change_pagecache(PAGECACHE *old_pagecache,
+ PAGECACHE *new_pagecache)
+{
+ LIST *pos;
+ DBUG_ENTER("maria_change_pagecache");
+
+ /*
+ Lock list to ensure that no one can close the table while we manipulate it
+ */
+ pthread_mutex_lock(&THR_LOCK_maria);
+ for (pos=maria_open_list ; pos ; pos=pos->next)
+ {
+ MARIA_HA *info= (MARIA_HA*) pos->data;
+ MARIA_SHARE *share= info->s;
+ if (share->pagecache == old_pagecache)
+ maria_assign_to_pagecache(info, (ulonglong) ~0, new_pagecache);
+ }
+
+ /*
+ We have to do the following call while we have the lock on the
+ MARIA list structure to ensure that another thread is not trying to
+ open a new table that will be associted with the old key cache
+ */
+ multi_pagecache_change(old_pagecache, new_pagecache);
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ DBUG_VOID_RETURN;
+}
diff --git a/storage/maria/ma_locking.c b/storage/maria/ma_locking.c
new file mode 100644
index 00000000000..9d57cd1cba3
--- /dev/null
+++ b/storage/maria/ma_locking.c
@@ -0,0 +1,553 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Locking of Maria-tables.
+ Must be first request before doing any furter calls to any Maria function.
+ Is used to allow many process use the same non transactional Maria table
+*/
+
+#include "ma_ftdefs.h"
+
+ /* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
+
+int maria_lock_database(MARIA_HA *info, int lock_type)
+{
+ int error;
+ uint count;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_lock_database");
+ DBUG_PRINT("enter",("lock_type: %d old lock %d r_locks: %u w_locks: %u "
+ "global_changed: %d open_count: %u name: '%s'",
+ lock_type, info->lock_type, share->r_locks,
+ share->w_locks,
+ share->global_changed, share->state.open_count,
+ share->index_file_name.str));
+ if (share->options & HA_OPTION_READ_ONLY_DATA ||
+ info->lock_type == lock_type)
+ DBUG_RETURN(0);
+ if (lock_type == F_EXTRA_LCK) /* Used by TMP tables */
+ {
+ ++share->w_locks;
+ ++share->tot_locks;
+ info->lock_type= lock_type;
+ DBUG_RETURN(0);
+ }
+
+ error=0;
+ pthread_mutex_lock(&share->intern_lock);
+ if (share->kfile.file >= 0) /* May only be false on windows */
+ {
+ switch (lock_type) {
+ case F_UNLCK:
+ maria_ftparser_call_deinitializer(info);
+ if (info->lock_type == F_RDLCK)
+ {
+ count= --share->r_locks;
+ if (share->lock_restore_status)
+ (*share->lock_restore_status)(info);
+ }
+ else
+ {
+ count= --share->w_locks;
+ if (share->lock.update_status)
+ (*share->lock.update_status)(info);
+ }
+ --share->tot_locks;
+ if (info->lock_type == F_WRLCK && !share->w_locks)
+ {
+ /* pages of transactional tables get flushed at Checkpoint */
+ if (!share->base.born_transactional && !share->temporary &&
+ _ma_flush_table_files(info,
+ share->delay_key_write ? MARIA_FLUSH_DATA :
+ MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_KEEP, FLUSH_KEEP))
+ error= my_errno;
+ }
+ if (info->opt_flag & (READ_CACHE_USED | WRITE_CACHE_USED))
+ {
+ if (end_io_cache(&info->rec_cache))
+ {
+ error=my_errno;
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_mark_crashed(info);
+ }
+ }
+ if (!count)
+ {
+ DBUG_PRINT("info",("changed: %u w_locks: %u",
+ (uint) share->changed, share->w_locks));
+ if (share->changed && !share->w_locks)
+ {
+#ifdef HAVE_MMAP
+ if ((share->mmaped_length !=
+ share->state.state.data_file_length) &&
+ (share->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
+ {
+ if (share->lock_key_trees)
+ rw_wrlock(&share->mmap_lock);
+ _ma_remap_file(info, share->state.state.data_file_length);
+ share->nonmmaped_inserts= 0;
+ if (share->lock_key_trees)
+ rw_unlock(&share->mmap_lock);
+ }
+#endif
+#ifdef EXTERNAL_LOCKING
+ share->state.process= share->last_process=share->this_process;
+ share->state.unique= info->last_unique= info->this_unique;
+ share->state.update_count= info->last_loop= ++info->this_loop;
+#endif
+ /* transactional tables rather flush their state at Checkpoint */
+ if (!share->base.born_transactional)
+ {
+ if (_ma_state_info_write_sub(share->kfile.file, &share->state,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET))
+ error= my_errno;
+ else
+ {
+ /* A value of 0 means below means "state flushed" */
+ share->changed= 0;
+ }
+ }
+ if (maria_flush)
+ {
+ if (_ma_sync_table_files(info))
+ error= my_errno;
+ }
+ else
+ share->not_flushed=1;
+ if (error)
+ {
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_mark_crashed(info);
+ }
+ }
+ }
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ info->lock_type= F_UNLCK;
+ break;
+ case F_RDLCK:
+ if (info->lock_type == F_WRLCK)
+ {
+ /*
+ Change RW to READONLY
+
+ mysqld does not turn write locks to read locks,
+ so we're never here in mysqld.
+ */
+ share->w_locks--;
+ share->r_locks++;
+ info->lock_type=lock_type;
+ break;
+ }
+#ifdef MARIA_EXTERNAL_LOCKING
+ if (!share->r_locks && !share->w_locks)
+ {
+ /* note that a transactional table should not do this */
+ if (_ma_state_info_read_dsk(share->kfile.file, &share->state))
+ {
+ error=my_errno;
+ break;
+ }
+ }
+#endif
+ VOID(_ma_test_if_changed(info));
+ share->r_locks++;
+ share->tot_locks++;
+ info->lock_type=lock_type;
+ break;
+ case F_WRLCK:
+ if (info->lock_type == F_RDLCK)
+ { /* Change READONLY to RW */
+ if (share->r_locks == 1)
+ {
+ share->r_locks--;
+ share->w_locks++;
+ info->lock_type=lock_type;
+ break;
+ }
+ }
+#ifdef MARIA_EXTERNAL_LOCKING
+ if (!(share->options & HA_OPTION_READ_ONLY_DATA))
+ {
+ if (!share->w_locks)
+ {
+ if (!share->r_locks)
+ {
+ /*
+ Note that transactional tables should not do this.
+ If we enabled this code, we should make sure to skip it if
+ born_transactional is true. We should not test
+ now_transactional to decide if we can call
+ _ma_state_info_read_dsk(), because it can temporarily be 0
+ (TRUNCATE on a partitioned table) and thus it would make a state
+ modification below without mutex, confusing a concurrent
+ checkpoint running.
+ Even if this code was enabled only for non-transactional tables:
+ in scenario LOCK TABLE t1 WRITE; INSERT INTO t1; DELETE FROM t1;
+ state on disk read by DELETE is obsolete as it was not flushed
+ at the end of INSERT. MyISAM same. It however causes no issue as
+ maria_delete_all_rows() calls _ma_reset_status() thus is not
+ influenced by the obsolete read values.
+ */
+ if (_ma_state_info_read_dsk(share->kfile.file, &share->state))
+ {
+ error=my_errno;
+ break;
+ }
+ }
+ }
+ }
+#endif /* defined(MARIA_EXTERNAL_LOCKING) */
+ VOID(_ma_test_if_changed(info));
+
+ info->lock_type=lock_type;
+ info->invalidator=share->invalidator;
+ share->w_locks++;
+ share->tot_locks++;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ break; /* Impossible */
+ }
+ }
+#ifdef __WIN__
+ else
+ {
+ /*
+ Check for bad file descriptors if this table is part
+ of a merge union. Failing to capture this may cause
+ a crash on windows if the table is renamed and
+ later on referenced by the merge table.
+ */
+ if( info->owned_by_merge && (info->s)->kfile.file < 0 )
+ {
+ error = HA_ERR_NO_SUCH_TABLE;
+ }
+ }
+#endif
+ pthread_mutex_unlock(&share->intern_lock);
+ DBUG_RETURN(error);
+} /* maria_lock_database */
+
+
+/****************************************************************************
+ ** functions to read / write the state
+****************************************************************************/
+
+int _ma_readinfo(register MARIA_HA *info __attribute__ ((unused)),
+ int lock_type __attribute__ ((unused)),
+ int check_keybuffer __attribute__ ((unused)))
+{
+#ifdef MARIA_EXTERNAL_LOCKING
+ DBUG_ENTER("_ma_readinfo");
+
+ if (info->lock_type == F_UNLCK)
+ {
+ MARIA_SHARE *share= info->s;
+ if (!share->tot_locks)
+ {
+ /* should not be done for transactional tables */
+ if (_ma_state_info_read_dsk(share->kfile.file, &share->state))
+ {
+ if (!my_errno)
+ my_errno= HA_ERR_FILE_TOO_SHORT;
+ DBUG_RETURN(1);
+ }
+ }
+ if (check_keybuffer)
+ VOID(_ma_test_if_changed(info));
+ info->invalidator=share->invalidator;
+ }
+ else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
+ {
+ my_errno=EACCES; /* Not allowed to change */
+ DBUG_RETURN(-1); /* when have read_lock() */
+ }
+ DBUG_RETURN(0);
+#else
+ return 0;
+#endif /* defined(MARIA_EXTERNAL_LOCKING) */
+} /* _ma_readinfo */
+
+
+/*
+ Every isam-function that uppdates the isam-database MUST end with this
+ request
+
+ NOTES
+ my_errno is not changed if this succeeds!
+*/
+
+int _ma_writeinfo(register MARIA_HA *info, uint operation)
+{
+ int error,olderror;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_writeinfo");
+ DBUG_PRINT("info",("operation: %u tot_locks: %u", operation,
+ share->tot_locks));
+
+ error=0;
+ if (share->tot_locks == 0 && !share->base.born_transactional)
+ {
+ /* transactional tables flush their state at Checkpoint */
+ if (operation)
+ { /* Two threads can't be here */
+ olderror= my_errno; /* Remember last error */
+
+#ifdef EXTERNAL_LOCKING
+ /*
+ The following only makes sense if we want to be allow two different
+ processes access the same table at the same time
+ */
+ share->state.process= share->last_process= share->this_process;
+ share->state.unique= info->last_unique= info->this_unique;
+ share->state.update_count= info->last_loop= ++info->this_loop;
+#endif
+
+ if ((error=
+ _ma_state_info_write_sub(share->kfile.file,
+ &share->state,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)))
+ olderror=my_errno;
+#ifdef __WIN__
+ if (maria_flush)
+ {
+ _commit(share->kfile.file);
+ _commit(info->dfile.file);
+ }
+#endif
+ my_errno=olderror;
+ }
+ }
+ else if (operation)
+ share->changed= 1; /* Mark keyfile changed */
+ DBUG_RETURN(error);
+} /* _ma_writeinfo */
+
+
+/*
+ Test if an external process has changed the database
+ (Should be called after readinfo)
+*/
+
+int _ma_test_if_changed(register MARIA_HA *info)
+{
+#ifdef EXTERNAL_LOCKING
+ MARIA_SHARE *share= info->s;
+ if (share->state.process != share->last_process ||
+ share->state.unique != info->last_unique ||
+ share->state.update_count != info->last_loop)
+ { /* Keyfile has changed */
+ DBUG_PRINT("info",("index file changed"));
+ if (share->state.process != share->this_process)
+ VOID(flush_pagecache_blocks(share->pagecache, &share->kfile,
+ FLUSH_RELEASE));
+ share->last_process=share->state.process;
+ info->last_unique= share->state.unique;
+ info->last_loop= share->state.update_count;
+ info->update|= HA_STATE_WRITTEN; /* Must use file on next */
+ info->data_changed= 1; /* For maria_is_changed */
+ return 1;
+ }
+#endif
+ return (!(info->update & HA_STATE_AKTIV) ||
+ (info->update & (HA_STATE_WRITTEN | HA_STATE_DELETED |
+ HA_STATE_KEY_CHANGED)));
+} /* _ma_test_if_changed */
+
+
+/*
+ Put a mark in the .MAI file that someone is updating the table
+
+ DOCUMENTATION
+ state.open_count in the .MAI file is used the following way:
+ - For the first change of the .MYI file in this process open_count is
+ incremented by _ma_mark_file_changed(). (We have a write lock on the file
+ when this happens)
+ - In maria_close() it's decremented by _ma_decrement_open_count() if it
+ was incremented in the same process.
+
+ This mean that if we are the only process using the file, the open_count
+ tells us if the MARIA file wasn't properly closed. (This is true if
+ my_disable_locking is set).
+
+ open_count is not maintained on disk for temporary tables.
+*/
+
+int _ma_mark_file_changed(MARIA_HA *info)
+{
+ uchar buff[3];
+ register MARIA_SHARE *share= info->s;
+ int error= 1;
+ DBUG_ENTER("_ma_mark_file_changed");
+
+#define _MA_ALREADY_MARKED_FILE_CHANGED \
+ ((share->state.changed & STATE_CHANGED) && share->global_changed)
+ if (_MA_ALREADY_MARKED_FILE_CHANGED)
+ DBUG_RETURN(0);
+ pthread_mutex_lock(&share->intern_lock); /* recheck under mutex */
+ if (! _MA_ALREADY_MARKED_FILE_CHANGED)
+ {
+ share->state.changed|=(STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_OPTIMIZED_KEYS);
+ if (!share->global_changed)
+ {
+ share->global_changed=1;
+ share->state.open_count++;
+ }
+ /*
+ Temp tables don't need an open_count as they are removed on crash.
+ In theory transactional tables are fixed by log-based recovery, so don't
+ need an open_count either, but if recovery has failed and logs have been
+ removed (by maria-force-start-after-recovery-failures), we still need to
+ detect dubious tables.
+ If we didn't maintain open_count on disk for a table, after a crash
+ we wouldn't know if it was closed at crash time (thus does not need a
+ check) or not. So we would have to check all tables: overkill.
+ */
+ if (!share->temporary)
+ {
+ mi_int2store(buff,share->state.open_count);
+ buff[2]=1; /* Mark that it's changed */
+ if (my_pwrite(share->kfile.file, buff, sizeof(buff),
+ sizeof(share->state.header) +
+ MARIA_FILE_OPEN_COUNT_OFFSET,
+ MYF(MY_NABP)))
+ goto err;
+ }
+ /* Set uuid of file if not yet set (zerofilled file) */
+ if (share->base.born_transactional &&
+ !(share->state.changed & STATE_NOT_MOVABLE))
+ {
+ /* Lock table to current installation */
+ if (_ma_set_uuid(info, 0) ||
+ (share->state.create_rename_lsn == LSN_NEEDS_NEW_STATE_LSNS &&
+ _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE,
+ trnman_get_min_trid(),
+ TRUE, TRUE)))
+ goto err;
+ share->state.changed|= STATE_NOT_MOVABLE;
+ }
+ }
+ error= 0;
+err:
+ pthread_mutex_unlock(&share->intern_lock);
+ DBUG_RETURN(error);
+#undef _MA_ALREADY_MARKED_FILE_CHANGED
+}
+
+/*
+ Check that a region is all zero
+
+ SYNOPSIS
+ check_if_zero()
+ pos Start of memory to check
+ length length of memory region
+
+ NOTES
+ Used mainly to detect rows with wrong extent information
+*/
+
+my_bool _ma_check_if_zero(uchar *pos, size_t length)
+{
+ uchar *end;
+ for (end= pos+ length; pos != end ; pos++)
+ if (pos[0] != 0)
+ return 1;
+ return 0;
+}
+
+/*
+ This is only called by close or by extra(HA_FLUSH) if the OS has the pwrite()
+ call. In these context the following code should be safe!
+ */
+
+int _ma_decrement_open_count(MARIA_HA *info)
+{
+ uchar buff[2];
+ register MARIA_SHARE *share= info->s;
+ int lock_error=0,write_error=0;
+ if (share->global_changed)
+ {
+ uint old_lock=info->lock_type;
+ share->global_changed=0;
+ lock_error=maria_lock_database(info,F_WRLCK);
+ /* Its not fatal even if we couldn't get the lock ! */
+ if (share->state.open_count > 0)
+ {
+ share->state.open_count--;
+ share->changed= 1; /* We have to update state */
+ if (!share->temporary)
+ {
+ mi_int2store(buff,share->state.open_count);
+ write_error= (int) my_pwrite(share->kfile.file, buff, sizeof(buff),
+ sizeof(share->state.header) +
+ MARIA_FILE_OPEN_COUNT_OFFSET,
+ MYF(MY_NABP));
+ }
+ }
+ if (!lock_error)
+ lock_error=maria_lock_database(info,old_lock);
+ }
+ return test(lock_error || write_error);
+}
+
+
+/** @brief mark file as crashed */
+
+void _ma_mark_file_crashed(MARIA_SHARE *share)
+{
+ uchar buff[2];
+ DBUG_ENTER("_ma_mark_file_crashed");
+
+ share->state.changed|= STATE_CRASHED;
+ mi_int2store(buff, share->state.changed);
+ /*
+ We can ignore the errors, as if the mark failed, there isn't anything
+ else we can do; The user should already have got an error that the
+ table was crashed.
+ */
+ (void) my_pwrite(share->kfile.file, buff, sizeof(buff),
+ sizeof(share->state.header) +
+ MARIA_FILE_CHANGED_OFFSET,
+ MYF(MY_NABP));
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Set uuid of for a Maria file
+
+ @fn _ma_set_uuid()
+ @param info Maria handler
+ @param reset_uuid Instead of setting file to maria_uuid, set it to
+ 0 to mark it as movable
+*/
+
+my_bool _ma_set_uuid(MARIA_HA *info, my_bool reset_uuid)
+{
+ uchar buff[MY_UUID_SIZE], *uuid;
+
+ uuid= maria_uuid;
+ if (reset_uuid)
+ {
+ bzero(buff, sizeof(buff));
+ uuid= buff;
+ }
+ return (my_bool) my_pwrite(info->s->kfile.file, uuid, MY_UUID_SIZE,
+ mi_uint2korr(info->s->state.header.base_pos),
+ MYF(MY_NABP));
+}
diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c
new file mode 100644
index 00000000000..93b7d5e84c9
--- /dev/null
+++ b/storage/maria/ma_loghandler.c
@@ -0,0 +1,8804 @@
+/* Copyright (C) 2007 MySQL AB & Sanja Belkin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "trnman.h"
+#include "ma_blockrec.h" /* for some constants and in-write hooks */
+#include "ma_key_recover.h" /* For some in-write hooks */
+#include "ma_checkpoint.h"
+
+/*
+ On Windows, neither my_open() nor my_sync() work for directories.
+ Also there is no need to flush filesystem changes ,i.e to sync()
+ directories.
+*/
+#ifdef __WIN__
+#define sync_dir(A,B) 0
+#else
+#define sync_dir(A,B) my_sync(A,B)
+#endif
+
+/**
+ @file
+ @brief Module which writes and reads to a transaction log
+*/
+
+/* 0xFF can never be valid first byte of a chunk */
+#define TRANSLOG_FILLER 0xFF
+
+/* number of opened log files in the pagecache (should be at least 2) */
+#define OPENED_FILES_NUM 3
+#define CACHED_FILES_NUM 5
+#define CACHED_FILES_NUM_DIRECT_SEARCH_LIMIT 7
+#if CACHED_FILES_NUM > CACHED_FILES_NUM_DIRECT_SEARCH_LIMIT
+#include <hash.h>
+#include <m_ctype.h>
+#endif
+
+/* transaction log file descriptor */
+typedef struct st_translog_file
+{
+ uint32 number;
+ PAGECACHE_FILE handler;
+ my_bool was_recovered;
+ my_bool is_sync;
+} TRANSLOG_FILE;
+
+/* records buffer size (should be TRANSLOG_PAGE_SIZE * n) */
+#define TRANSLOG_WRITE_BUFFER (1024*1024)
+/*
+ pagecache_read/write/inject() use bmove512() on their buffers so those must
+ be long-aligned, which we guarantee by using the type below:
+*/
+typedef union
+{
+ ulonglong dummy;
+ uchar buffer[TRANSLOG_PAGE_SIZE];
+} TRANSLOG_PAGE_SIZE_BUFF;
+
+/* min chunk length */
+#define TRANSLOG_MIN_CHUNK 3
+/*
+ Number of buffers used by loghandler
+
+ Should be at least 4, because one thread can block up to 2 buffers in
+ normal circumstances (less then half of one and full other, or just
+ switched one and other), But if we met end of the file in the middle and
+ have to switch buffer it will be 3. + 1 buffer for flushing/writing.
+ We have a bigger number here for higher concurrency and to make division
+ faster.
+
+ The number should be power of 2 to be fast.
+*/
+#define TRANSLOG_BUFFERS_NO 8
+/* number of bytes (+ header) which can be unused on first page in sequence */
+#define TRANSLOG_MINCHUNK_CONTENT 1
+/* version of log file */
+#define TRANSLOG_VERSION_ID 10000 /* 1.00.00 */
+
+#define TRANSLOG_PAGE_FLAGS 6 /* transaction log page flags offset */
+
+/* Maximum length of compressed LSNs (the worst case of whole LSN storing) */
+#define COMPRESSED_LSN_MAX_STORE_SIZE (2 + LSN_STORE_SIZE)
+#define MAX_NUMBER_OF_LSNS_PER_RECORD 2
+
+
+/* max lsn calculation for buffer */
+#define BUFFER_MAX_LSN(B) \
+ ((B)->last_lsn == LSN_IMPOSSIBLE ? (B)->prev_last_lsn : (B)->last_lsn)
+
+/* log write buffer descriptor */
+struct st_translog_buffer
+{
+ /*
+ Cache for current log. Comes first to be aligned for bmove512() in
+ pagecache_inject()
+ */
+ uchar buffer[TRANSLOG_WRITE_BUFFER];
+ /*
+ Maximum LSN of records which ends in this buffer (or IMPOSSIBLE_LSN
+ if no LSNs ends here)
+ */
+ LSN last_lsn;
+ /* last_lsn of previous buffer or IMPOSSIBLE_LSN if it is very first one */
+ LSN prev_last_lsn;
+ /* This buffer offset in the file */
+ TRANSLOG_ADDRESS offset;
+ /*
+ Next buffer offset in the file (it is not always offset + size,
+ in case of flush by LSN it can be offset + size - TRANSLOG_PAGE_SIZE)
+ */
+ TRANSLOG_ADDRESS next_buffer_offset;
+ /* Previous buffer offset to detect it flush finish */
+ TRANSLOG_ADDRESS prev_buffer_offset;
+ /*
+ How much is written (or will be written when copy_to_buffer_in_progress
+ become 0) to this buffer
+ */
+ translog_size_t size;
+ /* File handler for this buffer */
+ TRANSLOG_FILE *file;
+ /* Threads which are waiting for buffer filling/freeing */
+ pthread_cond_t waiting_filling_buffer;
+ /* Number of records which are in copy progress */
+ uint copy_to_buffer_in_progress;
+ /* list of waiting buffer ready threads */
+ struct st_my_thread_var *waiting_flush;
+ /*
+ If true then previous buffer overlap with this one (due to flush of
+ loghandler, the last page of that buffer is the same as the first page
+ of this buffer) and have to be written first (because contain old
+ content of page which present in both buffers)
+ */
+ my_bool overlay;
+ uint buffer_no;
+ /*
+ Lock for the buffer.
+
+ Current buffer also lock the whole handler (if one want lock the handler
+ one should lock the current buffer).
+
+ Buffers are locked only in one direction (with overflow and beginning
+ from the first buffer). If we keep lock on buffer N we can lock only
+ buffer N+1 (never N-1).
+
+ One thread do not lock more then 2 buffer in a time, so to make dead
+ lock it should be N thread (where N equal number of buffers) takes one
+ buffer and try to lock next. But it is impossible because there is only
+ 2 cases when thread take 2 buffers: 1) one thread finishes current
+ buffer (where horizon is) and start next (to which horizon moves). 2)
+ flush start from buffer after current (oldest) and go till the current
+ crabbing by buffer sequence. And there is only one flush in a moment
+ (they are serialised).
+
+ Because of above and number of buffers equal 5 we can't get dead lock (it is
+ impossible to get all 5 buffers locked simultaneously).
+ */
+ pthread_mutex_t mutex;
+ /*
+ Some thread is going to close the buffer and it should be
+ done only by that thread
+ */
+ my_bool is_closing_buffer;
+ /*
+ Version of the buffer increases every time buffer the buffer flushed.
+ With file and offset it allow detect buffer changes
+ */
+ uint8 ver;
+
+ /*
+ When previous buffer sent to disk it set its address here to allow
+ to detect when it is done
+ (we have to keep it in this buffer to lock buffers only in one direction).
+ */
+ TRANSLOG_ADDRESS prev_sent_to_disk;
+ pthread_cond_t prev_sent_to_disk_cond;
+};
+
+
+struct st_buffer_cursor
+{
+ /* pointer into the buffer */
+ uchar *ptr;
+ /* current buffer */
+ struct st_translog_buffer *buffer;
+ /* How many bytes we wrote on the current page */
+ uint16 current_page_fill;
+ /*
+ How many times we write the page on the disk during flushing process
+ (for sector protection).
+ */
+ uint16 write_counter;
+ /* previous write offset */
+ uint16 previous_offset;
+ /* Number of current buffer */
+ uint8 buffer_no;
+ /*
+ True if it is just filling buffer after advancing the pointer to
+ the horizon.
+ */
+ my_bool chaser;
+ /*
+ Is current page of the cursor already finished (sector protection
+ should be applied if it is needed)
+ */
+ my_bool protected;
+};
+
+
+typedef uint8 dirty_buffer_mask_t;
+
+struct st_translog_descriptor
+{
+ /* *** Parameters of the log handler *** */
+
+ /* Page cache for the log reads */
+ PAGECACHE *pagecache;
+ uint flags;
+ /* File open flags */
+ uint open_flags;
+ /* max size of one log size (for new logs creation) */
+ uint32 log_file_max_size;
+ uint32 server_version;
+ /* server ID (used for replication) */
+ uint32 server_id;
+ /* Loghandler's buffer capacity in case of chunk 2 filling */
+ uint32 buffer_capacity_chunk_2;
+ /*
+ Half of the buffer capacity in case of chunk 2 filling,
+ used to decide will we write a record in one group or many.
+ It is written to the variable just to avoid devision every
+ time we need it.
+ */
+ uint32 half_buffer_capacity_chunk_2;
+ /* Page overhead calculated by flags (whether CRC is enabled, etc) */
+ uint16 page_overhead;
+ /*
+ Page capacity ("useful load") calculated by flags
+ (TRANSLOG_PAGE_SIZE - page_overhead-1)
+ */
+ uint16 page_capacity_chunk_2;
+ /* Path to the directory where we store log store files */
+ char directory[FN_REFLEN];
+
+ /* *** Current state of the log handler *** */
+ /* list of opened files */
+ DYNAMIC_ARRAY open_files;
+ /* min/max number of file in the array */
+ uint32 max_file, min_file;
+ /* the opened files list guard */
+ rw_lock_t open_files_lock;
+
+ /*
+ File descriptor of the directory where we store log files for syncing
+ it.
+ */
+ File directory_fd;
+ /* buffers for log writing */
+ struct st_translog_buffer buffers[TRANSLOG_BUFFERS_NO];
+ /* Mask where 1 in position N mean that buffer N is not flushed */
+ dirty_buffer_mask_t dirty_buffer_mask;
+ /* The above variable protection */
+ pthread_mutex_t dirty_buffer_mask_lock;
+ /*
+ horizon - visible end of the log (here is absolute end of the log:
+ position where next chunk can start
+ */
+ TRANSLOG_ADDRESS horizon;
+ /* horizon buffer cursor */
+ struct st_buffer_cursor bc;
+ /* maximum LSN of the current (not finished) file */
+ LSN max_lsn;
+
+ /*
+ Last flushed LSN (protected by log_flush_lock).
+ Pointers in the log ordered like this:
+ last_lsn_checked <= flushed <= sent_to_disk <= in_buffers_only <=
+ max_lsn <= horizon
+ */
+ LSN flushed;
+ /* Last LSN sent to the disk (but maybe not written yet) */
+ LSN sent_to_disk;
+ /* Horizon from which log started after initialization */
+ TRANSLOG_ADDRESS log_start;
+ TRANSLOG_ADDRESS previous_flush_horizon;
+ /* All what is after this address is not sent to disk yet */
+ TRANSLOG_ADDRESS in_buffers_only;
+ /* protection of sent_to_disk and in_buffers_only */
+ pthread_mutex_t sent_to_disk_lock;
+ /*
+ Protect flushed (see above) and for flush serialization (will
+ be removed in v1.5
+ */
+ pthread_mutex_t log_flush_lock;
+ pthread_cond_t log_flush_cond;
+
+ /* Protects changing of headers of finished files (max_lsn) */
+ pthread_mutex_t file_header_lock;
+
+ /*
+ Sorted array (with protection) of files where we started writing process
+ and so we can't give last LSN yet
+ */
+ pthread_mutex_t unfinished_files_lock;
+ DYNAMIC_ARRAY unfinished_files;
+
+ /*
+ minimum number of still need file calculeted during last
+ translog_purge call
+ */
+ uint32 min_need_file;
+ /* Purger data: minimum file in the log (or 0 if unknown) */
+ uint32 min_file_number;
+ /* Protect purger from many calls and it's data */
+ pthread_mutex_t purger_lock;
+ /* last low water mark checked */
+ LSN last_lsn_checked;
+ /**
+ Must be set to 0 under loghandler lock every time a new LSN
+ is generated.
+ */
+ my_bool is_everything_flushed;
+ /* True when flush pass is in progress */
+ my_bool flush_in_progress;
+ /* Next flush pass variables */
+ TRANSLOG_ADDRESS next_pass_max_lsn;
+ pthread_t max_lsn_requester;
+};
+
+static struct st_translog_descriptor log_descriptor;
+
+ulong log_purge_type= TRANSLOG_PURGE_IMMIDIATE;
+ulong log_file_size= TRANSLOG_FILE_SIZE;
+ulong sync_log_dir= TRANSLOG_SYNC_DIR_NEWFILE;
+
+/* Marker for end of log */
+static uchar end_of_log= 0;
+#define END_OF_LOG &end_of_log
+
+enum enum_translog_status translog_status= TRANSLOG_UNINITED;
+
+/* chunk types */
+#define TRANSLOG_CHUNK_LSN 0x00 /* 0 chunk refer as LSN (head or tail */
+#define TRANSLOG_CHUNK_FIXED (1 << 6) /* 1 (pseudo)fixed record (also LSN) */
+#define TRANSLOG_CHUNK_NOHDR (2 << 6) /* 2 no head chunk (till page end) */
+#define TRANSLOG_CHUNK_LNGTH (3 << 6) /* 3 chunk with chunk length */
+#define TRANSLOG_CHUNK_TYPE (3 << 6) /* Mask to get chunk type */
+#define TRANSLOG_REC_TYPE 0x3F /* Mask to get record type */
+#define TRANSLOG_CHUNK_0_CONT 0x3F /* the type to mark chunk 0 continue */
+
+/* compressed (relative) LSN constants */
+#define TRANSLOG_CLSN_LEN_BITS 0xC0 /* Mask to get compressed LSN length */
+
+
+#include <my_atomic.h>
+/* an array that maps id of a MARIA_SHARE to this MARIA_SHARE */
+static MARIA_SHARE **id_to_share= NULL;
+/* lock for id_to_share */
+static my_atomic_rwlock_t LOCK_id_to_share;
+
+static my_bool translog_dummy_callback(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar* data_ptr);
+static my_bool translog_page_validator(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar* data_ptr);
+
+static my_bool translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner);
+static uint32 translog_first_file(TRANSLOG_ADDRESS horizon, int is_protected);
+LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon);
+
+
+/*
+ Initialize log_record_type_descriptors
+*/
+
+LOG_DESC log_record_type_descriptor[LOGREC_NUMBER_OF_TYPES];
+
+
+#ifndef DBUG_OFF
+
+#define translog_buffer_lock_assert_owner(B) \
+ safe_mutex_assert_owner(&(B)->mutex)
+#define translog_lock_assert_owner() \
+ safe_mutex_assert_owner(&log_descriptor.bc.buffer->mutex)
+void translog_lock_handler_assert_owner()
+{
+ translog_lock_assert_owner();
+}
+
+/**
+ @brief check the description table validity
+
+ @param num how many records should be filled
+*/
+
+static void check_translog_description_table(int num)
+{
+ int i;
+ DBUG_ENTER("check_translog_description_table");
+ DBUG_PRINT("enter", ("last record: %d", num));
+ DBUG_ASSERT(num > 0);
+ /* last is reserved for extending the table */
+ DBUG_ASSERT(num < LOGREC_NUMBER_OF_TYPES - 1);
+ DBUG_ASSERT(log_record_type_descriptor[0].rclass == LOGRECTYPE_NOT_ALLOWED);
+
+ for (i= 0; i <= num; i++)
+ {
+ DBUG_PRINT("info",
+ ("record type: %d class: %d fixed: %u header: %u LSNs: %u "
+ "name: %s",
+ i, log_record_type_descriptor[i].rclass,
+ (uint)log_record_type_descriptor[i].fixed_length,
+ (uint)log_record_type_descriptor[i].read_header_len,
+ (uint)log_record_type_descriptor[i].compressed_LSN,
+ log_record_type_descriptor[i].name));
+ switch (log_record_type_descriptor[i].rclass) {
+ case LOGRECTYPE_NOT_ALLOWED:
+ DBUG_ASSERT(i == 0);
+ break;
+ case LOGRECTYPE_VARIABLE_LENGTH:
+ DBUG_ASSERT(log_record_type_descriptor[i].fixed_length == 0);
+ DBUG_ASSERT((log_record_type_descriptor[i].compressed_LSN == 0) ||
+ ((log_record_type_descriptor[i].compressed_LSN == 1) &&
+ (log_record_type_descriptor[i].read_header_len >=
+ LSN_STORE_SIZE)) ||
+ ((log_record_type_descriptor[i].compressed_LSN == 2) &&
+ (log_record_type_descriptor[i].read_header_len >=
+ LSN_STORE_SIZE * 2)));
+ break;
+ case LOGRECTYPE_PSEUDOFIXEDLENGTH:
+ DBUG_ASSERT(log_record_type_descriptor[i].fixed_length ==
+ log_record_type_descriptor[i].read_header_len);
+ DBUG_ASSERT(log_record_type_descriptor[i].compressed_LSN > 0);
+ DBUG_ASSERT(log_record_type_descriptor[i].compressed_LSN <= 2);
+ break;
+ case LOGRECTYPE_FIXEDLENGTH:
+ DBUG_ASSERT(log_record_type_descriptor[i].fixed_length ==
+ log_record_type_descriptor[i].read_header_len);
+ DBUG_ASSERT(log_record_type_descriptor[i].compressed_LSN == 0);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ for (i= num + 1; i < LOGREC_NUMBER_OF_TYPES; i++)
+ {
+ DBUG_ASSERT(log_record_type_descriptor[i].rclass ==
+ LOGRECTYPE_NOT_ALLOWED);
+ }
+ DBUG_VOID_RETURN;
+}
+#else
+#define translog_buffer_lock_assert_owner(B) {}
+#define translog_lock_assert_owner() {}
+#endif
+
+static LOG_DESC INIT_LOGREC_RESERVED_FOR_CHUNKS23=
+{LOGRECTYPE_NOT_ALLOWED, 0, 0, NULL, NULL, NULL, 0,
+ "reserved", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL };
+
+static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_HEAD=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
+ write_hook_for_redo, NULL, 0,
+ "redo_insert_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_TAIL=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
+ write_hook_for_redo, NULL, 0,
+ "redo_insert_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_NEW_ROW_HEAD=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
+ write_hook_for_redo, NULL, 0,
+ "redo_new_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_NEW_ROW_TAIL=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
+ write_hook_for_redo, NULL, 0,
+ "redo_new_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_BLOBS=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, FILEID_STORE_SIZE, NULL,
+ write_hook_for_redo, NULL, 0,
+ "redo_insert_row_blobs", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_PURGE_ROW_HEAD=
+{LOGRECTYPE_FIXEDLENGTH,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ NULL, write_hook_for_redo, NULL, 0,
+ "redo_purge_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_PURGE_ROW_TAIL=
+{LOGRECTYPE_FIXEDLENGTH,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ NULL, write_hook_for_redo, NULL, 0,
+ "redo_purge_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_FREE_BLOCKS=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE,
+ NULL, write_hook_for_redo, NULL, 0,
+ "redo_free_blocks", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_FREE_HEAD_OR_TAIL=
+{LOGRECTYPE_FIXEDLENGTH,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE,
+ NULL, write_hook_for_redo, NULL, 0,
+ "redo_free_head_or_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+/* not yet used; for when we have versioning */
+static LOG_DESC INIT_LOGREC_REDO_DELETE_ROW=
+{LOGRECTYPE_FIXEDLENGTH, 16, 16, NULL, write_hook_for_redo, NULL, 0,
+ "redo_delete_row", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+/** @todo RECOVERY BUG unused, remove? */
+static LOG_DESC INIT_LOGREC_REDO_UPDATE_ROW_HEAD=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 9, NULL, write_hook_for_redo, NULL, 0,
+ "redo_update_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_INDEX=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 9, NULL, write_hook_for_redo, NULL, 0,
+ "redo_index", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_INDEX_NEW_PAGE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2 + KEY_NR_STORE_SIZE + 1,
+ NULL, write_hook_for_redo, NULL, 0,
+ "redo_index_new_page", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_INDEX_FREE_PAGE=
+{LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
+ NULL, write_hook_for_redo, NULL, 0,
+ "redo_index_free_page", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_UNDELETE_ROW=
+{LOGRECTYPE_FIXEDLENGTH, 16, 16, NULL, write_hook_for_redo, NULL, 0,
+ "redo_undelete_row", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_CLR_END=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE, NULL, write_hook_for_clr_end, NULL, 1,
+ "clr_end", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_PURGE_END=
+{LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, NULL, NULL, 1,
+ "purge_end", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_UNDO_ROW_INSERT=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ NULL, write_hook_for_undo_row_insert, NULL, 1,
+ "undo_row_insert", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_UNDO_ROW_DELETE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ NULL, write_hook_for_undo_row_delete, NULL, 1,
+ "undo_row_delete", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_UNDO_ROW_UPDATE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ NULL, write_hook_for_undo_row_update, NULL, 1,
+ "undo_row_update", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_UNDO_KEY_INSERT=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE,
+ NULL, write_hook_for_undo_key_insert, NULL, 1,
+ "undo_key_insert", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+/* This will never be in the log, only in the clr */
+static LOG_DESC INIT_LOGREC_UNDO_KEY_INSERT_WITH_ROOT=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE + PAGE_STORE_SIZE,
+ NULL, write_hook_for_undo_key, NULL, 1,
+ "undo_key_insert_with_root", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE,
+ NULL, write_hook_for_undo_key_delete, NULL, 1,
+ "undo_key_delete", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE_WITH_ROOT=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE + PAGE_STORE_SIZE,
+ NULL, write_hook_for_undo_key_delete, NULL, 1,
+ "undo_key_delete_with_root", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_PREPARE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
+ "prepare", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_PREPARE_WITH_UNDO_PURGE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, LSN_STORE_SIZE, NULL, NULL, NULL, 1,
+ "prepare_with_undo_purge", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_COMMIT=
+{LOGRECTYPE_FIXEDLENGTH, 0, 0, NULL,
+ write_hook_for_commit, NULL, 0, "commit", LOGREC_IS_GROUP_ITSELF, NULL,
+ NULL};
+
+static LOG_DESC INIT_LOGREC_COMMIT_WITH_UNDO_PURGE=
+{LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, write_hook_for_commit, NULL, 1,
+ "commit_with_undo_purge", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_CHECKPOINT=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
+ "checkpoint", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_CREATE_TABLE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 1 + 2, NULL, NULL, NULL, 0,
+"redo_create_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_RENAME_TABLE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
+ "redo_rename_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_DROP_TABLE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
+ "redo_drop_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_DELETE_ALL=
+{LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE, FILEID_STORE_SIZE,
+ NULL, write_hook_for_redo_delete_all, NULL, 0,
+ "redo_delete_all", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_REPAIR_TABLE=
+{LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE + 8 + 8, FILEID_STORE_SIZE + 8 + 8,
+ NULL, NULL, NULL, 0,
+ "redo_repair_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_FILE_ID=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 2, NULL, write_hook_for_file_id, NULL, 0,
+ "file_id", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_LONG_TRANSACTION_ID=
+{LOGRECTYPE_FIXEDLENGTH, 6, 6, NULL, NULL, NULL, 0,
+ "long_transaction_id", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_INCOMPLETE_LOG=
+{LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE, FILEID_STORE_SIZE,
+ NULL, NULL, NULL, 0,
+ "incomplete_log", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_INCOMPLETE_GROUP=
+{LOGRECTYPE_FIXEDLENGTH, 0, 0,
+ NULL, NULL, NULL, 0,
+ "incomplete_group", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_UNDO_BULK_INSERT=
+{LOGRECTYPE_VARIABLE_LENGTH, 0,
+ LSN_STORE_SIZE + FILEID_STORE_SIZE,
+ NULL, write_hook_for_undo_bulk_insert, NULL, 1,
+ "undo_bulk_insert", LOGREC_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_REDO_BITMAP_NEW_PAGE=
+{LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
+ FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
+ NULL, NULL, NULL, 0,
+ "redo_create_bitmap", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_IMPORTED_TABLE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
+ "imported_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_DEBUG_INFO=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
+ "info", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
+
+const myf log_write_flags= MY_WME | MY_NABP | MY_WAIT_IF_FULL;
+
+void translog_table_init()
+{
+ int i;
+ log_record_type_descriptor[LOGREC_RESERVED_FOR_CHUNKS23]=
+ INIT_LOGREC_RESERVED_FOR_CHUNKS23;
+ log_record_type_descriptor[LOGREC_REDO_INSERT_ROW_HEAD]=
+ INIT_LOGREC_REDO_INSERT_ROW_HEAD;
+ log_record_type_descriptor[LOGREC_REDO_INSERT_ROW_TAIL]=
+ INIT_LOGREC_REDO_INSERT_ROW_TAIL;
+ log_record_type_descriptor[LOGREC_REDO_NEW_ROW_HEAD]=
+ INIT_LOGREC_REDO_NEW_ROW_HEAD;
+ log_record_type_descriptor[LOGREC_REDO_NEW_ROW_TAIL]=
+ INIT_LOGREC_REDO_NEW_ROW_TAIL;
+ log_record_type_descriptor[LOGREC_REDO_INSERT_ROW_BLOBS]=
+ INIT_LOGREC_REDO_INSERT_ROW_BLOBS;
+ log_record_type_descriptor[LOGREC_REDO_PURGE_ROW_HEAD]=
+ INIT_LOGREC_REDO_PURGE_ROW_HEAD;
+ log_record_type_descriptor[LOGREC_REDO_PURGE_ROW_TAIL]=
+ INIT_LOGREC_REDO_PURGE_ROW_TAIL;
+ log_record_type_descriptor[LOGREC_REDO_FREE_BLOCKS]=
+ INIT_LOGREC_REDO_FREE_BLOCKS;
+ log_record_type_descriptor[LOGREC_REDO_FREE_HEAD_OR_TAIL]=
+ INIT_LOGREC_REDO_FREE_HEAD_OR_TAIL;
+ log_record_type_descriptor[LOGREC_REDO_DELETE_ROW]=
+ INIT_LOGREC_REDO_DELETE_ROW;
+ log_record_type_descriptor[LOGREC_REDO_UPDATE_ROW_HEAD]=
+ INIT_LOGREC_REDO_UPDATE_ROW_HEAD;
+ log_record_type_descriptor[LOGREC_REDO_INDEX]=
+ INIT_LOGREC_REDO_INDEX;
+ log_record_type_descriptor[LOGREC_REDO_INDEX_NEW_PAGE]=
+ INIT_LOGREC_REDO_INDEX_NEW_PAGE;
+ log_record_type_descriptor[LOGREC_REDO_INDEX_FREE_PAGE]=
+ INIT_LOGREC_REDO_INDEX_FREE_PAGE;
+ log_record_type_descriptor[LOGREC_REDO_UNDELETE_ROW]=
+ INIT_LOGREC_REDO_UNDELETE_ROW;
+ log_record_type_descriptor[LOGREC_CLR_END]=
+ INIT_LOGREC_CLR_END;
+ log_record_type_descriptor[LOGREC_PURGE_END]=
+ INIT_LOGREC_PURGE_END;
+ log_record_type_descriptor[LOGREC_UNDO_ROW_INSERT]=
+ INIT_LOGREC_UNDO_ROW_INSERT;
+ log_record_type_descriptor[LOGREC_UNDO_ROW_DELETE]=
+ INIT_LOGREC_UNDO_ROW_DELETE;
+ log_record_type_descriptor[LOGREC_UNDO_ROW_UPDATE]=
+ INIT_LOGREC_UNDO_ROW_UPDATE;
+ log_record_type_descriptor[LOGREC_UNDO_KEY_INSERT]=
+ INIT_LOGREC_UNDO_KEY_INSERT;
+ log_record_type_descriptor[LOGREC_UNDO_KEY_INSERT_WITH_ROOT]=
+ INIT_LOGREC_UNDO_KEY_INSERT_WITH_ROOT;
+ log_record_type_descriptor[LOGREC_UNDO_KEY_DELETE]=
+ INIT_LOGREC_UNDO_KEY_DELETE;
+ log_record_type_descriptor[LOGREC_UNDO_KEY_DELETE_WITH_ROOT]=
+ INIT_LOGREC_UNDO_KEY_DELETE_WITH_ROOT;
+ log_record_type_descriptor[LOGREC_PREPARE]=
+ INIT_LOGREC_PREPARE;
+ log_record_type_descriptor[LOGREC_PREPARE_WITH_UNDO_PURGE]=
+ INIT_LOGREC_PREPARE_WITH_UNDO_PURGE;
+ log_record_type_descriptor[LOGREC_COMMIT]=
+ INIT_LOGREC_COMMIT;
+ log_record_type_descriptor[LOGREC_COMMIT_WITH_UNDO_PURGE]=
+ INIT_LOGREC_COMMIT_WITH_UNDO_PURGE;
+ log_record_type_descriptor[LOGREC_CHECKPOINT]=
+ INIT_LOGREC_CHECKPOINT;
+ log_record_type_descriptor[LOGREC_REDO_CREATE_TABLE]=
+ INIT_LOGREC_REDO_CREATE_TABLE;
+ log_record_type_descriptor[LOGREC_REDO_RENAME_TABLE]=
+ INIT_LOGREC_REDO_RENAME_TABLE;
+ log_record_type_descriptor[LOGREC_REDO_DROP_TABLE]=
+ INIT_LOGREC_REDO_DROP_TABLE;
+ log_record_type_descriptor[LOGREC_REDO_DELETE_ALL]=
+ INIT_LOGREC_REDO_DELETE_ALL;
+ log_record_type_descriptor[LOGREC_REDO_REPAIR_TABLE]=
+ INIT_LOGREC_REDO_REPAIR_TABLE;
+ log_record_type_descriptor[LOGREC_FILE_ID]=
+ INIT_LOGREC_FILE_ID;
+ log_record_type_descriptor[LOGREC_LONG_TRANSACTION_ID]=
+ INIT_LOGREC_LONG_TRANSACTION_ID;
+ log_record_type_descriptor[LOGREC_INCOMPLETE_LOG]=
+ INIT_LOGREC_INCOMPLETE_LOG;
+ log_record_type_descriptor[LOGREC_INCOMPLETE_GROUP]=
+ INIT_LOGREC_INCOMPLETE_GROUP;
+ log_record_type_descriptor[LOGREC_UNDO_BULK_INSERT]=
+ INIT_LOGREC_UNDO_BULK_INSERT;
+ log_record_type_descriptor[LOGREC_REDO_BITMAP_NEW_PAGE]=
+ INIT_LOGREC_REDO_BITMAP_NEW_PAGE;
+ log_record_type_descriptor[LOGREC_IMPORTED_TABLE]=
+ INIT_LOGREC_IMPORTED_TABLE;
+ log_record_type_descriptor[LOGREC_DEBUG_INFO]=
+ INIT_LOGREC_DEBUG_INFO;
+
+ for (i= LOGREC_FIRST_FREE; i < LOGREC_NUMBER_OF_TYPES; i++)
+ log_record_type_descriptor[i].rclass= LOGRECTYPE_NOT_ALLOWED;
+#ifndef DBUG_OFF
+ check_translog_description_table(LOGREC_FIRST_FREE -1);
+#endif
+}
+
+
+/* all possible flags page overheads */
+static uint page_overhead[TRANSLOG_FLAGS_NUM];
+
+typedef struct st_translog_validator_data
+{
+ TRANSLOG_ADDRESS *addr;
+ my_bool was_recovered;
+} TRANSLOG_VALIDATOR_DATA;
+
+
+/*
+ Check cursor/buffer consistence
+
+ SYNOPSIS
+ translog_check_cursor
+ cursor cursor which will be checked
+*/
+
+static void translog_check_cursor(struct st_buffer_cursor *cursor
+ __attribute__((unused)))
+{
+ DBUG_ASSERT(cursor->chaser ||
+ ((ulong) (cursor->ptr - cursor->buffer->buffer) ==
+ cursor->buffer->size));
+ DBUG_ASSERT(cursor->buffer->buffer_no == cursor->buffer_no);
+ DBUG_ASSERT((cursor->ptr -cursor->buffer->buffer) %TRANSLOG_PAGE_SIZE ==
+ cursor->current_page_fill % TRANSLOG_PAGE_SIZE);
+ DBUG_ASSERT(cursor->current_page_fill <= TRANSLOG_PAGE_SIZE);
+}
+
+
+/**
+ @brief switch the loghandler in read only mode in case of write error
+*/
+
+void translog_stop_writing()
+{
+ DBUG_ENTER("translog_stop_writing");
+ DBUG_PRINT("error", ("errno: %d my_errno: %d", errno, my_errno));
+ translog_status= (translog_status == TRANSLOG_SHUTDOWN ?
+ TRANSLOG_UNINITED :
+ TRANSLOG_READONLY);
+ log_descriptor.is_everything_flushed= 1;
+ log_descriptor.open_flags= O_BINARY | O_RDONLY;
+ DBUG_ASSERT(0);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief Get file name of the log by log number
+
+ @param file_no Number of the log we want to open
+ @param path Pointer to buffer where file name will be
+ stored (must be FN_REFLEN bytes at least)
+
+ @return pointer to path
+*/
+
+char *translog_filename_by_fileno(uint32 file_no, char *path)
+{
+ char buff[11], *end;
+ uint length;
+ DBUG_ENTER("translog_filename_by_fileno");
+ DBUG_ASSERT(file_no <= 0xfffffff);
+
+ /* log_descriptor.directory is already formated */
+ end= strxmov(path, log_descriptor.directory, "maria_log.0000000", NullS);
+ length= (uint) (int10_to_str(file_no, buff, 10) - buff);
+ strmov(end - length +1, buff);
+
+ DBUG_PRINT("info", ("Path: '%s' path: 0x%lx", path, (ulong) path));
+ DBUG_RETURN(path);
+}
+
+
+/**
+ @brief Create log file with given number without cache
+
+ @param file_no Number of the log we want to open
+
+ retval -1 error
+ retval # file descriptor number
+*/
+
+static File create_logfile_by_number_no_cache(uint32 file_no)
+{
+ File file;
+ char path[FN_REFLEN];
+ DBUG_ENTER("create_logfile_by_number_no_cache");
+
+ if (translog_status != TRANSLOG_OK)
+ DBUG_RETURN(-1);
+
+ /* TODO: add O_DIRECT to open flags (when buffer is aligned) */
+ if ((file= my_create(translog_filename_by_fileno(file_no, path),
+ 0, O_BINARY | O_RDWR, MYF(MY_WME))) < 0)
+ {
+ DBUG_PRINT("error", ("Error %d during creating file '%s'", errno, path));
+ translog_stop_writing();
+ DBUG_RETURN(-1);
+ }
+ if (sync_log_dir >= TRANSLOG_SYNC_DIR_NEWFILE &&
+ sync_dir(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD)))
+ {
+ DBUG_PRINT("error", ("Error %d during syncing directory '%s'",
+ errno, log_descriptor.directory));
+ translog_stop_writing();
+ DBUG_RETURN(-1);
+ }
+ DBUG_PRINT("info", ("File: '%s' handler: %d", path, file));
+ DBUG_RETURN(file);
+}
+
+/**
+ @brief Open (not create) log file with given number without cache
+
+ @param file_no Number of the log we want to open
+
+ retval -1 error
+ retval # file descriptor number
+*/
+
+static File open_logfile_by_number_no_cache(uint32 file_no)
+{
+ File file;
+ char path[FN_REFLEN];
+ DBUG_ENTER("open_logfile_by_number_no_cache");
+
+ /* TODO: add O_DIRECT to open flags (when buffer is aligned) */
+ /* TODO: use my_create() */
+ if ((file= my_open(translog_filename_by_fileno(file_no, path),
+ log_descriptor.open_flags,
+ MYF(MY_WME))) < 0)
+ {
+ DBUG_PRINT("error", ("Error %d during opening file '%s'", errno, path));
+ DBUG_RETURN(-1);
+ }
+ DBUG_PRINT("info", ("File: '%s' handler: %d", path, file));
+ DBUG_RETURN(file);
+}
+
+
+/**
+ @brief get file descriptor by given number using cache
+
+ @param file_no Number of the log we want to open
+
+ retval # file descriptor
+ retval NULL file is not opened
+*/
+
+static TRANSLOG_FILE *get_logfile_by_number(uint32 file_no)
+{
+ TRANSLOG_FILE *file;
+ DBUG_ENTER("get_logfile_by_number");
+ rw_rdlock(&log_descriptor.open_files_lock);
+ if (log_descriptor.max_file - file_no >=
+ log_descriptor.open_files.elements)
+ {
+ DBUG_PRINT("info", ("File #%u is not opened", file_no));
+ rw_unlock(&log_descriptor.open_files_lock);
+ DBUG_RETURN(NULL);
+ }
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+ DBUG_ASSERT(log_descriptor.max_file >= file_no);
+ DBUG_ASSERT(log_descriptor.min_file <= file_no);
+
+ file= *dynamic_element(&log_descriptor.open_files,
+ log_descriptor.max_file - file_no, TRANSLOG_FILE **);
+ rw_unlock(&log_descriptor.open_files_lock);
+ DBUG_PRINT("info", ("File 0x%lx File no: %lu, File handler: %d",
+ (ulong)file, (ulong)file_no,
+ (file ? file->handler.file : -1)));
+ DBUG_ASSERT(!file || file->number == file_no);
+ DBUG_RETURN(file);
+}
+
+
+/**
+ @brief get current file descriptor
+
+ retval # file descriptor
+*/
+
+static TRANSLOG_FILE *get_current_logfile()
+{
+ TRANSLOG_FILE *file;
+ rw_rdlock(&log_descriptor.open_files_lock);
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+ file= *dynamic_element(&log_descriptor.open_files, 0, TRANSLOG_FILE **);
+ rw_unlock(&log_descriptor.open_files_lock);
+ return (file);
+}
+
+uchar NEAR maria_trans_file_magic[]=
+{ (uchar) 254, (uchar) 254, (uchar) 11, '\001', 'M', 'A', 'R', 'I', 'A',
+ 'L', 'O', 'G' };
+#define LOG_HEADER_DATA_SIZE (sizeof(maria_trans_file_magic) + \
+ 8 + 4 + 4 + 4 + 2 + 3 + \
+ LSN_STORE_SIZE)
+
+
+/*
+ Write log file page header in the just opened new log file
+
+ SYNOPSIS
+ translog_write_file_header();
+
+ NOTES
+ First page is just a marker page; We don't store any real log data in it.
+
+ RETURN
+ 0 OK
+ 1 ERROR
+*/
+
+static my_bool translog_write_file_header()
+{
+ TRANSLOG_FILE *file;
+ ulonglong timestamp;
+ uchar page_buff[TRANSLOG_PAGE_SIZE], *page= page_buff;
+ my_bool rc;
+ DBUG_ENTER("translog_write_file_header");
+
+ /* file tag */
+ memcpy(page, maria_trans_file_magic, sizeof(maria_trans_file_magic));
+ page+= sizeof(maria_trans_file_magic);
+ /* timestamp */
+ timestamp= my_getsystime();
+ int8store(page, timestamp);
+ page+= 8;
+ /* maria version */
+ int4store(page, TRANSLOG_VERSION_ID);
+ page+= 4;
+ /* mysql version (MYSQL_VERSION_ID) */
+ int4store(page, log_descriptor.server_version);
+ page+= 4;
+ /* server ID */
+ int4store(page, log_descriptor.server_id);
+ page+= 4;
+ /* loghandler page_size */
+ int2store(page, TRANSLOG_PAGE_SIZE - 1);
+ page+= 2;
+ /* file number */
+ int3store(page, LSN_FILE_NO(log_descriptor.horizon));
+ page+= 3;
+ lsn_store(page, LSN_IMPOSSIBLE);
+ page+= LSN_STORE_SIZE;
+ memset(page, TRANSLOG_FILLER, sizeof(page_buff) - (page- page_buff));
+
+ file= get_current_logfile();
+ rc= my_pwrite(file->handler.file, page_buff, sizeof(page_buff), 0,
+ log_write_flags) != 0;
+ /*
+ Dropping the flag in such way can make false alarm: signalling than the
+ file in not sync when it is sync, but the situation is quite rare and
+ protections with mutexes give much more overhead to the whole engine
+ */
+ file->is_sync= 0;
+ DBUG_RETURN(rc);
+}
+
+/*
+ @brief write the new LSN on the given file header
+
+ @param file The file descriptor
+ @param lsn That LSN which should be written
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_max_lsn_to_header(File file, LSN lsn)
+{
+ uchar lsn_buff[LSN_STORE_SIZE];
+ DBUG_ENTER("translog_max_lsn_to_header");
+ DBUG_PRINT("enter", ("File descriptor: %ld "
+ "lsn: (%lu,0x%lx)",
+ (long) file,
+ LSN_IN_PARTS(lsn)));
+
+ lsn_store(lsn_buff, lsn);
+
+ DBUG_RETURN(my_pwrite(file, lsn_buff,
+ LSN_STORE_SIZE,
+ (LOG_HEADER_DATA_SIZE - LSN_STORE_SIZE),
+ log_write_flags) != 0 ||
+ my_sync(file, MYF(MY_WME)) != 0);
+}
+
+
+/*
+ Information from transaction log file header
+*/
+
+typedef struct st_loghandler_file_info
+{
+ /*
+ LSN_IMPOSSIBLE for current file (not finished file).
+ Maximum LSN of the record which parts stored in the
+ file.
+ */
+ LSN max_lsn;
+ ulonglong timestamp; /* Time stamp */
+ ulong maria_version; /* Version of maria loghandler */
+ ulong mysql_version; /* Version of mysql server */
+ ulong server_id; /* Server ID */
+ ulong page_size; /* Loghandler page size */
+ ulong file_number; /* Number of the file (from the file header) */
+} LOGHANDLER_FILE_INFO;
+
+/*
+ @brief Extract hander file information from loghandler file page
+
+ @param desc header information descriptor to be filled with information
+ @param page_buff buffer with the page content
+*/
+
+static void translog_interpret_file_header(LOGHANDLER_FILE_INFO *desc,
+ uchar *page_buff)
+{
+ uchar *ptr;
+
+ ptr= page_buff + sizeof(maria_trans_file_magic);
+ desc->timestamp= uint8korr(ptr);
+ ptr+= 8;
+ desc->maria_version= uint4korr(ptr);
+ ptr+= 4;
+ desc->mysql_version= uint4korr(ptr);
+ ptr+= 4;
+ desc->server_id= uint4korr(ptr + 4);
+ ptr+= 4;
+ desc->page_size= uint2korr(ptr) + 1;
+ ptr+= 2;
+ desc->file_number= uint3korr(ptr);
+ ptr+=3;
+ desc->max_lsn= lsn_korr(ptr);
+}
+
+
+/*
+ @brief Read hander file information from loghandler file
+
+ @param desc header information descriptor to be filled with information
+ @param file file descriptor to read
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool translog_read_file_header(LOGHANDLER_FILE_INFO *desc, File file)
+{
+ uchar page_buff[LOG_HEADER_DATA_SIZE];
+ DBUG_ENTER("translog_read_file_header");
+
+ if (my_pread(file, page_buff,
+ sizeof(page_buff), 0, MYF(MY_FNABP | MY_WME)))
+ {
+ DBUG_PRINT("info", ("log read fail error: %d", my_errno));
+ DBUG_RETURN(1);
+ }
+ translog_interpret_file_header(desc, page_buff);
+ DBUG_PRINT("info", ("timestamp: %llu maria ver: %lu mysql ver: %lu "
+ "server id %lu page size %lu file number %lu "
+ "max lsn: (%lu,0x%lx)",
+ (ulonglong) desc->timestamp,
+ (ulong) desc->maria_version,
+ (ulong) desc->mysql_version,
+ (ulong) desc->server_id,
+ desc->page_size, (ulong) desc->file_number,
+ LSN_IN_PARTS(desc->max_lsn)));
+ DBUG_RETURN(0);
+}
+
+
+/*
+ @brief set the lsn to the files from_file - to_file if it is greater
+ then written in the file
+
+ @param from_file first file number (min)
+ @param to_file last file number (max)
+ @param lsn the lsn for writing
+ @param is_locked true if current thread locked the log handler
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_set_lsn_for_files(uint32 from_file, uint32 to_file,
+ LSN lsn, my_bool is_locked)
+{
+ uint32 file;
+ DBUG_ENTER("translog_set_lsn_for_files");
+ DBUG_PRINT("enter", ("From: %lu to: %lu lsn: (%lu,0x%lx) locked: %d",
+ (ulong) from_file, (ulong) to_file,
+ LSN_IN_PARTS(lsn),
+ is_locked));
+ DBUG_ASSERT(from_file <= to_file);
+ DBUG_ASSERT(from_file > 0); /* we have not file 0 */
+
+ /* Checks the current file (not finished yet file) */
+ if (!is_locked)
+ translog_lock();
+ if (to_file == (uint32) LSN_FILE_NO(log_descriptor.horizon))
+ {
+ if (likely(cmp_translog_addr(lsn, log_descriptor.max_lsn) > 0))
+ log_descriptor.max_lsn= lsn;
+ to_file--;
+ }
+ if (!is_locked)
+ translog_unlock();
+
+ /* Checks finished files if they are */
+ pthread_mutex_lock(&log_descriptor.file_header_lock);
+ for (file= from_file; file <= to_file; file++)
+ {
+ LOGHANDLER_FILE_INFO info;
+ File fd= open_logfile_by_number_no_cache(file);
+ if ((fd < 0) ||
+ ((translog_read_file_header(&info, fd) ||
+ (cmp_translog_addr(lsn, info.max_lsn) > 0 &&
+ translog_max_lsn_to_header(fd, lsn))) |
+ my_close(fd, MYF(MY_WME))))
+ {
+ translog_stop_writing();
+ DBUG_RETURN(1);
+ }
+ }
+ pthread_mutex_unlock(&log_descriptor.file_header_lock);
+
+ DBUG_RETURN(0);
+}
+
+
+/* descriptor of file in unfinished_files */
+struct st_file_counter
+{
+ uint32 file; /* file number */
+ uint32 counter; /* counter for started writes */
+};
+
+
+/*
+ @brief mark file "in progress" (for multi-group records)
+
+ @param file log file number
+*/
+
+static void translog_mark_file_unfinished(uint32 file)
+{
+ int place, i;
+ struct st_file_counter fc, *fc_ptr;
+
+ DBUG_ENTER("translog_mark_file_unfinished");
+ DBUG_PRINT("enter", ("file: %lu", (ulong) file));
+
+ fc.file= file; fc.counter= 1;
+ pthread_mutex_lock(&log_descriptor.unfinished_files_lock);
+
+ if (log_descriptor.unfinished_files.elements == 0)
+ {
+ insert_dynamic(&log_descriptor.unfinished_files, (uchar*) &fc);
+ DBUG_PRINT("info", ("The first element inserted"));
+ goto end;
+ }
+
+ for (place= log_descriptor.unfinished_files.elements - 1;
+ place >= 0;
+ place--)
+ {
+ fc_ptr= dynamic_element(&log_descriptor.unfinished_files,
+ place, struct st_file_counter *);
+ if (fc_ptr->file <= file)
+ break;
+ }
+
+ if (place >= 0 && fc_ptr->file == file)
+ {
+ fc_ptr->counter++;
+ DBUG_PRINT("info", ("counter increased"));
+ goto end;
+ }
+
+ if (place == (int)log_descriptor.unfinished_files.elements)
+ {
+ insert_dynamic(&log_descriptor.unfinished_files, (uchar*) &fc);
+ DBUG_PRINT("info", ("The last element inserted"));
+ goto end;
+ }
+ /* shift and assign new element */
+ insert_dynamic(&log_descriptor.unfinished_files,
+ (uchar*)
+ dynamic_element(&log_descriptor.unfinished_files,
+ log_descriptor.unfinished_files.elements- 1,
+ struct st_file_counter *));
+ for(i= log_descriptor.unfinished_files.elements - 1; i > place; i--)
+ {
+ /* we do not use set_dynamic() to avoid unneeded checks */
+ memcpy(dynamic_element(&log_descriptor.unfinished_files,
+ i, struct st_file_counter *),
+ dynamic_element(&log_descriptor.unfinished_files,
+ i + 1, struct st_file_counter *),
+ sizeof(struct st_file_counter));
+ }
+ memcpy(dynamic_element(&log_descriptor.unfinished_files,
+ place + 1, struct st_file_counter *),
+ &fc, sizeof(struct st_file_counter));
+end:
+ pthread_mutex_unlock(&log_descriptor.unfinished_files_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief remove file mark "in progress" (for multi-group records)
+
+ @param file log file number
+*/
+
+static void translog_mark_file_finished(uint32 file)
+{
+ int i;
+ struct st_file_counter *fc_ptr;
+ DBUG_ENTER("translog_mark_file_finished");
+ DBUG_PRINT("enter", ("file: %lu", (ulong) file));
+
+ LINT_INIT(fc_ptr);
+
+ pthread_mutex_lock(&log_descriptor.unfinished_files_lock);
+
+ DBUG_ASSERT(log_descriptor.unfinished_files.elements > 0);
+ for (i= 0;
+ i < (int) log_descriptor.unfinished_files.elements;
+ i++)
+ {
+ fc_ptr= dynamic_element(&log_descriptor.unfinished_files,
+ i, struct st_file_counter *);
+ if (fc_ptr->file == file)
+ {
+ break;
+ }
+ }
+ DBUG_ASSERT(i < (int) log_descriptor.unfinished_files.elements);
+
+ if (! --fc_ptr->counter)
+ delete_dynamic_element(&log_descriptor.unfinished_files, i);
+ pthread_mutex_unlock(&log_descriptor.unfinished_files_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief get max LSN of the record which parts stored in this file
+
+ @param file file number
+
+ @return requested LSN or LSN_IMPOSSIBLE/LSN_ERROR
+ @retval LSN_IMPOSSIBLE File is still not finished
+ @retval LSN_ERROR Error opening file
+ @retval # LSN of the record which parts stored in this file
+*/
+
+LSN translog_get_file_max_lsn_stored(uint32 file)
+{
+ uint32 limit= FILENO_IMPOSSIBLE;
+ DBUG_ENTER("translog_get_file_max_lsn_stored");
+ DBUG_PRINT("enter", ("file: %lu", (ulong)file));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ pthread_mutex_lock(&log_descriptor.unfinished_files_lock);
+
+ /* find file with minimum file number "in progress" */
+ if (log_descriptor.unfinished_files.elements > 0)
+ {
+ struct st_file_counter *fc_ptr;
+ fc_ptr= dynamic_element(&log_descriptor.unfinished_files,
+ 0, struct st_file_counter *);
+ limit= fc_ptr->file; /* minimal file number "in progress" */
+ }
+ pthread_mutex_unlock(&log_descriptor.unfinished_files_lock);
+
+ /*
+ if there is no "in progress file" then unfinished file is in progress
+ for sure
+ */
+ if (limit == FILENO_IMPOSSIBLE)
+ {
+ TRANSLOG_ADDRESS horizon= translog_get_horizon();
+ limit= LSN_FILE_NO(horizon);
+ }
+
+ if (file >= limit)
+ {
+ DBUG_PRINT("info", ("The file in in progress"));
+ DBUG_RETURN(LSN_IMPOSSIBLE);
+ }
+
+ {
+ LOGHANDLER_FILE_INFO info;
+ File fd= open_logfile_by_number_no_cache(file);
+ if ((fd < 0) ||
+ (translog_read_file_header(&info, fd) | my_close(fd, MYF(MY_WME))))
+ {
+ DBUG_PRINT("error", ("Can't read file header"));
+ DBUG_RETURN(LSN_ERROR);
+ }
+ DBUG_PRINT("info", ("Max lsn: (%lu,0x%lx)",
+ LSN_IN_PARTS(info.max_lsn)));
+ DBUG_RETURN(info.max_lsn);
+ }
+}
+
+/*
+ Initialize transaction log file buffer
+
+ SYNOPSIS
+ translog_buffer_init()
+ buffer The buffer to initialize
+ num Number of this buffer
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_buffer_init(struct st_translog_buffer *buffer, int num)
+{
+ DBUG_ENTER("translog_buffer_init");
+ buffer->prev_last_lsn= buffer->last_lsn= LSN_IMPOSSIBLE;
+ DBUG_PRINT("info", ("last_lsn and prev_last_lsn set to 0 buffer: 0x%lx",
+ (ulong) buffer));
+
+ buffer->buffer_no= (uint8) num;
+ /* This Buffer File */
+ buffer->file= NULL;
+ buffer->overlay= 0;
+ /* cache for current log */
+ memset(buffer->buffer, TRANSLOG_FILLER, TRANSLOG_WRITE_BUFFER);
+ /* Buffer size */
+ buffer->size= 0;
+ /* cond of thread which is waiting for buffer filling */
+ if (pthread_cond_init(&buffer->waiting_filling_buffer, 0))
+ DBUG_RETURN(1);
+ /* Number of records which are in copy progress */
+ buffer->copy_to_buffer_in_progress= 0;
+ /* list of waiting buffer ready threads */
+ buffer->waiting_flush= 0;
+ /*
+ Buffers locked by fallowing mutex. As far as buffers create logical
+ circle (after last buffer goes first) it trigger false alarm of deadlock
+ detect system, so we remove check of deadlock for this buffers. In deed
+ all mutex locks concentrated around current buffer except flushing
+ thread (but it is only one thread). One thread can't take more then
+ 2 buffer locks at once. So deadlock is impossible here.
+
+ To prevent false alarm of dead lock detection we switch dead lock
+ detection for one buffer in the middle of the buffers chain. Excluding
+ only one of eight buffers from deadlock detection hardly can hide other
+ possible problems which include this mutexes.
+ */
+ if (my_pthread_mutex_init(&buffer->mutex, MY_MUTEX_INIT_FAST,
+ "translog_buffer->mutex",
+ (num == TRANSLOG_BUFFERS_NO - 2 ?
+ MYF_NO_DEADLOCK_DETECTION : 0)) ||
+ pthread_cond_init(&buffer->prev_sent_to_disk_cond, 0))
+ DBUG_RETURN(1);
+ buffer->is_closing_buffer= 0;
+ buffer->prev_sent_to_disk= LSN_IMPOSSIBLE;
+ buffer->prev_buffer_offset= LSN_IMPOSSIBLE;
+ buffer->ver= 0;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ @brief close transaction log file by descriptor
+
+ @param file pagegecache file descriptor reference
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_close_log_file(TRANSLOG_FILE *file)
+{
+ int rc= 0;
+ flush_pagecache_blocks(log_descriptor.pagecache, &file->handler,
+ FLUSH_RELEASE);
+ /*
+ Sync file when we close it
+ TODO: sync only we have changed the log
+ */
+ if (!file->is_sync)
+ rc= my_sync(file->handler.file, MYF(MY_WME));
+ rc|= my_close(file->handler.file, MYF(MY_WME));
+ my_free(file, MYF(0));
+ return test(rc);
+}
+
+
+/**
+ @brief Dummy function for write failure (the log to not use
+ pagecache writing)
+*/
+
+void translog_dummy_write_failure(uchar *data __attribute__((unused)))
+{
+ return;
+}
+
+
+/**
+ @brief Initializes TRANSLOG_FILE structure
+
+ @param file reference on the file to initialize
+ @param number file number
+ @param is_sync is file synced on disk
+*/
+
+static void translog_file_init(TRANSLOG_FILE *file, uint32 number,
+ my_bool is_sync)
+{
+ pagecache_file_init(file->handler, &translog_page_validator,
+ &translog_dummy_callback,
+ &translog_dummy_write_failure,
+ maria_flush_log_for_page_none, file);
+ file->number= number;
+ file->was_recovered= 0;
+ file->is_sync= is_sync;
+}
+
+
+/**
+ @brief Create and fill header of new file.
+
+ @note the caller must call it right after it has increased
+ log_descriptor.horizon to the new file
+ (log_descriptor.horizon+= LSN_ONE_FILE)
+
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_create_new_file()
+{
+ TRANSLOG_FILE *file= (TRANSLOG_FILE*)my_malloc(sizeof(TRANSLOG_FILE),
+ MYF(0));
+
+ TRANSLOG_FILE *old= get_current_logfile();
+ uint32 file_no= LSN_FILE_NO(log_descriptor.horizon);
+ DBUG_ENTER("translog_create_new_file");
+
+ if (file == NULL)
+ goto error;
+
+ /*
+ Writes max_lsn to the file header before finishing it (there is no need
+ to lock file header buffer because it is still unfinished file, so only
+ one thread can finish the file and nobody interested of LSN of current
+ (unfinished) file, because no one can purge it).
+ */
+ if (translog_max_lsn_to_header(old->handler.file, log_descriptor.max_lsn))
+ goto error;
+
+ rw_wrlock(&log_descriptor.open_files_lock);
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+ DBUG_ASSERT(file_no == log_descriptor.max_file + 1);
+ if (allocate_dynamic(&log_descriptor.open_files,
+ log_descriptor.max_file - log_descriptor.min_file + 2))
+ goto error_lock;
+ if ((file->handler.file=
+ create_logfile_by_number_no_cache(file_no)) == -1)
+ goto error_lock;
+ translog_file_init(file, file_no, 0);
+
+ /* this call just expand the array */
+ insert_dynamic(&log_descriptor.open_files, (uchar*)&file);
+ log_descriptor.max_file++;
+ {
+ char *start= (char*) dynamic_element(&log_descriptor.open_files, 0,
+ TRANSLOG_FILE**);
+ memmove(start + sizeof(TRANSLOG_FILE*), start,
+ sizeof(TRANSLOG_FILE*) *
+ (log_descriptor.max_file - log_descriptor.min_file + 1 - 1));
+ }
+ /* can't fail we because we expanded array */
+ set_dynamic(&log_descriptor.open_files, (uchar*)&file, 0);
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+ rw_unlock(&log_descriptor.open_files_lock);
+
+ DBUG_PRINT("info", ("file_no: %lu", (ulong)file_no));
+
+ if (translog_write_file_header())
+ DBUG_RETURN(1);
+
+ if (ma_control_file_write_and_force(last_checkpoint_lsn, file_no,
+ max_trid_in_control_file,
+ recovery_failures))
+ {
+ translog_stop_writing();
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(0);
+
+error_lock:
+ rw_unlock(&log_descriptor.open_files_lock);
+error:
+ translog_stop_writing();
+ DBUG_RETURN(1);
+}
+
+
+/**
+ @brief Locks the loghandler buffer.
+
+ @param buffer This buffer which should be locked
+
+ @note See comment before buffer 'mutex' variable.
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static void translog_buffer_lock(struct st_translog_buffer *buffer)
+{
+ DBUG_ENTER("translog_buffer_lock");
+ DBUG_PRINT("enter",
+ ("Lock buffer #%u: (0x%lx)", (uint) buffer->buffer_no,
+ (ulong) buffer));
+ pthread_mutex_lock(&buffer->mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Unlock the loghandler buffer
+
+ SYNOPSIS
+ translog_buffer_unlock()
+ buffer This buffer which should be unlocked
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static void translog_buffer_unlock(struct st_translog_buffer *buffer)
+{
+ DBUG_ENTER("translog_buffer_unlock");
+ DBUG_PRINT("enter", ("Unlock buffer... #%u (0x%lx)",
+ (uint) buffer->buffer_no, (ulong) buffer));
+
+ pthread_mutex_unlock(&buffer->mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Write a header on the page
+
+ SYNOPSIS
+ translog_new_page_header()
+ horizon Where to write the page
+ cursor Where to write the page
+
+ NOTE
+ - space for page header should be checked before
+*/
+
+static uchar translog_sector_random;
+
+static void translog_new_page_header(TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor)
+{
+ uchar *ptr;
+
+ DBUG_ENTER("translog_new_page_header");
+ DBUG_ASSERT(cursor->ptr);
+
+ cursor->protected= 0;
+
+ ptr= cursor->ptr;
+ /* Page number */
+ int3store(ptr, LSN_OFFSET(*horizon) / TRANSLOG_PAGE_SIZE);
+ ptr+= 3;
+ /* File number */
+ int3store(ptr, LSN_FILE_NO(*horizon));
+ ptr+= 3;
+ DBUG_ASSERT(TRANSLOG_PAGE_FLAGS == (ptr - cursor->ptr));
+ cursor->ptr[TRANSLOG_PAGE_FLAGS]= (uchar) log_descriptor.flags;
+ ptr++;
+ if (log_descriptor.flags & TRANSLOG_PAGE_CRC)
+ {
+#ifndef DBUG_OFF
+ DBUG_PRINT("info", ("write 0x11223344 CRC to (%lu,0x%lx)",
+ LSN_IN_PARTS(*horizon)));
+ /* This will be overwritten by real CRC; This is just for debugging */
+ int4store(ptr, 0x11223344);
+#endif
+ /* CRC will be put when page is finished */
+ ptr+= CRC_SIZE;
+ }
+ if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
+ {
+ /*
+ translog_sector_randmo works like "random" values producer because
+ it is enough to have such "random" for this purpose and it will
+ not interfere with higher level pseudo random value generator
+ */
+ ptr[0]= translog_sector_random++;
+ ptr+= TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
+ }
+ {
+ uint len= (ptr - cursor->ptr);
+ (*horizon)+= len; /* increasing the offset part of the address */
+ cursor->current_page_fill= len;
+ if (!cursor->chaser)
+ cursor->buffer->size+= len;
+ }
+ cursor->ptr= ptr;
+ DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx chaser: %d Size: %lu (%lu) "
+ "Horizon: (%lu,0x%lx)",
+ (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
+ cursor->chaser, (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer),
+ LSN_IN_PARTS(*horizon)));
+ translog_check_cursor(cursor);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Put sector protection on the page image
+
+ SYNOPSIS
+ translog_put_sector_protection()
+ page reference on the page content
+ cursor cursor of the buffer
+
+ NOTES
+ We put a sector protection on all following sectors on the page,
+ except the first sector that is protected by page header.
+*/
+
+static void translog_put_sector_protection(uchar *page,
+ struct st_buffer_cursor *cursor)
+{
+ uchar *table= page + log_descriptor.page_overhead -
+ TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
+ uint i, offset;
+ uint16 last_protected_sector= ((cursor->previous_offset - 1) /
+ DISK_DRIVE_SECTOR_SIZE);
+ uint16 start_sector= cursor->previous_offset / DISK_DRIVE_SECTOR_SIZE;
+ uint8 value= table[0] + cursor->write_counter;
+ DBUG_ENTER("translog_put_sector_protection");
+
+ if (start_sector == 0)
+ {
+ /* First sector is protected by file & page numbers in the page header. */
+ start_sector= 1;
+ }
+
+ DBUG_PRINT("enter", ("Write counter:%u value:%u offset:%u, "
+ "last protected:%u start sector:%u",
+ (uint) cursor->write_counter,
+ (uint) value,
+ (uint) cursor->previous_offset,
+ (uint) last_protected_sector, (uint) start_sector));
+ if (last_protected_sector == start_sector)
+ {
+ i= last_protected_sector;
+ offset= last_protected_sector * DISK_DRIVE_SECTOR_SIZE;
+ /* restore data, because we modified sector which was protected */
+ if (offset < cursor->previous_offset)
+ page[offset]= table[i];
+ }
+ for (i= start_sector, offset= start_sector * DISK_DRIVE_SECTOR_SIZE;
+ i < TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
+ i++, (offset+= DISK_DRIVE_SECTOR_SIZE))
+ {
+ DBUG_PRINT("info", ("sector:%u offset:%u data 0x%x",
+ i, offset, (uint) page[offset]));
+ table[i]= page[offset];
+ page[offset]= value;
+ DBUG_PRINT("info", ("sector:%u offset:%u data 0x%x",
+ i, offset, (uint) page[offset]));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Calculate CRC32 of given area
+
+ SYNOPSIS
+ translog_crc()
+ area Pointer of the area beginning
+ length The Area length
+
+ RETURN
+ CRC32
+*/
+
+static uint32 translog_crc(uchar *area, uint length)
+{
+ DBUG_ENTER("translog_crc");
+ DBUG_RETURN(crc32(0L, (unsigned char*) area, length));
+}
+
+
+/*
+ Finish current page with zeros
+
+ SYNOPSIS
+ translog_finish_page()
+ horizon \ horizon & buffer pointers
+ cursor /
+*/
+
+static void translog_finish_page(TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor)
+{
+ uint16 left= TRANSLOG_PAGE_SIZE - cursor->current_page_fill;
+ uchar *page= cursor->ptr - cursor->current_page_fill;
+ DBUG_ENTER("translog_finish_page");
+ DBUG_PRINT("enter", ("Buffer: #%u 0x%lx "
+ "Buffer addr: (%lu,0x%lx) "
+ "Page addr: (%lu,0x%lx) "
+ "size:%lu (%lu) Pg:%u left:%u",
+ (uint) cursor->buffer_no, (ulong) cursor->buffer,
+ LSN_IN_PARTS(cursor->buffer->offset),
+ (ulong) LSN_FILE_NO(*horizon),
+ (ulong) (LSN_OFFSET(*horizon) -
+ cursor->current_page_fill),
+ (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr -cursor->buffer->buffer),
+ (uint) cursor->current_page_fill, (uint) left));
+ DBUG_ASSERT(LSN_FILE_NO(*horizon) == LSN_FILE_NO(cursor->buffer->offset));
+ translog_check_cursor(cursor);
+ if (cursor->protected)
+ {
+ DBUG_PRINT("info", ("Already protected and finished"));
+ DBUG_VOID_RETURN;
+ }
+ cursor->protected= 1;
+
+ DBUG_ASSERT(left < TRANSLOG_PAGE_SIZE);
+ if (left != 0)
+ {
+ DBUG_PRINT("info", ("left: %u", (uint) left));
+ memset(cursor->ptr, TRANSLOG_FILLER, left);
+ cursor->ptr+= left;
+ (*horizon)+= left; /* offset increasing */
+ if (!cursor->chaser)
+ cursor->buffer->size+= left;
+ /* We are finishing the page so reset the counter */
+ cursor->current_page_fill= 0;
+ DBUG_PRINT("info", ("Finish Page buffer #%u: 0x%lx "
+ "chaser: %d Size: %lu (%lu)",
+ (uint) cursor->buffer->buffer_no,
+ (ulong) cursor->buffer, cursor->chaser,
+ (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer)));
+ translog_check_cursor(cursor);
+ }
+ /*
+ When we are finishing the page other thread might not finish the page
+ header yet (in case if we started from the middle of the page) so we
+ have to read log_descriptor.flags but not the flags from the page.
+ */
+ if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
+ {
+ translog_put_sector_protection(page, cursor);
+ DBUG_PRINT("info", ("drop write_counter"));
+ cursor->write_counter= 0;
+ cursor->previous_offset= 0;
+ }
+ if (log_descriptor.flags & TRANSLOG_PAGE_CRC)
+ {
+ uint32 crc= translog_crc(page + log_descriptor.page_overhead,
+ TRANSLOG_PAGE_SIZE -
+ log_descriptor.page_overhead);
+ DBUG_PRINT("info", ("CRC: %lx", (ulong) crc));
+ /* We have page number, file number and flag before crc */
+ int4store(page + 3 + 3 + 1, crc);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief Wait until all threads have finished closing this buffer.
+
+ @param buffer This buffer should be check
+*/
+
+static void translog_wait_for_closing(struct st_translog_buffer *buffer)
+{
+ DBUG_ENTER("translog_wait_for_closing");
+ DBUG_PRINT("enter", ("Buffer #%u 0x%lx copies in progress: %u "
+ "is closing %u File: %d size: %lu",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ (uint) buffer->copy_to_buffer_in_progress,
+ (uint) buffer->is_closing_buffer,
+ (buffer->file ? buffer->file->handler.file : -1),
+ (ulong) buffer->size));
+ translog_buffer_lock_assert_owner(buffer);
+
+ while (buffer->is_closing_buffer)
+ {
+ DBUG_PRINT("info", ("wait for writers... buffer: #%u 0x%lx",
+ (uint) buffer->buffer_no, (ulong) buffer));
+ DBUG_ASSERT(buffer->file != NULL);
+ pthread_cond_wait(&buffer->waiting_filling_buffer, &buffer->mutex);
+ DBUG_PRINT("info", ("wait for writers done buffer: #%u 0x%lx",
+ (uint) buffer->buffer_no, (ulong) buffer));
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief Wait until all threads have finished filling this buffer.
+
+ @param buffer This buffer should be check
+*/
+
+static void translog_wait_for_writers(struct st_translog_buffer *buffer)
+{
+ DBUG_ENTER("translog_wait_for_writers");
+ DBUG_PRINT("enter", ("Buffer #%u 0x%lx copies in progress: %u "
+ "is closing %u File: %d size: %lu",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ (uint) buffer->copy_to_buffer_in_progress,
+ (uint) buffer->is_closing_buffer,
+ (buffer->file ? buffer->file->handler.file : -1),
+ (ulong) buffer->size));
+ translog_buffer_lock_assert_owner(buffer);
+
+ while (buffer->copy_to_buffer_in_progress)
+ {
+ DBUG_PRINT("info", ("wait for writers... buffer: #%u 0x%lx",
+ (uint) buffer->buffer_no, (ulong) buffer));
+ DBUG_ASSERT(buffer->file != NULL);
+ pthread_cond_wait(&buffer->waiting_filling_buffer, &buffer->mutex);
+ DBUG_PRINT("info", ("wait for writers done buffer: #%u 0x%lx",
+ (uint) buffer->buffer_no, (ulong) buffer));
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+
+ Wait for buffer to become free
+
+ SYNOPSIS
+ translog_wait_for_buffer_free()
+ buffer The buffer we are waiting for
+
+ NOTE
+ - this buffer should be locked
+*/
+
+static void translog_wait_for_buffer_free(struct st_translog_buffer *buffer)
+{
+ TRANSLOG_ADDRESS offset= buffer->offset;
+ TRANSLOG_FILE *file= buffer->file;
+ uint8 ver= buffer->ver;
+ DBUG_ENTER("translog_wait_for_buffer_free");
+ DBUG_PRINT("enter", ("Buffer #%u 0x%lx copies in progress: %u "
+ "is closing %u File: %d size: %lu",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ (uint) buffer->copy_to_buffer_in_progress,
+ (uint) buffer->is_closing_buffer,
+ (buffer->file ? buffer->file->handler.file : -1),
+ (ulong) buffer->size));
+
+ translog_wait_for_writers(buffer);
+
+ if (offset != buffer->offset || file != buffer->file || ver != buffer->ver)
+ DBUG_VOID_RETURN; /* the buffer if already freed */
+
+ while (buffer->file != NULL)
+ {
+ DBUG_PRINT("info", ("wait for writers... buffer: #%u 0x%lx",
+ (uint) buffer->buffer_no, (ulong) buffer));
+ pthread_cond_wait(&buffer->waiting_filling_buffer, &buffer->mutex);
+ DBUG_PRINT("info", ("wait for writers done. buffer: #%u 0x%lx",
+ (uint) buffer->buffer_no, (ulong) buffer));
+ }
+ DBUG_ASSERT(buffer->copy_to_buffer_in_progress == 0);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Initialize the cursor for a buffer
+
+ SYNOPSIS
+ translog_cursor_init()
+ buffer The buffer
+ cursor It's cursor
+ buffer_no Number of buffer
+*/
+
+static void translog_cursor_init(struct st_buffer_cursor *cursor,
+ struct st_translog_buffer *buffer,
+ uint8 buffer_no)
+{
+ DBUG_ENTER("translog_cursor_init");
+ cursor->ptr= buffer->buffer;
+ cursor->buffer= buffer;
+ cursor->buffer_no= buffer_no;
+ cursor->current_page_fill= 0;
+ cursor->chaser= (cursor != &log_descriptor.bc);
+ cursor->write_counter= 0;
+ cursor->previous_offset= 0;
+ cursor->protected= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief Initialize buffer for the current file, and a cursor for this buffer.
+
+ @param buffer The buffer
+ @param cursor It's cursor
+ @param buffer_no Number of buffer
+*/
+
+static void translog_start_buffer(struct st_translog_buffer *buffer,
+ struct st_buffer_cursor *cursor,
+ uint buffer_no)
+{
+ DBUG_ENTER("translog_start_buffer");
+ DBUG_PRINT("enter",
+ ("Assign buffer: #%u (0x%lx) offset: 0x%lx(%lu)",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ (ulong) LSN_OFFSET(log_descriptor.horizon),
+ (ulong) LSN_OFFSET(log_descriptor.horizon)));
+ DBUG_ASSERT(buffer_no == buffer->buffer_no);
+ buffer->prev_last_lsn= buffer->last_lsn= LSN_IMPOSSIBLE;
+ DBUG_PRINT("info", ("last_lsn and prev_last_lsn set to 0 buffer: 0x%lx",
+ (ulong) buffer));
+ buffer->offset= log_descriptor.horizon;
+ buffer->next_buffer_offset= LSN_IMPOSSIBLE;
+ buffer->file= get_current_logfile();
+ buffer->overlay= 0;
+ buffer->size= 0;
+ translog_cursor_init(cursor, buffer, buffer_no);
+ DBUG_PRINT("info", ("file: #%ld (%d) init cursor #%u: 0x%lx "
+ "chaser: %d Size: %lu (%lu)",
+ (long) (buffer->file ? buffer->file->number : 0),
+ (buffer->file ? buffer->file->handler.file : -1),
+ (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
+ cursor->chaser, (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer)));
+ translog_check_cursor(cursor);
+ pthread_mutex_lock(&log_descriptor.dirty_buffer_mask_lock);
+ log_descriptor.dirty_buffer_mask|= (1 << buffer->buffer_no);
+ pthread_mutex_unlock(&log_descriptor.dirty_buffer_mask_lock);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief Switch to the next buffer in a chain.
+
+ @param horizon \ Pointers on current position in file and buffer
+ @param cursor /
+ @param new_file Also start new file
+
+ @note
+ - loghandler should be locked
+ - after return new and old buffer still are locked
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_buffer_next(TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor,
+ my_bool new_file)
+{
+ uint old_buffer_no= cursor->buffer_no;
+ uint new_buffer_no= (old_buffer_no + 1) % TRANSLOG_BUFFERS_NO;
+ struct st_translog_buffer *new_buffer= log_descriptor.buffers + new_buffer_no;
+ my_bool chasing= cursor->chaser;
+ DBUG_ENTER("translog_buffer_next");
+
+ DBUG_PRINT("info", ("horizon: (%lu,0x%lx) chasing: %d",
+ LSN_IN_PARTS(log_descriptor.horizon), chasing));
+
+ DBUG_ASSERT(cmp_translog_addr(log_descriptor.horizon, *horizon) >= 0);
+
+ translog_finish_page(horizon, cursor);
+
+ if (!chasing)
+ {
+ translog_buffer_lock(new_buffer);
+#ifndef DBUG_OFF
+ {
+ TRANSLOG_ADDRESS offset= new_buffer->offset;
+ TRANSLOG_FILE *file= new_buffer->file;
+ uint8 ver= new_buffer->ver;
+ translog_lock_assert_owner();
+#endif
+ translog_wait_for_buffer_free(new_buffer);
+#ifndef DBUG_OFF
+ /* We keep the handler locked so nobody can start this new buffer */
+ DBUG_ASSERT(offset == new_buffer->offset && new_buffer->file == NULL &&
+ (file == NULL ? ver : (uint8)(ver + 1)) == new_buffer->ver);
+ }
+#endif
+ }
+ else
+ DBUG_ASSERT(new_buffer->file != NULL);
+
+ if (new_file)
+ {
+ /* move the horizon to the next file and its header page */
+ (*horizon)+= LSN_ONE_FILE;
+ (*horizon)= LSN_REPLACE_OFFSET(*horizon, TRANSLOG_PAGE_SIZE);
+ if (!chasing && translog_create_new_file())
+ {
+ DBUG_RETURN(1);
+ }
+ }
+
+ /* prepare next page */
+ if (chasing)
+ translog_cursor_init(cursor, new_buffer, new_buffer_no);
+ else
+ {
+ translog_lock_assert_owner();
+ translog_start_buffer(new_buffer, cursor, new_buffer_no);
+ new_buffer->prev_buffer_offset=
+ log_descriptor.buffers[old_buffer_no].offset;
+ new_buffer->prev_last_lsn=
+ BUFFER_MAX_LSN(log_descriptor.buffers + old_buffer_no);
+ }
+ log_descriptor.buffers[old_buffer_no].next_buffer_offset= new_buffer->offset;
+ DBUG_PRINT("info", ("prev_last_lsn set to (%lu,0x%lx) buffer: 0x%lx",
+ LSN_IN_PARTS(new_buffer->prev_last_lsn),
+ (ulong) new_buffer));
+ translog_new_page_header(horizon, cursor);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Sets max LSN sent to file, and address from which data is only in the buffer
+
+ SYNOPSIS
+ translog_set_sent_to_disk()
+ buffer buffer which we have sent to disk
+
+ TODO: use atomic operations if possible (64bit architectures?)
+*/
+
+static void translog_set_sent_to_disk(struct st_translog_buffer *buffer)
+{
+ LSN lsn= buffer->last_lsn;
+ TRANSLOG_ADDRESS in_buffers= buffer->next_buffer_offset;
+
+ DBUG_ENTER("translog_set_sent_to_disk");
+ pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
+ DBUG_PRINT("enter", ("lsn: (%lu,0x%lx) in_buffers: (%lu,0x%lx) "
+ "in_buffers_only: (%lu,0x%lx) start: (%lu,0x%lx) "
+ "sent_to_disk: (%lu,0x%lx)",
+ LSN_IN_PARTS(lsn),
+ LSN_IN_PARTS(in_buffers),
+ LSN_IN_PARTS(log_descriptor.log_start),
+ LSN_IN_PARTS(log_descriptor.in_buffers_only),
+ LSN_IN_PARTS(log_descriptor.sent_to_disk)));
+ /*
+ We write sequentially (first part of following assert) but we rewrite
+ the same page in case we started mysql and shut it down immediately
+ (second part of the following assert)
+ */
+ DBUG_ASSERT(cmp_translog_addr(lsn, log_descriptor.sent_to_disk) >= 0 ||
+ cmp_translog_addr(lsn, log_descriptor.log_start) < 0);
+ log_descriptor.sent_to_disk= lsn;
+ /* LSN_IMPOSSIBLE == 0 => it will work for very first time */
+ if (cmp_translog_addr(in_buffers, log_descriptor.in_buffers_only) > 0)
+ {
+ log_descriptor.in_buffers_only= in_buffers;
+ DBUG_PRINT("info", ("set new in_buffers_only"));
+ }
+ pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Sets address from which data is only in the buffer
+
+ SYNOPSIS
+ translog_set_only_in_buffers()
+ lsn LSN to assign
+ in_buffers to assign to in_buffers_only
+*/
+
+static void translog_set_only_in_buffers(TRANSLOG_ADDRESS in_buffers)
+{
+ DBUG_ENTER("translog_set_only_in_buffers");
+ pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
+ DBUG_PRINT("enter", ("in_buffers: (%lu,0x%lx) "
+ "in_buffers_only: (%lu,0x%lx)",
+ LSN_IN_PARTS(in_buffers),
+ LSN_IN_PARTS(log_descriptor.in_buffers_only)));
+ /* LSN_IMPOSSIBLE == 0 => it will work for very first time */
+ if (cmp_translog_addr(in_buffers, log_descriptor.in_buffers_only) > 0)
+ {
+ if (translog_status != TRANSLOG_OK)
+ DBUG_VOID_RETURN;
+ log_descriptor.in_buffers_only= in_buffers;
+ DBUG_PRINT("info", ("set new in_buffers_only"));
+ }
+ pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Gets address from which data is only in the buffer
+
+ SYNOPSIS
+ translog_only_in_buffers()
+
+ RETURN
+ address from which data is only in the buffer
+*/
+
+static TRANSLOG_ADDRESS translog_only_in_buffers()
+{
+ register TRANSLOG_ADDRESS addr;
+ DBUG_ENTER("translog_only_in_buffers");
+ pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
+ addr= log_descriptor.in_buffers_only;
+ pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
+ DBUG_RETURN(addr);
+}
+
+
+/*
+ Get max LSN sent to file
+
+ SYNOPSIS
+ translog_get_sent_to_disk()
+
+ RETURN
+ max LSN send to file
+*/
+
+static LSN translog_get_sent_to_disk()
+{
+ register LSN lsn;
+ DBUG_ENTER("translog_get_sent_to_disk");
+ pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
+ lsn= log_descriptor.sent_to_disk;
+ DBUG_PRINT("info", ("sent to disk up to (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
+ pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
+ DBUG_RETURN(lsn);
+}
+
+
+/*
+ Get first chunk address on the given page
+
+ SYNOPSIS
+ translog_get_first_chunk_offset()
+ page The page where to find first chunk
+
+ RETURN
+ first chunk offset
+*/
+
+static my_bool translog_get_first_chunk_offset(uchar *page)
+{
+ DBUG_ENTER("translog_get_first_chunk_offset");
+ DBUG_ASSERT(page[TRANSLOG_PAGE_FLAGS] < TRANSLOG_FLAGS_NUM);
+ DBUG_RETURN(page_overhead[page[TRANSLOG_PAGE_FLAGS]]);
+}
+
+
+/*
+ Write coded length of record
+
+ SYNOPSIS
+ translog_write_variable_record_1group_code_len
+ dst Destination buffer pointer
+ length Length which should be coded
+ header_len Calculated total header length
+*/
+
+static void
+translog_write_variable_record_1group_code_len(uchar *dst,
+ translog_size_t length,
+ uint16 header_len)
+{
+ switch (header_len) {
+ case 6: /* (5 + 1) */
+ DBUG_ASSERT(length <= 250);
+ *dst= (uint8) length;
+ return;
+ case 8: /* (5 + 3) */
+ DBUG_ASSERT(length <= 0xFFFF);
+ *dst= 251;
+ int2store(dst + 1, length);
+ return;
+ case 9: /* (5 + 4) */
+ DBUG_ASSERT(length <= (ulong) 0xFFFFFF);
+ *dst= 252;
+ int3store(dst + 1, length);
+ return;
+ case 10: /* (5 + 5) */
+ *dst= 253;
+ int4store(dst + 1, length);
+ return;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return;
+}
+
+
+/*
+ Decode record data length and advance given pointer to the next field
+
+ SYNOPSIS
+ translog_variable_record_1group_decode_len()
+ src The pointer to the pointer to the length beginning
+
+ RETURN
+ decoded length
+*/
+
+static translog_size_t translog_variable_record_1group_decode_len(uchar **src)
+{
+ uint8 first= (uint8) (**src);
+ switch (first) {
+ case 251:
+ (*src)+= 3;
+ return (uint2korr((*src) - 2));
+ case 252:
+ (*src)+= 4;
+ return (uint3korr((*src) - 3));
+ case 253:
+ (*src)+= 5;
+ return (uint4korr((*src) - 4));
+ case 254:
+ case 255:
+ DBUG_ASSERT(0); /* reserved for future use */
+ return (0);
+ default:
+ (*src)++;
+ return (first);
+ }
+}
+
+
+/*
+ Get total length of this chunk (not only body)
+
+ SYNOPSIS
+ translog_get_total_chunk_length()
+ page The page where chunk placed
+ offset Offset of the chunk on this place
+
+ RETURN
+ total length of the chunk
+*/
+
+static uint16 translog_get_total_chunk_length(uchar *page, uint16 offset)
+{
+ DBUG_ENTER("translog_get_total_chunk_length");
+ switch (page[offset] & TRANSLOG_CHUNK_TYPE) {
+ case TRANSLOG_CHUNK_LSN:
+ {
+ /* 0 chunk referred as LSN (head or tail) */
+ translog_size_t rec_len;
+ uchar *start= page + offset;
+ uchar *ptr= start + 1 + 2; /* chunk type and short trid */
+ uint16 chunk_len, header_len, page_rest;
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_LSN"));
+ rec_len= translog_variable_record_1group_decode_len(&ptr);
+ chunk_len= uint2korr(ptr);
+ header_len= (uint16) (ptr -start) + 2;
+ DBUG_PRINT("info", ("rec len: %lu chunk len: %u header len: %u",
+ (ulong) rec_len, (uint) chunk_len, (uint) header_len));
+ if (chunk_len)
+ {
+ DBUG_PRINT("info", ("chunk len: %u + %u = %u",
+ (uint) header_len, (uint) chunk_len,
+ (uint) (chunk_len + header_len)));
+ DBUG_RETURN(chunk_len + header_len);
+ }
+ page_rest= TRANSLOG_PAGE_SIZE - offset;
+ DBUG_PRINT("info", ("page_rest %u", (uint) page_rest));
+ if (rec_len + header_len < page_rest)
+ DBUG_RETURN(rec_len + header_len);
+ DBUG_RETURN(page_rest);
+ }
+ case TRANSLOG_CHUNK_FIXED:
+ {
+ uchar *ptr;
+ uint type= page[offset] & TRANSLOG_REC_TYPE;
+ uint length;
+ int i;
+ /* 1 (pseudo)fixed record (also LSN) */
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_FIXED"));
+ DBUG_ASSERT(log_record_type_descriptor[type].rclass ==
+ LOGRECTYPE_FIXEDLENGTH ||
+ log_record_type_descriptor[type].rclass ==
+ LOGRECTYPE_PSEUDOFIXEDLENGTH);
+ if (log_record_type_descriptor[type].rclass == LOGRECTYPE_FIXEDLENGTH)
+ {
+ DBUG_PRINT("info",
+ ("Fixed length: %u",
+ (uint) (log_record_type_descriptor[type].fixed_length + 3)));
+ DBUG_RETURN(log_record_type_descriptor[type].fixed_length + 3);
+ }
+
+ ptr= page + offset + 3; /* first compressed LSN */
+ length= log_record_type_descriptor[type].fixed_length + 3;
+ for (i= 0; i < log_record_type_descriptor[type].compressed_LSN; i++)
+ {
+ /* first 2 bits is length - 2 */
+ uint len= (((uint8) (*ptr)) >> 6) + 2;
+ if (ptr[0] == 0 && ((uint8) ptr[1]) == 1)
+ len+= LSN_STORE_SIZE; /* case of full LSN storing */
+ ptr+= len;
+ /* subtract saved bytes */
+ length-= (LSN_STORE_SIZE - len);
+ }
+ DBUG_PRINT("info", ("Pseudo-fixed length: %u", length));
+ DBUG_RETURN(length);
+ }
+ case TRANSLOG_CHUNK_NOHDR:
+ /* 2 no header chunk (till page end) */
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_NOHDR length: %u",
+ (uint) (TRANSLOG_PAGE_SIZE - offset)));
+ DBUG_RETURN(TRANSLOG_PAGE_SIZE - offset);
+ case TRANSLOG_CHUNK_LNGTH: /* 3 chunk with chunk length */
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_LNGTH"));
+ DBUG_ASSERT(TRANSLOG_PAGE_SIZE - offset >= 3);
+ DBUG_PRINT("info", ("length: %u", uint2korr(page + offset + 1) + 3));
+ DBUG_RETURN(uint2korr(page + offset + 1) + 3);
+ default:
+ DBUG_ASSERT(0);
+ DBUG_RETURN(0);
+ }
+}
+
+/*
+ @brief Waits previous buffer flush finish
+
+ @param buffer buffer for check
+
+ @retval 0 previous buffer flushed and this thread have to flush this one
+ @retval 1 previous buffer flushed and this buffer flushed by other thread too
+*/
+
+my_bool translog_prev_buffer_flush_wait(struct st_translog_buffer *buffer)
+{
+ TRANSLOG_ADDRESS offset= buffer->offset;
+ TRANSLOG_FILE *file= buffer->file;
+ uint8 ver= buffer->ver;
+ DBUG_ENTER("translog_prev_buffer_flush_wait");
+ DBUG_PRINT("enter", ("buffer: 0x%lx #%u offset: (%lu,0x%lx) "
+ "prev sent: (%lu,0x%lx) prev offset: (%lu,0x%lx)",
+ (ulong) buffer, (uint) buffer->buffer_no,
+ LSN_IN_PARTS(buffer->offset),
+ LSN_IN_PARTS(buffer->prev_sent_to_disk),
+ LSN_IN_PARTS(buffer->prev_buffer_offset)));
+ translog_buffer_lock_assert_owner(buffer);
+ /*
+ if prev_sent_to_disk == LSN_IMPOSSIBLE then
+ prev_buffer_offset should be LSN_IMPOSSIBLE
+ because it means that this buffer was never used
+ */
+ DBUG_ASSERT((buffer->prev_sent_to_disk == LSN_IMPOSSIBLE &&
+ buffer->prev_buffer_offset == LSN_IMPOSSIBLE) ||
+ buffer->prev_sent_to_disk != LSN_IMPOSSIBLE);
+ if (buffer->prev_buffer_offset != buffer->prev_sent_to_disk)
+ {
+ do {
+ pthread_cond_wait(&buffer->prev_sent_to_disk_cond, &buffer->mutex);
+ if (buffer->file != file || buffer->offset != offset ||
+ buffer->ver != ver)
+ {
+ translog_buffer_unlock(buffer);
+ DBUG_RETURN(1); /* some the thread flushed the buffer already */
+ }
+ } while(buffer->prev_buffer_offset != buffer->prev_sent_to_disk);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Flush given buffer
+
+ SYNOPSIS
+ translog_buffer_flush()
+ buffer This buffer should be flushed
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_buffer_flush(struct st_translog_buffer *buffer)
+{
+ uint32 i, pg;
+ TRANSLOG_ADDRESS offset= buffer->offset;
+ TRANSLOG_FILE *file= buffer->file;
+ uint8 ver= buffer->ver;
+ DBUG_ENTER("translog_buffer_flush");
+ DBUG_PRINT("enter",
+ ("Buffer: #%u 0x%lx file: %d offset: (%lu,0x%lx) size: %lu",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ buffer->file->handler.file,
+ LSN_IN_PARTS(buffer->offset),
+ (ulong) buffer->size));
+ translog_buffer_lock_assert_owner(buffer);
+
+ if (buffer->file == NULL)
+ DBUG_RETURN(0);
+
+ translog_wait_for_writers(buffer);
+
+ if (buffer->file != file || buffer->offset != offset || buffer->ver != ver)
+ DBUG_RETURN(0); /* some the thread flushed the buffer already */
+
+ if (buffer->is_closing_buffer)
+ {
+ /* some other flush in progress */
+ translog_wait_for_closing(buffer);
+ }
+
+ if (buffer->file != file || buffer->offset != offset || buffer->ver != ver)
+ DBUG_RETURN(0); /* some the thread flushed the buffer already */
+
+ if (buffer->overlay && translog_prev_buffer_flush_wait(buffer))
+ DBUG_RETURN(0); /* some the thread flushed the buffer already */
+
+ /*
+ Send page by page in the pagecache what we are going to write on the
+ disk
+ */
+ file= buffer->file;
+ for (i= 0, pg= LSN_OFFSET(buffer->offset) / TRANSLOG_PAGE_SIZE;
+ i < buffer->size;
+ i+= TRANSLOG_PAGE_SIZE, pg++)
+ {
+ TRANSLOG_ADDRESS addr= (buffer->offset + i);
+ TRANSLOG_VALIDATOR_DATA data;
+ DBUG_PRINT("info", ("send log form %lu till %lu address: (%lu,0x%lx) "
+ "page #: %lu buffer size: %lu buffer: 0x%lx",
+ (ulong) i, (ulong) (i + TRANSLOG_PAGE_SIZE),
+ LSN_IN_PARTS(addr), (ulong) pg, (ulong) buffer->size,
+ (ulong) buffer));
+ data.addr= &addr;
+ DBUG_ASSERT(log_descriptor.pagecache->block_size == TRANSLOG_PAGE_SIZE);
+ DBUG_ASSERT(i + TRANSLOG_PAGE_SIZE <= buffer->size);
+ if (translog_status != TRANSLOG_OK && translog_status != TRANSLOG_SHUTDOWN)
+ DBUG_RETURN(1);
+ if (pagecache_inject(log_descriptor.pagecache,
+ &file->handler, pg, 3,
+ buffer->buffer + i,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED, 0,
+ LSN_IMPOSSIBLE))
+ {
+ DBUG_PRINT("error",
+ ("Can't write page (%lu,0x%lx) to pagecache, error: %d",
+ (ulong) buffer->file->number,
+ (ulong) (LSN_OFFSET(buffer->offset)+ i),
+ my_errno));
+ translog_stop_writing();
+ DBUG_RETURN(1);
+ }
+ }
+ file->is_sync= 0;
+ if (my_pwrite(file->handler.file, buffer->buffer,
+ buffer->size, LSN_OFFSET(buffer->offset),
+ log_write_flags))
+ {
+ DBUG_PRINT("error", ("Can't write buffer (%lu,0x%lx) size %lu "
+ "to the disk (%d)",
+ (ulong) file->handler.file,
+ (ulong) LSN_OFFSET(buffer->offset),
+ (ulong) buffer->size, errno));
+ translog_stop_writing();
+ DBUG_RETURN(1);
+ }
+ /*
+ Dropping the flag in such way can make false alarm: signalling than the
+ file in not sync when it is sync, but the situation is quite rare and
+ protections with mutexes give much more overhead to the whole engine
+ */
+ file->is_sync= 0;
+
+ if (LSN_OFFSET(buffer->last_lsn) != 0) /* if buffer->last_lsn is set */
+ {
+ if (translog_prev_buffer_flush_wait(buffer))
+ DBUG_RETURN(0); /* some the thread flushed the buffer already */
+ translog_set_sent_to_disk(buffer);
+ }
+ else
+ translog_set_only_in_buffers(buffer->next_buffer_offset);
+
+ /* say to next buffer that we are finished */
+ {
+ struct st_translog_buffer *next_buffer=
+ log_descriptor.buffers + ((buffer->buffer_no + 1) % TRANSLOG_BUFFERS_NO);
+ if (likely(translog_status == TRANSLOG_OK)){
+ translog_buffer_lock(next_buffer);
+ next_buffer->prev_sent_to_disk= buffer->offset;
+ translog_buffer_unlock(next_buffer);
+ pthread_cond_broadcast(&next_buffer->prev_sent_to_disk_cond);
+ }
+ else
+ {
+ /*
+ It is shutdown =>
+ 1) there is only one thread
+ 2) mutexes of other buffers can be destroyed => we can't use them
+ */
+ next_buffer->prev_sent_to_disk= buffer->offset;
+ }
+ }
+ /* Free buffer */
+ buffer->file= NULL;
+ buffer->overlay= 0;
+ buffer->ver++;
+ pthread_mutex_lock(&log_descriptor.dirty_buffer_mask_lock);
+ log_descriptor.dirty_buffer_mask&= ~(1 << buffer->buffer_no);
+ pthread_mutex_unlock(&log_descriptor.dirty_buffer_mask_lock);
+ pthread_cond_broadcast(&buffer->waiting_filling_buffer);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Recover page with sector protection (wipe out failed chunks)
+
+ SYNOPSYS
+ translog_recover_page_up_to_sector()
+ page reference on the page
+ offset offset of failed sector
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_recover_page_up_to_sector(uchar *page, uint16 offset)
+{
+ uint16 chunk_offset= translog_get_first_chunk_offset(page), valid_chunk_end;
+ DBUG_ENTER("translog_recover_page_up_to_sector");
+ DBUG_PRINT("enter", ("offset: %u first chunk: %u",
+ (uint) offset, (uint) chunk_offset));
+
+ while (page[chunk_offset] != TRANSLOG_FILLER && chunk_offset < offset)
+ {
+ uint16 chunk_length;
+ if ((chunk_length=
+ translog_get_total_chunk_length(page, chunk_offset)) == 0)
+ {
+ DBUG_PRINT("error", ("cant get chunk length (offset %u)",
+ (uint) chunk_offset));
+ DBUG_RETURN(1);
+ }
+ DBUG_PRINT("info", ("chunk: offset: %u length %u",
+ (uint) chunk_offset, (uint) chunk_length));
+ if (((ulong) chunk_offset) + ((ulong) chunk_length) > TRANSLOG_PAGE_SIZE)
+ {
+ DBUG_PRINT("error", ("damaged chunk (offset %u) in trusted area",
+ (uint) chunk_offset));
+ DBUG_RETURN(1);
+ }
+ chunk_offset+= chunk_length;
+ }
+
+ valid_chunk_end= chunk_offset;
+ /* end of trusted area - sector parsing */
+ while (page[chunk_offset] != TRANSLOG_FILLER)
+ {
+ uint16 chunk_length;
+ if ((chunk_length=
+ translog_get_total_chunk_length(page, chunk_offset)) == 0)
+ break;
+
+ DBUG_PRINT("info", ("chunk: offset: %u length %u",
+ (uint) chunk_offset, (uint) chunk_length));
+ if (((ulong) chunk_offset) + ((ulong) chunk_length) >
+ (uint) (offset + DISK_DRIVE_SECTOR_SIZE))
+ break;
+
+ chunk_offset+= chunk_length;
+ valid_chunk_end= chunk_offset;
+ }
+ DBUG_PRINT("info", ("valid chunk end offset: %u", (uint) valid_chunk_end));
+
+ memset(page + valid_chunk_end, TRANSLOG_FILLER,
+ TRANSLOG_PAGE_SIZE - valid_chunk_end);
+
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Dummy write callback.
+*/
+
+static my_bool
+translog_dummy_callback(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar* data_ptr __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/**
+ @brief Checks and removes sector protection.
+
+ @param page reference on the page content.
+ @param file transaction log descriptor.
+
+ @retvat 0 OK
+ @retval 1 Error
+*/
+
+static my_bool
+translog_check_sector_protection(uchar *page, TRANSLOG_FILE *file)
+{
+ uint i, offset;
+ uchar *table= page + page_overhead[page[TRANSLOG_PAGE_FLAGS]] -
+ TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
+ uint8 current= table[0];
+ DBUG_ENTER("translog_check_sector_protection");
+
+ for (i= 1, offset= DISK_DRIVE_SECTOR_SIZE;
+ i < TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
+ i++, offset+= DISK_DRIVE_SECTOR_SIZE)
+ {
+ /*
+ TODO: add chunk counting for "suspecting" sectors (difference is
+ more than 1-2), if difference more then present chunks then it is
+ the problem.
+ */
+ uint8 test= page[offset];
+ DBUG_PRINT("info", ("sector: #%u offset: %u current: %lx "
+ "read: 0x%x stored: 0x%x%x",
+ i, offset, (ulong) current,
+ (uint) uint2korr(page + offset), (uint) table[i],
+ (uint) table[i + 1]));
+ /*
+ 3 is minimal possible record length. So we can have "distance"
+ between 2 sectors value more then DISK_DRIVE_SECTOR_SIZE / 3
+ only if it is old value, i.e. the sector was not written.
+ */
+ if (((test < current) &&
+ ((uint)(0xFFL - current + test) > DISK_DRIVE_SECTOR_SIZE / 3)) ||
+ ((test >= current) &&
+ ((uint)(test - current) > DISK_DRIVE_SECTOR_SIZE / 3)))
+ {
+ if (translog_recover_page_up_to_sector(page, offset))
+ DBUG_RETURN(1);
+ file->was_recovered= 1;
+ DBUG_RETURN(0);
+ }
+
+ /* Restore value on the page */
+ page[offset]= table[i];
+ current= test;
+ DBUG_PRINT("info", ("sector: #%u offset: %u current: %lx "
+ "read: 0x%x stored: 0x%x",
+ i, offset, (ulong) current,
+ (uint) page[offset], (uint) table[i]));
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Log page validator (read callback)
+
+ @param page The page data to check
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Read callback data pointer (pointer to TRANSLOG_FILE)
+
+ @todo: add turning loghandler to read-only mode after merging with
+ that patch.
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_page_validator(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar* data_ptr)
+{
+ uint this_page_page_overhead;
+ uint flags;
+ uchar *page_pos;
+ TRANSLOG_FILE *data= (TRANSLOG_FILE *) data_ptr;
+#ifndef DBUG_OFF
+ pgcache_page_no_t offset= page_no * TRANSLOG_PAGE_SIZE;
+#endif
+ DBUG_ENTER("translog_page_validator");
+
+ data->was_recovered= 0;
+
+ if (uint3korr(page) != page_no ||
+ uint3korr(page + 3) != data->number)
+ {
+ DBUG_PRINT("error", ("Page (%lu,0x%lx): "
+ "page address written in the page is incorrect: "
+ "File %lu instead of %lu or page %lu instead of %lu",
+ (ulong) data->number, (ulong) offset,
+ (ulong) uint3korr(page + 3), (ulong) data->number,
+ (ulong) uint3korr(page),
+ (ulong) page_no));
+ DBUG_RETURN(1);
+ }
+ flags= (uint)(page[TRANSLOG_PAGE_FLAGS]);
+ this_page_page_overhead= page_overhead[flags];
+ if (flags & ~(TRANSLOG_PAGE_CRC | TRANSLOG_SECTOR_PROTECTION |
+ TRANSLOG_RECORD_CRC))
+ {
+ DBUG_PRINT("error", ("Page (%lu,0x%lx): "
+ "Garbage in the page flags field detected : %x",
+ (ulong) data->number, (ulong) offset,
+ (uint) flags));
+ DBUG_RETURN(1);
+ }
+ page_pos= page + (3 + 3 + 1);
+ if (flags & TRANSLOG_PAGE_CRC)
+ {
+ uint32 crc= translog_crc(page + this_page_page_overhead,
+ TRANSLOG_PAGE_SIZE -
+ this_page_page_overhead);
+ if (crc != uint4korr(page_pos))
+ {
+ DBUG_PRINT("error", ("Page (%lu,0x%lx): "
+ "CRC mismatch: calculated: %lx on the page %lx",
+ (ulong) data->number, (ulong) offset,
+ (ulong) crc, (ulong) uint4korr(page_pos)));
+ DBUG_RETURN(1);
+ }
+ page_pos+= CRC_SIZE; /* Skip crc */
+ }
+ if (flags & TRANSLOG_SECTOR_PROTECTION &&
+ translog_check_sector_protection(page, data))
+ {
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Locks the loghandler.
+*/
+
+void translog_lock()
+{
+ uint8 current_buffer;
+ DBUG_ENTER("translog_lock");
+
+ /*
+ Locking the loghandler mean locking current buffer, but it can change
+ during locking, so we should check it
+ */
+ for (;;)
+ {
+ /*
+ log_descriptor.bc.buffer_no is only one byte so its reading is
+ an atomic operation
+ */
+ current_buffer= log_descriptor.bc.buffer_no;
+ translog_buffer_lock(log_descriptor.buffers + current_buffer);
+ if (log_descriptor.bc.buffer_no == current_buffer)
+ break;
+ translog_buffer_unlock(log_descriptor.buffers + current_buffer);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Unlock the loghandler
+
+ SYNOPSIS
+ translog_unlock()
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+void translog_unlock()
+{
+ translog_buffer_unlock(log_descriptor.bc.buffer);
+}
+
+
+/**
+ @brief Get log page by file number and offset of the beginning of the page
+
+ @param data validator data, which contains the page address
+ @param buffer buffer for page placing
+ (might not be used in some cache implementations)
+ @param direct_link if it is not NULL then caller can accept direct
+ link to the page cache
+
+ @retval NULL Error
+ @retval # pointer to the page cache which should be used to read this page
+*/
+
+static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer,
+ PAGECACHE_BLOCK_LINK **direct_link)
+{
+ TRANSLOG_ADDRESS addr= *(data->addr), in_buffers;
+ uint32 file_no= LSN_FILE_NO(addr);
+ TRANSLOG_FILE *file;
+ DBUG_ENTER("translog_get_page");
+ DBUG_PRINT("enter", ("File: %lu Offset: %lu(0x%lx)",
+ (ulong) file_no,
+ (ulong) LSN_OFFSET(addr),
+ (ulong) LSN_OFFSET(addr)));
+
+ /* it is really page address */
+ DBUG_ASSERT(LSN_OFFSET(addr) % TRANSLOG_PAGE_SIZE == 0);
+ if (direct_link)
+ *direct_link= NULL;
+
+restart:
+
+ in_buffers= translog_only_in_buffers();
+ DBUG_PRINT("info", ("in_buffers: (%lu,0x%lx)",
+ LSN_IN_PARTS(in_buffers)));
+ if (in_buffers != LSN_IMPOSSIBLE &&
+ cmp_translog_addr(addr, in_buffers) >= 0)
+ {
+ translog_lock();
+ DBUG_ASSERT(cmp_translog_addr(addr, log_descriptor.horizon) < 0);
+ /* recheck with locked loghandler */
+ in_buffers= translog_only_in_buffers();
+ if (cmp_translog_addr(addr, in_buffers) >= 0)
+ {
+ uint16 buffer_no= log_descriptor.bc.buffer_no;
+#ifndef DBUG_OFF
+ uint16 buffer_start= buffer_no;
+#endif
+ struct st_translog_buffer *buffer_unlock= log_descriptor.bc.buffer;
+ struct st_translog_buffer *curr_buffer= log_descriptor.bc.buffer;
+ for (;;)
+ {
+ /*
+ if the page is in the buffer and it is the last version of the
+ page (in case of division the page by buffer flush)
+ */
+ if (curr_buffer->file != NULL &&
+ cmp_translog_addr(addr, curr_buffer->offset) >= 0 &&
+ cmp_translog_addr(addr,
+ (curr_buffer->next_buffer_offset ?
+ curr_buffer->next_buffer_offset:
+ curr_buffer->offset + curr_buffer->size)) < 0)
+ {
+ TRANSLOG_ADDRESS offset= curr_buffer->offset;
+ TRANSLOG_FILE *fl= curr_buffer->file;
+ uchar *from, *table= NULL;
+ int is_last_unfinished_page;
+ uint last_protected_sector= 0;
+ TRANSLOG_FILE file_copy;
+ uint8 ver= curr_buffer->ver;
+ translog_wait_for_writers(curr_buffer);
+ if (offset != curr_buffer->offset || fl != curr_buffer->file ||
+ ver != curr_buffer->ver)
+ {
+ DBUG_ASSERT(buffer_unlock == curr_buffer);
+ translog_buffer_unlock(buffer_unlock);
+ goto restart;
+ }
+ DBUG_ASSERT(LSN_FILE_NO(addr) == LSN_FILE_NO(curr_buffer->offset));
+ from= curr_buffer->buffer + (addr - curr_buffer->offset);
+ memcpy(buffer, from, TRANSLOG_PAGE_SIZE);
+ /*
+ We can use copy then in translog_page_validator() because it
+ do not put it permanently somewhere.
+ We have to use copy because after releasing log lock we can't
+ guaranty that the file still be present (in real life it will be
+ present but theoretically possible that it will be released
+ already from last files cache);
+ */
+ file_copy= *(curr_buffer->file);
+ file_copy.handler.callback_data= (uchar*) &file_copy;
+ is_last_unfinished_page= ((log_descriptor.bc.buffer ==
+ curr_buffer) &&
+ (log_descriptor.bc.ptr >= from) &&
+ (log_descriptor.bc.ptr <
+ from + TRANSLOG_PAGE_SIZE));
+ if (is_last_unfinished_page &&
+ (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION))
+ {
+ last_protected_sector= ((log_descriptor.bc.previous_offset - 1) /
+ DISK_DRIVE_SECTOR_SIZE);
+ table= buffer + log_descriptor.page_overhead -
+ TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
+ }
+
+ DBUG_ASSERT(buffer_unlock == curr_buffer);
+ translog_buffer_unlock(buffer_unlock);
+ if (is_last_unfinished_page)
+ {
+ uint i;
+ /*
+ This is last unfinished page => we should not check CRC and
+ remove only that protection which already installed (no need
+ to check it)
+
+ We do not check the flag of sector protection, because if
+ (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION) is
+ not set then last_protected_sector will be 0 so following loop
+ will be never executed
+ */
+ DBUG_PRINT("info", ("This is last unfinished page, "
+ "last protected sector %u",
+ last_protected_sector));
+ for (i= 1; i <= last_protected_sector; i++)
+ {
+ uint offset= i * DISK_DRIVE_SECTOR_SIZE;
+ DBUG_PRINT("info", ("Sector %u: 0x%02x <- 0x%02x",
+ i, buffer[offset],
+ table[i]));
+ buffer[offset]= table[i];
+ }
+ }
+ else
+ {
+ /*
+ This IF should be true because we use in-memory data which
+ supposed to be correct.
+ */
+ if (translog_page_validator((uchar*) buffer,
+ LSN_OFFSET(addr) / TRANSLOG_PAGE_SIZE,
+ (uchar*) &file_copy))
+ {
+ DBUG_ASSERT(0);
+ buffer= NULL;
+ }
+ }
+ DBUG_RETURN(buffer);
+ }
+ buffer_no= (buffer_no + 1) % TRANSLOG_BUFFERS_NO;
+ curr_buffer= log_descriptor.buffers + buffer_no;
+ translog_buffer_lock(curr_buffer);
+ translog_buffer_unlock(buffer_unlock);
+ buffer_unlock= curr_buffer;
+ /* we can't make a full circle */
+ DBUG_ASSERT(buffer_start != buffer_no);
+ }
+ }
+ translog_unlock();
+ }
+ file= get_logfile_by_number(file_no);
+ DBUG_ASSERT(file != NULL);
+ buffer=
+ (uchar*) pagecache_read(log_descriptor.pagecache, &file->handler,
+ LSN_OFFSET(addr) / TRANSLOG_PAGE_SIZE,
+ 3, (direct_link ? NULL : buffer),
+ PAGECACHE_PLAIN_PAGE,
+ (direct_link ?
+ PAGECACHE_LOCK_READ :
+ PAGECACHE_LOCK_LEFT_UNLOCKED),
+ direct_link);
+ DBUG_PRINT("info", ("Direct link is assigned to : 0x%lx * 0x%lx",
+ (ulong) direct_link,
+ (ulong)(direct_link ? *direct_link : NULL)));
+ data->was_recovered= file->was_recovered;
+ DBUG_RETURN(buffer);
+}
+
+
+/**
+ @brief free direct log page link
+
+ @param direct_link the direct log page link to be freed
+
+*/
+
+static void translog_free_link(PAGECACHE_BLOCK_LINK *direct_link)
+{
+ DBUG_ENTER("translog_free_link");
+ DBUG_PRINT("info", ("Direct link: 0x%lx",
+ (ulong) direct_link));
+ if (direct_link)
+ pagecache_unlock_by_link(log_descriptor.pagecache, direct_link,
+ PAGECACHE_LOCK_READ_UNLOCK, PAGECACHE_UNPIN,
+ LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, 0, FALSE);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Finds last full page of the given log file.
+
+ @param addr address structure to fill with data, which contain
+ file number of the log file
+ @param last_page_ok Result of the check whether last page OK.
+ (for now only we check only that file length
+ divisible on page length).
+ @param no_errors suppress messages about non-critical errors
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_get_last_page_addr(TRANSLOG_ADDRESS *addr,
+ my_bool *last_page_ok,
+ my_bool no_errors)
+{
+ char path[FN_REFLEN];
+ uint32 rec_offset;
+ my_off_t file_size;
+ uint32 file_no= LSN_FILE_NO(*addr);
+ TRANSLOG_FILE *file;
+#ifndef DBUG_OFF
+ char buff[21];
+#endif
+ DBUG_ENTER("translog_get_last_page_addr");
+
+ if (likely((file= get_logfile_by_number(file_no)) != NULL))
+ {
+ /*
+ This function used only during initialization of loghandler or in
+ scanner (which mean we need read that part of the log), so the
+ requested log file have to be opened and can't be freed after
+ returning pointer on it (file_size).
+ */
+ file_size= my_seek(file->handler.file, 0, SEEK_END, MYF(0));
+ }
+ else
+ {
+ /*
+ This branch is used only during very early initialization
+ when files are not opened.
+ */
+ File fd;
+ if ((fd= my_open(translog_filename_by_fileno(file_no, path),
+ O_RDONLY, (no_errors ? MYF(0) : MYF(MY_WME)))) < 0)
+ {
+ my_errno= errno;
+ DBUG_PRINT("error", ("Error %d during opening file #%d",
+ errno, file_no));
+ DBUG_RETURN(1);
+ }
+ file_size= my_seek(fd, 0, SEEK_END, MYF(0));
+ my_close(fd, MYF(0));
+ }
+ DBUG_PRINT("info", ("File size: %s", llstr(file_size, buff)));
+ if (file_size == MY_FILEPOS_ERROR)
+ DBUG_RETURN(1);
+ DBUG_ASSERT(file_size < ULL(0xffffffff));
+ if (((uint32)file_size) > TRANSLOG_PAGE_SIZE)
+ {
+ rec_offset= (((((uint32)file_size) / TRANSLOG_PAGE_SIZE) - 1) *
+ TRANSLOG_PAGE_SIZE);
+ *last_page_ok= (((uint32)file_size) == rec_offset + TRANSLOG_PAGE_SIZE);
+ }
+ else
+ {
+ *last_page_ok= 0;
+ rec_offset= 0;
+ }
+ *addr= MAKE_LSN(file_no, rec_offset);
+ DBUG_PRINT("info", ("Last page: 0x%lx ok: %d", (ulong) rec_offset,
+ *last_page_ok));
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Get number bytes for record length storing
+
+ @param length Record length which will be encoded
+
+ @return 1,3,4,5 - number of bytes to store given length
+*/
+
+static uint translog_variable_record_length_bytes(translog_size_t length)
+{
+ if (length < 250)
+ return 1;
+ if (length < 0xFFFF)
+ return 3;
+ if (length < (ulong) 0xFFFFFF)
+ return 4;
+ return 5;
+}
+
+
+/**
+ @brief Gets header of this chunk.
+
+ @param chunk The pointer to the chunk beginning
+
+ @retval # total length of the chunk
+ @retval 0 Error
+*/
+
+static uint16 translog_get_chunk_header_length(uchar *chunk)
+{
+ DBUG_ENTER("translog_get_chunk_header_length");
+ switch (*chunk & TRANSLOG_CHUNK_TYPE) {
+ case TRANSLOG_CHUNK_LSN:
+ {
+ /* 0 chunk referred as LSN (head or tail) */
+ translog_size_t rec_len;
+ uchar *start= chunk;
+ uchar *ptr= start + 1 + 2;
+ uint16 chunk_len, header_len;
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_LSN"));
+ rec_len= translog_variable_record_1group_decode_len(&ptr);
+ chunk_len= uint2korr(ptr);
+ header_len= (uint16) (ptr - start) +2;
+ DBUG_PRINT("info", ("rec len: %lu chunk len: %u header len: %u",
+ (ulong) rec_len, (uint) chunk_len, (uint) header_len));
+ if (chunk_len)
+ {
+ /* TODO: fine header end */
+ /*
+ The last chunk of multi-group record can be base for it header
+ calculation (we skip to the first group to read the header) so if we
+ stuck here something is wrong.
+ */
+ DBUG_ASSERT(0);
+ DBUG_RETURN(0); /* Keep compiler happy */
+ }
+ DBUG_RETURN(header_len);
+ }
+ case TRANSLOG_CHUNK_FIXED:
+ {
+ /* 1 (pseudo)fixed record (also LSN) */
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_FIXED = 3"));
+ DBUG_RETURN(3);
+ }
+ case TRANSLOG_CHUNK_NOHDR:
+ /* 2 no header chunk (till page end) */
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_NOHDR = 1"));
+ DBUG_RETURN(1);
+ break;
+ case TRANSLOG_CHUNK_LNGTH:
+ /* 3 chunk with chunk length */
+ DBUG_PRINT("info", ("TRANSLOG_CHUNK_LNGTH = 3"));
+ DBUG_RETURN(3);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ DBUG_RETURN(0); /* Keep compiler happy */
+ }
+}
+
+
+/**
+ @brief Truncate the log to the given address. Used during the startup if the
+ end of log if corrupted.
+
+ @param addr new horizon
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_truncate_log(TRANSLOG_ADDRESS addr)
+{
+ uchar *page;
+ TRANSLOG_ADDRESS current_page;
+ uint32 next_page_offset, page_rest;
+ uint32 i;
+ File fd;
+ TRANSLOG_VALIDATOR_DATA data;
+ char path[FN_REFLEN];
+ uchar page_buff[TRANSLOG_PAGE_SIZE];
+ DBUG_ENTER("translog_truncate_log");
+ /* TODO: write warning to the client */
+ DBUG_PRINT("warning", ("removing all records from (%lu,0x%lx) "
+ "till (%lu,0x%lx)",
+ LSN_IN_PARTS(addr),
+ LSN_IN_PARTS(log_descriptor.horizon)));
+ DBUG_ASSERT(cmp_translog_addr(addr, log_descriptor.horizon) < 0);
+ /* remove files between the address and horizon */
+ for (i= LSN_FILE_NO(addr) + 1; i <= LSN_FILE_NO(log_descriptor.horizon); i++)
+ if (my_delete(translog_filename_by_fileno(i, path), MYF(MY_WME)))
+ {
+ translog_unlock();
+ DBUG_RETURN(1);
+ }
+
+ /* truncate the last file up to the last page */
+ next_page_offset= LSN_OFFSET(addr);
+ next_page_offset= (next_page_offset -
+ ((next_page_offset - 1) % TRANSLOG_PAGE_SIZE + 1) +
+ TRANSLOG_PAGE_SIZE);
+ page_rest= next_page_offset - LSN_OFFSET(addr);
+ memset(page_buff, TRANSLOG_FILLER, page_rest);
+ if ((fd= open_logfile_by_number_no_cache(LSN_FILE_NO(addr))) < 0 ||
+ ((my_chsize(fd, next_page_offset, TRANSLOG_FILLER, MYF(MY_WME)) ||
+ (page_rest && my_pwrite(fd, page_buff, page_rest, LSN_OFFSET(addr),
+ log_write_flags)) ||
+ my_sync(fd, MYF(MY_WME))) |
+ my_close(fd, MYF(MY_WME))) ||
+ (sync_log_dir >= TRANSLOG_SYNC_DIR_ALWAYS &&
+ sync_dir(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD))))
+ DBUG_RETURN(1);
+
+ /* fix the horizon */
+ log_descriptor.horizon= addr;
+ /* fix the buffer data */
+ current_page= MAKE_LSN(LSN_FILE_NO(addr), (next_page_offset -
+ TRANSLOG_PAGE_SIZE));
+ data.addr= &current_page;
+ if ((page= translog_get_page(&data, log_descriptor.buffers->buffer, NULL)) ==
+ NULL)
+ DBUG_RETURN(1);
+ if (page != log_descriptor.buffers->buffer)
+ memcpy(log_descriptor.buffers->buffer, page, TRANSLOG_PAGE_SIZE);
+ log_descriptor.bc.buffer->offset= current_page;
+ log_descriptor.bc.buffer->size= LSN_OFFSET(addr) - LSN_OFFSET(current_page);
+ log_descriptor.bc.ptr=
+ log_descriptor.buffers->buffer + log_descriptor.bc.buffer->size;
+ log_descriptor.bc.current_page_fill= log_descriptor.bc.buffer->size;
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Applies function 'callback' to all files (in a directory) which
+ name looks like a log's name (maria_log.[0-9]{7}).
+ If 'callback' returns TRUE this interrupts the walk and returns
+ TRUE. Otherwise FALSE is returned after processing all log files.
+ It cannot just use log_descriptor.directory because that may not yet have
+ been initialized.
+
+ @param directory directory to scan
+ @param callback function to apply; is passed directory and base
+ name of found file
+*/
+
+my_bool translog_walk_filenames(const char *directory,
+ my_bool (*callback)(const char *,
+ const char *))
+{
+ MY_DIR *dirp;
+ uint i;
+ my_bool rc= FALSE;
+
+ /* Finds and removes transaction log files */
+ if (!(dirp = my_dir(directory, MYF(MY_DONT_SORT))))
+ return FALSE;
+
+ for (i= 0; i < dirp->number_off_files; i++)
+ {
+ char *file= dirp->dir_entry[i].name;
+ if (strncmp(file, "maria_log.", 10) == 0 &&
+ file[10] >= '0' && file[10] <= '9' &&
+ file[11] >= '0' && file[11] <= '9' &&
+ file[12] >= '0' && file[12] <= '9' &&
+ file[13] >= '0' && file[13] <= '9' &&
+ file[14] >= '0' && file[14] <= '9' &&
+ file[15] >= '0' && file[15] <= '9' &&
+ file[16] >= '0' && file[16] <= '9' &&
+ file[17] >= '0' && file[17] <= '9' &&
+ file[18] == '\0' && (*callback)(directory, file))
+ {
+ rc= TRUE;
+ break;
+ }
+ }
+ my_dirend(dirp);
+ return rc;
+}
+
+
+/**
+ @brief Fills table of dependence length of page header from page flags
+*/
+
+static void translog_fill_overhead_table()
+{
+ uint i;
+ for (i= 0; i < TRANSLOG_FLAGS_NUM; i++)
+ {
+ page_overhead[i]= 7;
+ if (i & TRANSLOG_PAGE_CRC)
+ page_overhead[i]+= CRC_SIZE;
+ if (i & TRANSLOG_SECTOR_PROTECTION)
+ page_overhead[i]+= TRANSLOG_PAGE_SIZE /
+ DISK_DRIVE_SECTOR_SIZE;
+ }
+}
+
+
+/**
+ Callback to find first log in directory.
+*/
+
+static my_bool translog_callback_search_first(const char *directory
+ __attribute__((unused)),
+ const char *filename
+ __attribute__((unused)))
+{
+ return TRUE;
+}
+
+
+/**
+ @brief Checks that chunk is LSN one
+
+ @param type type of the chunk
+
+ @retval 1 the chunk is LNS
+ @retval 0 the chunk is not LSN
+*/
+
+static my_bool translog_is_LSN_chunk(uchar type)
+{
+ DBUG_ENTER("translog_is_LSN_chunk");
+ DBUG_PRINT("info", ("byte: %x chunk type: %u record type: %u",
+ type, type >> 6, type & TRANSLOG_REC_TYPE));
+ DBUG_RETURN(((type & TRANSLOG_CHUNK_TYPE) == TRANSLOG_CHUNK_FIXED) ||
+ (((type & TRANSLOG_CHUNK_TYPE) == TRANSLOG_CHUNK_LSN) &&
+ ((type & TRANSLOG_REC_TYPE)) != TRANSLOG_CHUNK_0_CONT));
+}
+
+
+/**
+ @brief Initialize transaction log
+
+ @param directory Directory where log files are put
+ @param log_file_max_size max size of one log size (for new logs creation)
+ @param server_version version of MySQL server (MYSQL_VERSION_ID)
+ @param server_id server ID (replication & Co)
+ @param pagecache Page cache for the log reads
+ @param flags flags (TRANSLOG_PAGE_CRC, TRANSLOG_SECTOR_PROTECTION
+ TRANSLOG_RECORD_CRC)
+ @param read_only Put transaction log in read-only mode
+ @param init_table_func function to initialize record descriptors table
+ @param no_errors suppress messages about non-critical errors
+
+ @todo
+ Free used resources in case of error.
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool translog_init_with_table(const char *directory,
+ uint32 log_file_max_size,
+ uint32 server_version,
+ uint32 server_id, PAGECACHE *pagecache,
+ uint flags, my_bool readonly,
+ void (*init_table_func)(),
+ my_bool no_errors)
+{
+ int i;
+ int old_log_was_recovered= 0, logs_found= 0;
+ uint old_flags= flags;
+ uint32 start_file_num= 1;
+ TRANSLOG_ADDRESS sure_page, last_page, last_valid_page, checkpoint_lsn;
+ my_bool version_changed= 0;
+ DBUG_ENTER("translog_init_with_table");
+
+ id_to_share= NULL;
+ log_descriptor.directory_fd= -1;
+ log_descriptor.is_everything_flushed= 1;
+ log_descriptor.next_pass_max_lsn= LSN_IMPOSSIBLE;
+
+ (*init_table_func)();
+ compile_time_assert(sizeof(log_descriptor.dirty_buffer_mask) * 8 >=
+ TRANSLOG_BUFFERS_NO);
+ log_descriptor.dirty_buffer_mask= 0;
+ if (readonly)
+ log_descriptor.open_flags= O_BINARY | O_RDONLY;
+ else
+ log_descriptor.open_flags= O_BINARY | O_RDWR;
+ if (pthread_mutex_init(&log_descriptor.sent_to_disk_lock,
+ MY_MUTEX_INIT_FAST) ||
+ pthread_mutex_init(&log_descriptor.file_header_lock,
+ MY_MUTEX_INIT_FAST) ||
+ pthread_mutex_init(&log_descriptor.unfinished_files_lock,
+ MY_MUTEX_INIT_FAST) ||
+ pthread_mutex_init(&log_descriptor.purger_lock,
+ MY_MUTEX_INIT_FAST) ||
+ pthread_mutex_init(&log_descriptor.log_flush_lock,
+ MY_MUTEX_INIT_FAST) ||
+ pthread_mutex_init(&log_descriptor.dirty_buffer_mask_lock,
+ MY_MUTEX_INIT_FAST) ||
+ pthread_cond_init(&log_descriptor.log_flush_cond, 0) ||
+ my_rwlock_init(&log_descriptor.open_files_lock,
+ NULL) ||
+ my_init_dynamic_array(&log_descriptor.open_files,
+ sizeof(TRANSLOG_FILE*), 10, 10) ||
+ my_init_dynamic_array(&log_descriptor.unfinished_files,
+ sizeof(struct st_file_counter),
+ 10, 10))
+ goto err;
+ log_descriptor.min_need_file= 0;
+ log_descriptor.min_file_number= 0;
+ log_descriptor.last_lsn_checked= LSN_IMPOSSIBLE;
+
+ /* Directory to store files */
+ unpack_dirname(log_descriptor.directory, directory);
+#ifndef __WIN__
+ if ((log_descriptor.directory_fd= my_open(log_descriptor.directory,
+ O_RDONLY, MYF(MY_WME))) < 0)
+ {
+ my_errno= errno;
+ DBUG_PRINT("error", ("Error %d during opening directory '%s'",
+ errno, log_descriptor.directory));
+ goto err;
+ }
+#endif
+ log_descriptor.in_buffers_only= LSN_IMPOSSIBLE;
+ DBUG_ASSERT(log_file_max_size % TRANSLOG_PAGE_SIZE == 0 &&
+ log_file_max_size >= TRANSLOG_MIN_FILE_SIZE);
+ /* max size of one log size (for new logs creation) */
+ log_file_size= log_descriptor.log_file_max_size=
+ log_file_max_size;
+ /* server version */
+ log_descriptor.server_version= server_version;
+ /* server ID */
+ log_descriptor.server_id= server_id;
+ /* Page cache for the log reads */
+ log_descriptor.pagecache= pagecache;
+ /* Flags */
+ DBUG_ASSERT((flags &
+ ~(TRANSLOG_PAGE_CRC | TRANSLOG_SECTOR_PROTECTION |
+ TRANSLOG_RECORD_CRC)) == 0);
+ log_descriptor.flags= flags;
+ translog_fill_overhead_table();
+ log_descriptor.page_overhead= page_overhead[flags];
+ log_descriptor.page_capacity_chunk_2=
+ TRANSLOG_PAGE_SIZE - log_descriptor.page_overhead - 1;
+ compile_time_assert(TRANSLOG_WRITE_BUFFER % TRANSLOG_PAGE_SIZE == 0);
+ log_descriptor.buffer_capacity_chunk_2=
+ (TRANSLOG_WRITE_BUFFER / TRANSLOG_PAGE_SIZE) *
+ log_descriptor.page_capacity_chunk_2;
+ log_descriptor.half_buffer_capacity_chunk_2=
+ log_descriptor.buffer_capacity_chunk_2 / 2;
+ DBUG_PRINT("info",
+ ("Overhead: %u pc2: %u bc2: %u, bc2/2: %u",
+ log_descriptor.page_overhead,
+ log_descriptor.page_capacity_chunk_2,
+ log_descriptor.buffer_capacity_chunk_2,
+ log_descriptor.half_buffer_capacity_chunk_2));
+
+ /* Just to init it somehow (hack for bootstrap)*/
+ {
+ TRANSLOG_FILE *file= 0;
+ log_descriptor.min_file = log_descriptor.max_file= 1;
+ insert_dynamic(&log_descriptor.open_files, (uchar *)&file);
+ translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
+ pop_dynamic(&log_descriptor.open_files);
+ }
+
+ /* Buffers for log writing */
+ for (i= 0; i < TRANSLOG_BUFFERS_NO; i++)
+ {
+ if (translog_buffer_init(log_descriptor.buffers + i, i))
+ goto err;
+ DBUG_PRINT("info", ("translog_buffer buffer #%u: 0x%lx",
+ i, (ulong) log_descriptor.buffers + i));
+ }
+
+ /*
+ last_logno and last_checkpoint_lsn were set in
+ ma_control_file_create_or_open()
+ */
+ logs_found= (last_logno != FILENO_IMPOSSIBLE);
+
+ translog_status= (readonly ? TRANSLOG_READONLY : TRANSLOG_OK);
+ checkpoint_lsn= last_checkpoint_lsn;
+
+ if (logs_found)
+ {
+ my_bool pageok;
+ DBUG_PRINT("info", ("log found..."));
+ /*
+ TODO: scan directory for maria_log.XXXXXXXX files and find
+ highest XXXXXXXX & set logs_found
+ TODO: check that last checkpoint within present log addresses space
+
+ find the log end
+ */
+ if (LSN_FILE_NO(last_checkpoint_lsn) == FILENO_IMPOSSIBLE)
+ {
+ DBUG_ASSERT(LSN_OFFSET(last_checkpoint_lsn) == 0);
+ /* only last log needs to be checked */
+ sure_page= MAKE_LSN(last_logno, TRANSLOG_PAGE_SIZE);
+ }
+ else
+ {
+ sure_page= last_checkpoint_lsn;
+ DBUG_ASSERT(LSN_OFFSET(sure_page) % TRANSLOG_PAGE_SIZE != 0);
+ sure_page-= LSN_OFFSET(sure_page) % TRANSLOG_PAGE_SIZE;
+ }
+ /* Set horizon to the beginning of the last file first */
+ log_descriptor.horizon= last_page= MAKE_LSN(last_logno, 0);
+ if (translog_get_last_page_addr(&last_page, &pageok, no_errors))
+ {
+ if (!translog_walk_filenames(log_descriptor.directory,
+ &translog_callback_search_first))
+ {
+ /*
+ Files was deleted, just start from the next log number, so that
+ existing tables are in the past.
+ */
+ start_file_num= last_logno + 1;
+ checkpoint_lsn= LSN_IMPOSSIBLE; /* no log so no checkpoint */
+ logs_found= 0;
+ }
+ else
+ goto err;
+ }
+ else if (LSN_OFFSET(last_page) == 0)
+ {
+ if (LSN_FILE_NO(last_page) == 1)
+ {
+ logs_found= 0; /* file #1 has no pages */
+ DBUG_PRINT("info", ("log found. But is is empty => no log assumed"));
+ }
+ else
+ {
+ last_page-= LSN_ONE_FILE;
+ if (translog_get_last_page_addr(&last_page, &pageok, 0))
+ goto err;
+ }
+ }
+ if (logs_found)
+ {
+ uint32 i;
+ log_descriptor.min_file= translog_first_file(log_descriptor.horizon, 1);
+ log_descriptor.max_file= last_logno;
+ /* Open all files */
+ if (allocate_dynamic(&log_descriptor.open_files,
+ log_descriptor.max_file -
+ log_descriptor.min_file + 1))
+ goto err;
+ for (i = log_descriptor.max_file; i >= log_descriptor.min_file; i--)
+ {
+ /*
+ We can't allocate all file together because they will be freed
+ one by one
+ */
+ TRANSLOG_FILE *file= (TRANSLOG_FILE *)my_malloc(sizeof(TRANSLOG_FILE),
+ MYF(0));
+
+ compile_time_assert(MY_FILEPOS_ERROR > ULL(0xffffffff));
+ if (file == NULL ||
+ (file->handler.file=
+ open_logfile_by_number_no_cache(i)) < 0 ||
+ my_seek(file->handler.file, 0, SEEK_END, MYF(0)) >=
+ ULL(0xffffffff))
+ {
+ int j;
+ for (j= i - log_descriptor.min_file - 1; j > 0; j--)
+ {
+ TRANSLOG_FILE *el=
+ *dynamic_element(&log_descriptor.open_files, j,
+ TRANSLOG_FILE **);
+ my_close(el->handler.file, MYF(MY_WME));
+ my_free(el, MYF(0));
+ }
+ if (file)
+ {
+ free(file);
+ goto err;
+ }
+ else
+ goto err;
+ }
+ translog_file_init(file, i, 1);
+ /* we allocated space so it can't fail */
+ insert_dynamic(&log_descriptor.open_files, (uchar *)&file);
+ }
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+ }
+ }
+ else if (readonly)
+ {
+ /* There is no logs and there is read-only mode => nothing to read */
+ DBUG_PRINT("error", ("No logs and read-only mode"));
+ goto err;
+ }
+
+ if (logs_found)
+ {
+ TRANSLOG_ADDRESS current_page= sure_page;
+ my_bool pageok;
+
+ DBUG_PRINT("info", ("The log is really present"));
+ DBUG_ASSERT(sure_page <= last_page);
+
+ /* TODO: check page size */
+
+ last_valid_page= LSN_IMPOSSIBLE;
+ /*
+ Scans and validate pages. We need it to show "outside" only for sure
+ valid part of the log. If the log was damaged then fixed we have to
+ cut off damaged part before some other process start write something
+ in the log.
+ */
+ do
+ {
+ TRANSLOG_ADDRESS current_file_last_page;
+ current_file_last_page= current_page;
+ if (translog_get_last_page_addr(&current_file_last_page, &pageok, 0))
+ goto err;
+ if (!pageok)
+ {
+ DBUG_PRINT("error", ("File %lu have no complete last page",
+ (ulong) LSN_FILE_NO(current_file_last_page)));
+ old_log_was_recovered= 1;
+ /* This file is not written till the end so it should be last */
+ last_page= current_file_last_page;
+ /* TODO: issue warning */
+ }
+ do
+ {
+ TRANSLOG_VALIDATOR_DATA data;
+ TRANSLOG_PAGE_SIZE_BUFF psize_buff;
+ uchar *page;
+ data.addr= &current_page;
+ if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL)
+ goto err;
+ if (data.was_recovered)
+ {
+ DBUG_PRINT("error", ("file no: %lu (%d) "
+ "rec_offset: 0x%lx (%lu) (%d)",
+ (ulong) LSN_FILE_NO(current_page),
+ (uint3korr(page + 3) !=
+ LSN_FILE_NO(current_page)),
+ (ulong) LSN_OFFSET(current_page),
+ (ulong) (LSN_OFFSET(current_page) /
+ TRANSLOG_PAGE_SIZE),
+ (uint3korr(page) !=
+ LSN_OFFSET(current_page) /
+ TRANSLOG_PAGE_SIZE)));
+ old_log_was_recovered= 1;
+ break;
+ }
+ old_flags= page[TRANSLOG_PAGE_FLAGS];
+ last_valid_page= current_page;
+ current_page+= TRANSLOG_PAGE_SIZE; /* increase offset */
+ } while (current_page <= current_file_last_page);
+ current_page+= LSN_ONE_FILE;
+ current_page= LSN_REPLACE_OFFSET(current_page, TRANSLOG_PAGE_SIZE);
+ } while (LSN_FILE_NO(current_page) <= LSN_FILE_NO(last_page) &&
+ !old_log_was_recovered);
+ if (last_valid_page == LSN_IMPOSSIBLE)
+ {
+ /* Panic!!! Even page which should be valid is invalid */
+ /* TODO: issue error */
+ goto err;
+ }
+ DBUG_PRINT("info", ("Last valid page is in file: %lu "
+ "offset: %lu (0x%lx) "
+ "Logs found: %d was recovered: %d "
+ "flags match: %d",
+ (ulong) LSN_FILE_NO(last_valid_page),
+ (ulong) LSN_OFFSET(last_valid_page),
+ (ulong) LSN_OFFSET(last_valid_page),
+ logs_found, old_log_was_recovered,
+ (old_flags == flags)));
+
+ /* TODO: check server ID */
+ if (logs_found && !old_log_was_recovered && old_flags == flags)
+ {
+ TRANSLOG_VALIDATOR_DATA data;
+ TRANSLOG_PAGE_SIZE_BUFF psize_buff;
+ uchar *page;
+ uint16 chunk_offset;
+ data.addr= &last_valid_page;
+ /* continue old log */
+ DBUG_ASSERT(LSN_FILE_NO(last_valid_page)==
+ LSN_FILE_NO(log_descriptor.horizon));
+ if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL ||
+ (chunk_offset= translog_get_first_chunk_offset(page)) == 0)
+ goto err;
+
+ /* Puts filled part of old page in the buffer */
+ log_descriptor.horizon= last_valid_page;
+ translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
+ /*
+ Free space if filled with TRANSLOG_FILLER and first uchar of
+ real chunk can't be TRANSLOG_FILLER
+ */
+ while (chunk_offset < TRANSLOG_PAGE_SIZE &&
+ page[chunk_offset] != TRANSLOG_FILLER)
+ {
+ uint16 chunk_length;
+ if ((chunk_length=
+ translog_get_total_chunk_length(page, chunk_offset)) == 0)
+ goto err;
+ DBUG_PRINT("info", ("chunk: offset: %u length: %u",
+ (uint) chunk_offset, (uint) chunk_length));
+ chunk_offset+= chunk_length;
+
+ /* chunk can't cross the page border */
+ DBUG_ASSERT(chunk_offset <= TRANSLOG_PAGE_SIZE);
+ }
+ memcpy(log_descriptor.buffers->buffer, page, chunk_offset);
+ log_descriptor.bc.buffer->size+= chunk_offset;
+ log_descriptor.bc.ptr+= chunk_offset;
+ log_descriptor.bc.current_page_fill= chunk_offset;
+ log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
+ (chunk_offset +
+ LSN_OFFSET(last_valid_page)));
+ DBUG_PRINT("info", ("Move Page #%u: 0x%lx chaser: %d Size: %lu (%lu)",
+ (uint) log_descriptor.bc.buffer_no,
+ (ulong) log_descriptor.bc.buffer,
+ log_descriptor.bc.chaser,
+ (ulong) log_descriptor.bc.buffer->size,
+ (ulong) (log_descriptor.bc.ptr - log_descriptor.bc.
+ buffer->buffer)));
+ translog_check_cursor(&log_descriptor.bc);
+ }
+ if (!old_log_was_recovered && old_flags == flags)
+ {
+ LOGHANDLER_FILE_INFO info;
+ /*
+ Accessing &log_descriptor.open_files without mutex is safe
+ because it is initialization
+ */
+ if (translog_read_file_header(&info,
+ (*dynamic_element(&log_descriptor.
+ open_files,
+ 0, TRANSLOG_FILE **))->
+ handler.file))
+ goto err;
+ version_changed= (info.maria_version != TRANSLOG_VERSION_ID);
+ }
+ }
+ DBUG_PRINT("info", ("Logs found: %d was recovered: %d",
+ logs_found, old_log_was_recovered));
+ if (!logs_found)
+ {
+ TRANSLOG_FILE *file= (TRANSLOG_FILE*)my_malloc(sizeof(TRANSLOG_FILE),
+ MYF(0));
+ DBUG_PRINT("info", ("The log is not found => we will create new log"));
+ if (file == NULL)
+ goto err;
+ /* Start new log system from scratch */
+ log_descriptor.horizon= MAKE_LSN(start_file_num,
+ TRANSLOG_PAGE_SIZE); /* header page */
+ if ((file->handler.file=
+ create_logfile_by_number_no_cache(start_file_num)) == -1)
+ goto err;
+ translog_file_init(file, start_file_num, 0);
+ if (insert_dynamic(&log_descriptor.open_files, (uchar*)&file))
+ goto err;
+ log_descriptor.min_file= log_descriptor.max_file= start_file_num;
+ if (translog_write_file_header())
+ goto err;
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+
+ if (ma_control_file_write_and_force(checkpoint_lsn, start_file_num,
+ max_trid_in_control_file,
+ recovery_failures))
+ goto err;
+ /* assign buffer 0 */
+ translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
+ translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
+ }
+ else if ((old_log_was_recovered || old_flags != flags || version_changed) &&
+ !readonly)
+ {
+ /* leave the damaged file untouched */
+ log_descriptor.horizon+= LSN_ONE_FILE;
+ /* header page */
+ log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
+ TRANSLOG_PAGE_SIZE);
+ if (translog_create_new_file())
+ goto err;
+ /*
+ Buffer system left untouched after recovery => we should init it
+ (starting from buffer 0)
+ */
+ translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
+ translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
+ }
+
+ /* all LSNs that are on disk are flushed */
+ log_descriptor.log_start= log_descriptor.sent_to_disk=
+ log_descriptor.flushed= log_descriptor.horizon;
+ log_descriptor.in_buffers_only= log_descriptor.bc.buffer->offset;
+ log_descriptor.max_lsn= LSN_IMPOSSIBLE; /* set to 0 */
+ log_descriptor.previous_flush_horizon= log_descriptor.horizon;
+ /*
+ Now 'flushed' is set to 'horizon' value, but 'horizon' is (potentially)
+ address of the next LSN and we want indicate that all LSNs that are
+ already on the disk are flushed so we need decrease horizon on 1 (we are
+ sure that there is no LSN on the disk which is greater then 'flushed'
+ and there will not be LSN created that is equal or less then the value
+ of the 'flushed').
+ */
+ log_descriptor.flushed--; /* offset decreased */
+ log_descriptor.sent_to_disk--; /* offset decreased */
+ /*
+ Log records will refer to a MARIA_SHARE by a unique 2-byte id; set up
+ structures for generating 2-byte ids:
+ */
+ my_atomic_rwlock_init(&LOCK_id_to_share);
+ id_to_share= (MARIA_SHARE **) my_malloc(SHARE_ID_MAX * sizeof(MARIA_SHARE*),
+ MYF(MY_WME | MY_ZEROFILL));
+ if (unlikely(!id_to_share))
+ goto err;
+ id_to_share--; /* min id is 1 */
+
+ /* Check the last LSN record integrity */
+ if (logs_found)
+ {
+ TRANSLOG_SCANNER_DATA scanner;
+ TRANSLOG_ADDRESS page_addr;
+ LSN last_lsn= LSN_IMPOSSIBLE;
+ /*
+ take very last page address and try to find LSN record on it
+ if it fail take address of previous page and so on
+ */
+ page_addr= (log_descriptor.horizon -
+ ((log_descriptor.horizon - 1) % TRANSLOG_PAGE_SIZE + 1));
+ if (translog_scanner_init(page_addr, 1, &scanner, 1))
+ goto err;
+ scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
+ for (;;)
+ {
+ uint chunk_1byte;
+ chunk_1byte= scanner.page[scanner.page_offset];
+ while (!translog_is_LSN_chunk(chunk_1byte) &&
+ scanner.page != END_OF_LOG &&
+ scanner.page[scanner.page_offset] != TRANSLOG_FILLER &&
+ scanner.page_addr == page_addr)
+ {
+ if (translog_get_next_chunk(&scanner))
+ {
+ translog_destroy_scanner(&scanner);
+ goto err;
+ }
+ if (scanner.page != END_OF_LOG)
+ chunk_1byte= scanner.page[scanner.page_offset];
+ }
+ if (translog_is_LSN_chunk(chunk_1byte))
+ {
+ last_lsn= scanner.page_addr + scanner.page_offset;
+ if (translog_get_next_chunk(&scanner))
+ {
+ translog_destroy_scanner(&scanner);
+ goto err;
+ }
+ if (scanner.page == END_OF_LOG)
+ break; /* it was the last record */
+ chunk_1byte= scanner.page[scanner.page_offset];
+ continue; /* try to find other record on this page */
+ }
+
+ if (last_lsn != LSN_IMPOSSIBLE)
+ break; /* there is no more records on the page */
+
+ /* We have to make step back */
+ if (unlikely(LSN_OFFSET(page_addr) == TRANSLOG_PAGE_SIZE))
+ {
+ uint32 file_no= LSN_FILE_NO(page_addr);
+ my_bool last_page_ok;
+ /* it is beginning of the current file */
+ if (unlikely(file_no == 1))
+ {
+ /*
+ It is beginning of the log => there is no LSNs in the log =>
+ There is no harm in leaving it "as-is".
+ */
+ DBUG_RETURN(0);
+ }
+ file_no--;
+ page_addr= MAKE_LSN(file_no, TRANSLOG_PAGE_SIZE);
+ translog_get_last_page_addr(&page_addr, &last_page_ok, 0);
+ /* page should be OK as it is not the last file */
+ DBUG_ASSERT(last_page_ok);
+ }
+ else
+ {
+ page_addr-= TRANSLOG_PAGE_SIZE;
+ }
+ translog_destroy_scanner(&scanner);
+ if (translog_scanner_init(page_addr, 1, &scanner, 1))
+ goto err;
+ scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
+ }
+ translog_destroy_scanner(&scanner);
+
+ /* Now scanner points to the last LSN chunk, lets check it */
+ {
+ TRANSLOG_HEADER_BUFFER rec;
+ translog_size_t rec_len;
+ int len;
+ uchar buffer[1];
+ DBUG_PRINT("info", ("going to check the last found record (%lu,0x%lx)",
+ LSN_IN_PARTS(last_lsn)));
+
+ len=
+ translog_read_record_header(last_lsn, &rec);
+ if (unlikely (len == RECHEADER_READ_ERROR ||
+ len == RECHEADER_READ_EOF))
+ {
+ DBUG_PRINT("error", ("unexpected end of log or record during "
+ "reading record header: (%lu,0x%lx) len: %d",
+ LSN_IN_PARTS(last_lsn), len));
+ if (readonly)
+ log_descriptor.log_start= log_descriptor.horizon= last_lsn;
+ else if (translog_truncate_log(last_lsn))
+ {
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ }
+ else
+ {
+ DBUG_ASSERT(last_lsn == rec.lsn);
+ if (likely(rec.record_length != 0))
+ {
+ /*
+ Reading the last byte of record will trigger scanning all
+ record chunks for now
+ */
+ rec_len= translog_read_record(rec.lsn, rec.record_length - 1, 1,
+ buffer, NULL);
+ if (rec_len != 1)
+ {
+ DBUG_PRINT("error", ("unexpected end of log or record during "
+ "reading record body: (%lu,0x%lx) len: %d",
+ LSN_IN_PARTS(rec.lsn),
+ len));
+ if (readonly)
+ log_descriptor.log_start= log_descriptor.horizon= last_lsn;
+
+ else if (translog_truncate_log(last_lsn))
+ {
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ }
+ }
+ }
+ translog_free_record_header(&rec);
+ }
+ }
+ DBUG_RETURN(0);
+err:
+ ma_message_no_user(0, "log initialization failed");
+ DBUG_RETURN(1);
+}
+
+
+/*
+ @brief Free transaction log file buffer.
+
+ @param buffer_no The buffer to free
+*/
+
+static void translog_buffer_destroy(struct st_translog_buffer *buffer)
+{
+ DBUG_ENTER("translog_buffer_destroy");
+ DBUG_PRINT("enter",
+ ("Buffer #%u: 0x%lx file: %d offset: (%lu,0x%lx) size: %lu",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ (buffer->file ? buffer->file->handler.file : -1),
+ LSN_IN_PARTS(buffer->offset),
+ (ulong) buffer->size));
+ if (buffer->file != NULL)
+ {
+ /*
+ We ignore errors here, because we can't do something about it
+ (it is shutting down)
+
+ We also have to take the locks even if there can't be any other
+ threads running, because translog_buffer_flush()
+ requires that we have the buffer locked.
+ */
+ translog_buffer_lock(buffer);
+ translog_buffer_flush(buffer);
+ translog_buffer_unlock(buffer);
+ }
+ DBUG_PRINT("info", ("Destroy mutex: 0x%lx", (ulong) &buffer->mutex));
+ pthread_mutex_destroy(&buffer->mutex);
+ pthread_cond_destroy(&buffer->waiting_filling_buffer);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Free log handler resources
+
+ SYNOPSIS
+ translog_destroy()
+*/
+
+void translog_destroy()
+{
+ TRANSLOG_FILE **file;
+ uint i;
+ uint8 current_buffer;
+ DBUG_ENTER("translog_destroy");
+
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+ translog_lock();
+ current_buffer= log_descriptor.bc.buffer_no;
+ translog_status= (translog_status == TRANSLOG_READONLY ?
+ TRANSLOG_UNINITED :
+ TRANSLOG_SHUTDOWN);
+ if (log_descriptor.bc.buffer->file != NULL)
+ translog_finish_page(&log_descriptor.horizon, &log_descriptor.bc);
+ translog_unlock();
+
+ for (i= 0; i < TRANSLOG_BUFFERS_NO; i++)
+ {
+ struct st_translog_buffer *buffer= (log_descriptor.buffers +
+ ((i + current_buffer + 1) %
+ TRANSLOG_BUFFERS_NO));
+ translog_buffer_destroy(buffer);
+ }
+ translog_status= TRANSLOG_UNINITED;
+
+ /* close files */
+ while ((file= (TRANSLOG_FILE **)pop_dynamic(&log_descriptor.open_files)))
+ translog_close_log_file(*file);
+ pthread_mutex_destroy(&log_descriptor.sent_to_disk_lock);
+ pthread_mutex_destroy(&log_descriptor.file_header_lock);
+ pthread_mutex_destroy(&log_descriptor.unfinished_files_lock);
+ pthread_mutex_destroy(&log_descriptor.purger_lock);
+ pthread_mutex_destroy(&log_descriptor.log_flush_lock);
+ pthread_mutex_destroy(&log_descriptor.dirty_buffer_mask_lock);
+ pthread_cond_destroy(&log_descriptor.log_flush_cond);
+ rwlock_destroy(&log_descriptor.open_files_lock);
+ delete_dynamic(&log_descriptor.open_files);
+ delete_dynamic(&log_descriptor.unfinished_files);
+
+ if (log_descriptor.directory_fd >= 0)
+ my_close(log_descriptor.directory_fd, MYF(MY_WME));
+ my_atomic_rwlock_destroy(&LOCK_id_to_share);
+ if (id_to_share != NULL)
+ my_free((uchar*)(id_to_share + 1), MYF(MY_WME));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ @brief Starts new page.
+
+ @param horizon \ Position in file and buffer where we are
+ @param cursor /
+ @param prev_buffer Buffer which should be flushed will be assigned here.
+ This is always set (to NULL if nothing to flush).
+
+ @note We do not want to flush the buffer immediately because we want to
+ let caller of this function first advance 'horizon' pointer and unlock the
+ loghandler and only then flush the log which can take some time.
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_page_next(TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor,
+ struct st_translog_buffer **prev_buffer)
+{
+ struct st_translog_buffer *buffer= cursor->buffer;
+ DBUG_ENTER("translog_page_next");
+
+ *prev_buffer= NULL;
+ if ((cursor->ptr + TRANSLOG_PAGE_SIZE >
+ cursor->buffer->buffer + TRANSLOG_WRITE_BUFFER) ||
+ (LSN_OFFSET(*horizon) >
+ log_descriptor.log_file_max_size - TRANSLOG_PAGE_SIZE))
+ {
+ DBUG_PRINT("info", ("Switch to next buffer Buffer Size: %lu (%lu) => %d "
+ "File size: %lu max: %lu => %d",
+ (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer),
+ (cursor->ptr + TRANSLOG_PAGE_SIZE >
+ cursor->buffer->buffer + TRANSLOG_WRITE_BUFFER),
+ (ulong) LSN_OFFSET(*horizon),
+ (ulong) log_descriptor.log_file_max_size,
+ (LSN_OFFSET(*horizon) >
+ (log_descriptor.log_file_max_size -
+ TRANSLOG_PAGE_SIZE))));
+ if (translog_buffer_next(horizon, cursor,
+ LSN_OFFSET(*horizon) >
+ (log_descriptor.log_file_max_size -
+ TRANSLOG_PAGE_SIZE)))
+ DBUG_RETURN(1);
+ *prev_buffer= buffer;
+ DBUG_PRINT("info", ("Buffer #%u (0x%lu): have to be flushed",
+ (uint) buffer->buffer_no, (ulong) buffer));
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Use the same buffer #%u (0x%lu): "
+ "Buffer Size: %lu (%lu)",
+ (uint) buffer->buffer_no,
+ (ulong) buffer,
+ (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer)));
+ translog_finish_page(horizon, cursor);
+ translog_new_page_header(horizon, cursor);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Write data of given length to the current page
+
+ SYNOPSIS
+ translog_write_data_on_page()
+ horizon \ Pointers on file and buffer
+ cursor /
+ length IN length of the chunk
+ buffer buffer with data
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_write_data_on_page(TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor,
+ translog_size_t length,
+ uchar *buffer)
+{
+ DBUG_ENTER("translog_write_data_on_page");
+ DBUG_PRINT("enter", ("Chunk length: %lu Page size %u",
+ (ulong) length, (uint) cursor->current_page_fill));
+ DBUG_ASSERT(length > 0);
+ DBUG_ASSERT(length + cursor->current_page_fill <= TRANSLOG_PAGE_SIZE);
+ DBUG_ASSERT(length + cursor->ptr <= cursor->buffer->buffer +
+ TRANSLOG_WRITE_BUFFER);
+
+ memcpy(cursor->ptr, buffer, length);
+ cursor->ptr+= length;
+ (*horizon)+= length; /* adds offset */
+ cursor->current_page_fill+= length;
+ if (!cursor->chaser)
+ cursor->buffer->size+= length;
+ DBUG_PRINT("info", ("Write data buffer #%u: 0x%lx "
+ "chaser: %d Size: %lu (%lu)",
+ (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
+ cursor->chaser, (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer)));
+ translog_check_cursor(cursor);
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Write data from parts of given length to the current page
+
+ SYNOPSIS
+ translog_write_parts_on_page()
+ horizon \ Pointers on file and buffer
+ cursor /
+ length IN length of the chunk
+ parts IN/OUT chunk source
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_write_parts_on_page(TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor,
+ translog_size_t length,
+ struct st_translog_parts *parts)
+{
+ translog_size_t left= length;
+ uint cur= (uint) parts->current;
+ DBUG_ENTER("translog_write_parts_on_page");
+ DBUG_PRINT("enter", ("Chunk length: %lu parts: %u of %u. Page size: %u "
+ "Buffer size: %lu (%lu)",
+ (ulong) length,
+ (uint) (cur + 1), (uint) parts->elements,
+ (uint) cursor->current_page_fill,
+ (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer)));
+ DBUG_ASSERT(length > 0);
+ DBUG_ASSERT(length + cursor->current_page_fill <= TRANSLOG_PAGE_SIZE);
+ DBUG_ASSERT(length + cursor->ptr <= cursor->buffer->buffer +
+ TRANSLOG_WRITE_BUFFER);
+
+ do
+ {
+ translog_size_t len;
+ LEX_CUSTRING *part;
+ const uchar *buff;
+
+ DBUG_ASSERT(cur < parts->elements);
+ part= parts->parts + cur;
+ buff= part->str;
+ DBUG_PRINT("info", ("Part: %u Length: %lu left: %lu buff: 0x%lx",
+ (uint) (cur + 1), (ulong) part->length, (ulong) left,
+ (ulong) buff));
+
+ if (part->length > left)
+ {
+ /* we should write less then the current part */
+ len= left;
+ part->length-= len;
+ part->str+= len;
+ DBUG_PRINT("info", ("Set new part: %u Length: %lu",
+ (uint) (cur + 1), (ulong) part->length));
+ }
+ else
+ {
+ len= (translog_size_t) part->length;
+ cur++;
+ DBUG_PRINT("info", ("moved to next part (len: %lu)", (ulong) len));
+ }
+ DBUG_PRINT("info", ("copy: 0x%lx <- 0x%lx %u",
+ (ulong) cursor->ptr, (ulong)buff, (uint)len));
+ if (likely(len))
+ {
+ memcpy(cursor->ptr, buff, len);
+ left-= len;
+ cursor->ptr+= len;
+ }
+ } while (left);
+
+ DBUG_PRINT("info", ("Horizon: (%lu,0x%lx) Length %lu(0x%lx)",
+ LSN_IN_PARTS(*horizon),
+ (ulong) length, (ulong) length));
+ parts->current= cur;
+ (*horizon)+= length; /* offset increasing */
+ cursor->current_page_fill+= length;
+ if (!cursor->chaser)
+ cursor->buffer->size+= length;
+ /*
+ We do not not updating parts->total_record_length here because it is
+ need only before writing record to have total length
+ */
+ DBUG_PRINT("info", ("Write parts buffer #%u: 0x%lx "
+ "chaser: %d Size: %lu (%lu) "
+ "Horizon: (%lu,0x%lx) buff offset: 0x%lx",
+ (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
+ cursor->chaser, (ulong) cursor->buffer->size,
+ (ulong) (cursor->ptr - cursor->buffer->buffer),
+ LSN_IN_PARTS(*horizon),
+ (ulong) (LSN_OFFSET(cursor->buffer->offset) +
+ cursor->buffer->size)));
+ translog_check_cursor(cursor);
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Put 1 group chunk type 0 header into parts array
+
+ SYNOPSIS
+ translog_write_variable_record_1group_header()
+ parts Descriptor of record source parts
+ type The log record type
+ short_trid Short transaction ID or 0 if it has no sense
+ header_length Calculated header length of chunk type 0
+ chunk0_header Buffer for the chunk header writing
+*/
+
+static void
+translog_write_variable_record_1group_header(struct st_translog_parts *parts,
+ enum translog_record_type type,
+ SHORT_TRANSACTION_ID short_trid,
+ uint16 header_length,
+ uchar *chunk0_header)
+{
+ LEX_CUSTRING *part;
+ DBUG_ASSERT(parts->current != 0); /* first part is left for header */
+ part= parts->parts + (--parts->current);
+ parts->total_record_length+= (translog_size_t) (part->length= header_length);
+ part->str= chunk0_header;
+ /* puts chunk type */
+ *chunk0_header= (uchar) (type | TRANSLOG_CHUNK_LSN);
+ int2store(chunk0_header + 1, short_trid);
+ /* puts record length */
+ translog_write_variable_record_1group_code_len(chunk0_header + 3,
+ parts->record_length,
+ header_length);
+ /* puts 0 as chunk length which indicate 1 group record */
+ int2store(chunk0_header + header_length - 2, 0);
+}
+
+
+/*
+ Increase number of writers for this buffer
+
+ SYNOPSIS
+ translog_buffer_increase_writers()
+ buffer target buffer
+*/
+
+static inline void
+translog_buffer_increase_writers(struct st_translog_buffer *buffer)
+{
+ DBUG_ENTER("translog_buffer_increase_writers");
+ translog_buffer_lock_assert_owner(buffer);
+ buffer->copy_to_buffer_in_progress++;
+ DBUG_PRINT("info", ("copy_to_buffer_in_progress. Buffer #%u 0x%lx progress: %d",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ buffer->copy_to_buffer_in_progress));
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Decrease number of writers for this buffer
+
+ SYNOPSIS
+ translog_buffer_decrease_writers()
+ buffer target buffer
+*/
+
+static void translog_buffer_decrease_writers(struct st_translog_buffer *buffer)
+{
+ DBUG_ENTER("translog_buffer_decrease_writers");
+ translog_buffer_lock_assert_owner(buffer);
+ buffer->copy_to_buffer_in_progress--;
+ DBUG_PRINT("info",
+ ("copy_to_buffer_in_progress. Buffer #%u 0x%lx progress: %d",
+ (uint) buffer->buffer_no, (ulong) buffer,
+ buffer->copy_to_buffer_in_progress));
+ if (buffer->copy_to_buffer_in_progress == 0)
+ pthread_cond_broadcast(&buffer->waiting_filling_buffer);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Skip to the next page for chaser (thread which advanced horizon
+ pointer and now feeling the buffer)
+
+ @param horizon \ Pointers on file position and buffer
+ @param cursor /
+
+ @retval 1 OK
+ @retval 0 Error
+*/
+
+static my_bool translog_chaser_page_next(TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor)
+{
+ struct st_translog_buffer *buffer_to_flush;
+ my_bool rc;
+ DBUG_ENTER("translog_chaser_page_next");
+ DBUG_ASSERT(cursor->chaser);
+ rc= translog_page_next(horizon, cursor, &buffer_to_flush);
+ if (buffer_to_flush != NULL)
+ {
+ translog_buffer_lock(buffer_to_flush);
+ translog_buffer_decrease_writers(buffer_to_flush);
+ if (!rc)
+ rc= translog_buffer_flush(buffer_to_flush);
+ translog_buffer_unlock(buffer_to_flush);
+ }
+ DBUG_RETURN(rc);
+}
+
+/*
+ Put chunk 2 from new page beginning
+
+ SYNOPSIS
+ translog_write_variable_record_chunk2_page()
+ parts Descriptor of record source parts
+ horizon \ Pointers on file position and buffer
+ cursor /
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool
+translog_write_variable_record_chunk2_page(struct st_translog_parts *parts,
+ TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor)
+{
+ uchar chunk2_header[1];
+ DBUG_ENTER("translog_write_variable_record_chunk2_page");
+ chunk2_header[0]= TRANSLOG_CHUNK_NOHDR;
+
+ if (translog_chaser_page_next(horizon, cursor))
+ DBUG_RETURN(1);
+
+ /* Puts chunk type */
+ translog_write_data_on_page(horizon, cursor, 1, chunk2_header);
+ /* Puts chunk body */
+ translog_write_parts_on_page(horizon, cursor,
+ log_descriptor.page_capacity_chunk_2, parts);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Put chunk 3 of requested length in the buffer from new page beginning
+
+ SYNOPSIS
+ translog_write_variable_record_chunk3_page()
+ parts Descriptor of record source parts
+ length Length of this chunk
+ horizon \ Pointers on file position and buffer
+ cursor /
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool
+translog_write_variable_record_chunk3_page(struct st_translog_parts *parts,
+ uint16 length,
+ TRANSLOG_ADDRESS *horizon,
+ struct st_buffer_cursor *cursor)
+{
+ LEX_CUSTRING *part;
+ uchar chunk3_header[1 + 2];
+ DBUG_ENTER("translog_write_variable_record_chunk3_page");
+
+ if (translog_chaser_page_next(horizon, cursor))
+ DBUG_RETURN(1);
+
+ if (length == 0)
+ {
+ /* It was call to write page header only (no data for chunk 3) */
+ DBUG_PRINT("info", ("It is a call to make page header only"));
+ DBUG_RETURN(0);
+ }
+
+ DBUG_ASSERT(parts->current != 0); /* first part is left for header */
+ part= parts->parts + (--parts->current);
+ parts->total_record_length+= (translog_size_t) (part->length= 1 + 2);
+ part->str= chunk3_header;
+ /* Puts chunk type */
+ *chunk3_header= (uchar) (TRANSLOG_CHUNK_LNGTH);
+ /* Puts chunk length */
+ int2store(chunk3_header + 1, length);
+
+ translog_write_parts_on_page(horizon, cursor, length + 1 + 2, parts);
+ DBUG_RETURN(0);
+}
+
+/*
+ Move log pointer (horizon) on given number pages starting from next page,
+ and given offset on the last page
+
+ SYNOPSIS
+ translog_advance_pointer()
+ pages Number of full pages starting from the next one
+ last_page_data Plus this data on the last page
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_advance_pointer(int pages, uint16 last_page_data)
+{
+ translog_size_t last_page_offset= (log_descriptor.page_overhead +
+ last_page_data);
+ translog_size_t offset= (TRANSLOG_PAGE_SIZE -
+ log_descriptor.bc.current_page_fill +
+ pages * TRANSLOG_PAGE_SIZE + last_page_offset);
+ translog_size_t buffer_end_offset, file_end_offset, min_offset;
+ DBUG_ENTER("translog_advance_pointer");
+ DBUG_PRINT("enter", ("Pointer: (%lu, 0x%lx) + %u + %u pages + %u + %u",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ (uint) (TRANSLOG_PAGE_SIZE -
+ log_descriptor.bc.current_page_fill),
+ pages, (uint) log_descriptor.page_overhead,
+ (uint) last_page_data));
+ translog_lock_assert_owner();
+
+ if (pages == -1)
+ {
+ /*
+ It is special case when we advance the pointer on the same page.
+ It can happened when we write last part of multi-group record.
+ */
+ DBUG_ASSERT(last_page_data + log_descriptor.bc.current_page_fill <=
+ TRANSLOG_PAGE_SIZE);
+ offset= last_page_data;
+ last_page_offset= log_descriptor.bc.current_page_fill + last_page_data;
+ goto end;
+ }
+ DBUG_PRINT("info", ("last_page_offset %lu", (ulong) last_page_offset));
+ DBUG_ASSERT(last_page_offset <= TRANSLOG_PAGE_SIZE);
+
+ /*
+ The loop will be executed 1-3 times. Usually we advance the
+ pointer to fill only the current buffer (if we have more then 1/2 of
+ buffer free or 2 buffers (rest of current and all next). In case of
+ really huge record end where we write last group with "table of
+ content" of all groups and ignore buffer borders we can occupy
+ 3 buffers.
+ */
+ for (;;)
+ {
+ uint8 new_buffer_no;
+ struct st_translog_buffer *new_buffer;
+ struct st_translog_buffer *old_buffer;
+ buffer_end_offset= TRANSLOG_WRITE_BUFFER - log_descriptor.bc.buffer->size;
+ if (likely(log_descriptor.log_file_max_size >=
+ LSN_OFFSET(log_descriptor.horizon)))
+ file_end_offset= (log_descriptor.log_file_max_size -
+ LSN_OFFSET(log_descriptor.horizon));
+ else
+ {
+ /*
+ We already have written more then current file limit allow,
+ So we will finish this page and start new file
+ */
+ file_end_offset= (TRANSLOG_PAGE_SIZE -
+ log_descriptor.bc.current_page_fill);
+ }
+ DBUG_PRINT("info", ("offset: %lu buffer_end_offs: %lu, "
+ "file_end_offs: %lu",
+ (ulong) offset, (ulong) buffer_end_offset,
+ (ulong) file_end_offset));
+ DBUG_PRINT("info", ("Buff #%u %u (0x%lx) offset 0x%lx + size 0x%lx = "
+ "0x%lx (0x%lx)",
+ (uint) log_descriptor.bc.buffer->buffer_no,
+ (uint) log_descriptor.bc.buffer_no,
+ (ulong) log_descriptor.bc.buffer,
+ (ulong) LSN_OFFSET(log_descriptor.bc.buffer->offset),
+ (ulong) log_descriptor.bc.buffer->size,
+ (ulong) (LSN_OFFSET(log_descriptor.bc.buffer->offset) +
+ log_descriptor.bc.buffer->size),
+ (ulong) LSN_OFFSET(log_descriptor.horizon)));
+ DBUG_ASSERT(LSN_OFFSET(log_descriptor.bc.buffer->offset) +
+ log_descriptor.bc.buffer->size ==
+ LSN_OFFSET(log_descriptor.horizon));
+
+ if (offset <= buffer_end_offset && offset <= file_end_offset)
+ break;
+ old_buffer= log_descriptor.bc.buffer;
+ new_buffer_no= (log_descriptor.bc.buffer_no + 1) % TRANSLOG_BUFFERS_NO;
+ new_buffer= log_descriptor.buffers + new_buffer_no;
+
+ translog_buffer_lock(new_buffer);
+#ifndef DBUG_OFF
+ {
+ TRANSLOG_ADDRESS offset= new_buffer->offset;
+ TRANSLOG_FILE *file= new_buffer->file;
+ uint8 ver= new_buffer->ver;
+ translog_lock_assert_owner();
+#endif
+ translog_wait_for_buffer_free(new_buffer);
+#ifndef DBUG_OFF
+ /* We keep the handler locked so nobody can start this new buffer */
+ DBUG_ASSERT(offset == new_buffer->offset && new_buffer->file == NULL &&
+ (file == NULL ? ver : (uint8)(ver + 1)) == new_buffer->ver);
+ }
+#endif
+
+ min_offset= min(buffer_end_offset, file_end_offset);
+ /* TODO: check is it ptr or size enough */
+ log_descriptor.bc.buffer->size+= min_offset;
+ log_descriptor.bc.ptr+= min_offset;
+ DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx chaser: %d Size: %lu (%lu)",
+ (uint) log_descriptor.bc.buffer->buffer_no,
+ (ulong) log_descriptor.bc.buffer,
+ log_descriptor.bc.chaser,
+ (ulong) log_descriptor.bc.buffer->size,
+ (ulong) (log_descriptor.bc.ptr -log_descriptor.bc.
+ buffer->buffer)));
+ DBUG_ASSERT((ulong) (log_descriptor.bc.ptr -
+ log_descriptor.bc.buffer->buffer) ==
+ log_descriptor.bc.buffer->size);
+ DBUG_ASSERT(log_descriptor.bc.buffer->buffer_no ==
+ log_descriptor.bc.buffer_no);
+ translog_buffer_increase_writers(log_descriptor.bc.buffer);
+
+ if (file_end_offset <= buffer_end_offset)
+ {
+ log_descriptor.horizon+= LSN_ONE_FILE;
+ log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
+ TRANSLOG_PAGE_SIZE);
+ DBUG_PRINT("info", ("New file: %lu",
+ (ulong) LSN_FILE_NO(log_descriptor.horizon)));
+ if (translog_create_new_file())
+ {
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info", ("The same file"));
+ log_descriptor.horizon+= min_offset; /* offset increasing */
+ }
+ translog_start_buffer(new_buffer, &log_descriptor.bc, new_buffer_no);
+ old_buffer->next_buffer_offset= new_buffer->offset;
+ new_buffer->prev_buffer_offset= old_buffer->offset;
+ translog_buffer_unlock(old_buffer);
+ offset-= min_offset;
+ }
+ DBUG_PRINT("info", ("drop write_counter"));
+ log_descriptor.bc.write_counter= 0;
+ log_descriptor.bc.previous_offset= 0;
+end:
+ log_descriptor.bc.ptr+= offset;
+ log_descriptor.bc.buffer->size+= offset;
+ translog_buffer_increase_writers(log_descriptor.bc.buffer);
+ log_descriptor.horizon+= offset; /* offset increasing */
+ log_descriptor.bc.current_page_fill= last_page_offset;
+ DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx chaser: %d Size: %lu (%lu) "
+ "offset: %u last page: %u",
+ (uint) log_descriptor.bc.buffer->buffer_no,
+ (ulong) log_descriptor.bc.buffer,
+ log_descriptor.bc.chaser,
+ (ulong) log_descriptor.bc.buffer->size,
+ (ulong) (log_descriptor.bc.ptr -
+ log_descriptor.bc.buffer->
+ buffer), (uint) offset,
+ (uint) last_page_offset));
+ DBUG_PRINT("info",
+ ("pointer moved to: (%lu, 0x%lx)",
+ LSN_IN_PARTS(log_descriptor.horizon)));
+ translog_check_cursor(&log_descriptor.bc);
+ log_descriptor.bc.protected= 0;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Get page rest
+
+ SYNOPSIS
+ translog_get_current_page_rest()
+
+ NOTE loghandler should be locked
+
+ RETURN
+ number of bytes left on the current page
+*/
+
+static uint translog_get_current_page_rest()
+{
+ return (TRANSLOG_PAGE_SIZE - log_descriptor.bc.current_page_fill);
+}
+
+
+/*
+ Get buffer rest in full pages
+
+ SYNOPSIS
+ translog_get_current_buffer_rest()
+
+ NOTE loghandler should be locked
+
+ RETURN
+ number of full pages left on the current buffer
+*/
+
+static uint translog_get_current_buffer_rest()
+{
+ return ((log_descriptor.bc.buffer->buffer + TRANSLOG_WRITE_BUFFER -
+ log_descriptor.bc.ptr) /
+ TRANSLOG_PAGE_SIZE);
+}
+
+/*
+ Calculate possible group size without first (current) page
+
+ SYNOPSIS
+ translog_get_current_group_size()
+
+ NOTE loghandler should be locked
+
+ RETURN
+ group size without first (current) page
+*/
+
+static translog_size_t translog_get_current_group_size()
+{
+ /* buffer rest in full pages */
+ translog_size_t buffer_rest= translog_get_current_buffer_rest();
+ DBUG_ENTER("translog_get_current_group_size");
+ DBUG_PRINT("info", ("buffer_rest in pages: %u", buffer_rest));
+
+ buffer_rest*= log_descriptor.page_capacity_chunk_2;
+ /* in case of only half of buffer free we can write this and next buffer */
+ if (buffer_rest < log_descriptor.half_buffer_capacity_chunk_2)
+ {
+ DBUG_PRINT("info", ("buffer_rest: %lu -> add %lu",
+ (ulong) buffer_rest,
+ (ulong) log_descriptor.buffer_capacity_chunk_2));
+ buffer_rest+= log_descriptor.buffer_capacity_chunk_2;
+ }
+
+ DBUG_PRINT("info", ("buffer_rest: %lu", (ulong) buffer_rest));
+
+ DBUG_RETURN(buffer_rest);
+}
+
+
+static inline void set_lsn(LSN *lsn, LSN value)
+{
+ DBUG_ENTER("set_lsn");
+ translog_lock_assert_owner();
+ *lsn= value;
+ /* we generate LSN so something is not flushed in log */
+ log_descriptor.is_everything_flushed= 0;
+ DBUG_PRINT("info", ("new LSN appeared: (%lu,0x%lx)", LSN_IN_PARTS(value)));
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Write variable record in 1 group.
+
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param buffer_to_flush Buffer which have to be flushed if it is not 0
+ @param header_length Calculated header length of chunk type 0
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
+
+ @note
+ We must have a translog_lock() when entering this function
+ We must have buffer_to_flush locked (if not null)
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool
+translog_write_variable_record_1group(LSN *lsn,
+ enum translog_record_type type,
+ MARIA_HA *tbl_info,
+ SHORT_TRANSACTION_ID short_trid,
+ struct st_translog_parts *parts,
+ struct st_translog_buffer
+ *buffer_to_flush, uint16 header_length,
+ TRN *trn, void *hook_arg)
+{
+ TRANSLOG_ADDRESS horizon;
+ struct st_buffer_cursor cursor;
+ int rc= 0;
+ uint i;
+ translog_size_t record_rest, full_pages, first_page;
+ uint additional_chunk3_page= 0;
+ uchar chunk0_header[1 + 2 + 5 + 2];
+ DBUG_ENTER("translog_write_variable_record_1group");
+ translog_lock_assert_owner();
+ if (buffer_to_flush)
+ translog_buffer_lock_assert_owner(buffer_to_flush);
+
+ set_lsn(lsn, horizon= log_descriptor.horizon);
+ if (translog_set_lsn_for_files(LSN_FILE_NO(*lsn), LSN_FILE_NO(*lsn),
+ *lsn, TRUE) ||
+ (log_record_type_descriptor[type].inwrite_hook &&
+ (*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
+ lsn, hook_arg)))
+ {
+ translog_unlock();
+ DBUG_RETURN(1);
+ }
+ cursor= log_descriptor.bc;
+ cursor.chaser= 1;
+
+ /* Advance pointer to be able unlock the loghandler */
+ first_page= translog_get_current_page_rest();
+ record_rest= parts->record_length - (first_page - header_length);
+ full_pages= record_rest / log_descriptor.page_capacity_chunk_2;
+ record_rest= (record_rest % log_descriptor.page_capacity_chunk_2);
+
+ if (record_rest + 1 == log_descriptor.page_capacity_chunk_2)
+ {
+ DBUG_PRINT("info", ("2 chunks type 3 is needed"));
+ /* We will write 2 chunks type 3 at the end of this group */
+ additional_chunk3_page= 1;
+ record_rest= 1;
+ }
+
+ DBUG_PRINT("info", ("first_page: %u (%u) full_pages: %u (%lu) "
+ "additional: %u (%u) rest %u = %u",
+ first_page, first_page - header_length,
+ full_pages,
+ (ulong) full_pages *
+ log_descriptor.page_capacity_chunk_2,
+ additional_chunk3_page,
+ additional_chunk3_page *
+ (log_descriptor.page_capacity_chunk_2 - 1),
+ record_rest, parts->record_length));
+ /* record_rest + 3 is chunk type 3 overhead + record_rest */
+ rc|= translog_advance_pointer((int)(full_pages + additional_chunk3_page),
+ (record_rest ? record_rest + 3 : 0));
+ log_descriptor.bc.buffer->last_lsn= *lsn;
+ DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx) buffer: 0x%lx",
+ LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn),
+ (ulong) log_descriptor.bc.buffer));
+
+ translog_unlock();
+
+ /*
+ Check if we switched buffer and need process it (current buffer is
+ unlocked already => we will not delay other threads
+ */
+ if (buffer_to_flush != NULL)
+ {
+ if (!rc)
+ rc= translog_buffer_flush(buffer_to_flush);
+ translog_buffer_unlock(buffer_to_flush);
+ }
+ if (rc)
+ DBUG_RETURN(1);
+
+ translog_write_variable_record_1group_header(parts, type, short_trid,
+ header_length, chunk0_header);
+
+ /* fill the pages */
+ translog_write_parts_on_page(&horizon, &cursor, first_page, parts);
+
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon)));
+
+ for (i= 0; i < full_pages; i++)
+ {
+ if (translog_write_variable_record_chunk2_page(parts, &horizon, &cursor))
+ DBUG_RETURN(1);
+
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon)));
+ }
+
+ if (additional_chunk3_page)
+ {
+ if (translog_write_variable_record_chunk3_page(parts,
+ log_descriptor.
+ page_capacity_chunk_2 - 2,
+ &horizon, &cursor))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon)));
+ DBUG_ASSERT(cursor.current_page_fill == TRANSLOG_PAGE_SIZE);
+ }
+
+ if (translog_write_variable_record_chunk3_page(parts,
+ record_rest,
+ &horizon, &cursor))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx)",
+ (ulong) LSN_FILE_NO(log_descriptor.horizon),
+ (ulong) LSN_OFFSET(log_descriptor.horizon),
+ (ulong) LSN_FILE_NO(horizon),
+ (ulong) LSN_OFFSET(horizon)));
+
+ translog_buffer_lock(cursor.buffer);
+ translog_buffer_decrease_writers(cursor.buffer);
+ translog_buffer_unlock(cursor.buffer);
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief Write variable record in 1 chunk.
+
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param buffer_to_flush Buffer which have to be flushed if it is not 0
+ @param header_length Calculated header length of chunk type 0
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
+
+ @note
+ We must have a translog_lock() when entering this function
+ We must have buffer_to_flush locked (if not null)
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool
+translog_write_variable_record_1chunk(LSN *lsn,
+ enum translog_record_type type,
+ MARIA_HA *tbl_info,
+ SHORT_TRANSACTION_ID short_trid,
+ struct st_translog_parts *parts,
+ struct st_translog_buffer
+ *buffer_to_flush, uint16 header_length,
+ TRN *trn, void *hook_arg)
+{
+ int rc;
+ uchar chunk0_header[1 + 2 + 5 + 2];
+ DBUG_ENTER("translog_write_variable_record_1chunk");
+ translog_lock_assert_owner();
+ if (buffer_to_flush)
+ translog_buffer_lock_assert_owner(buffer_to_flush);
+
+ translog_write_variable_record_1group_header(parts, type, short_trid,
+ header_length, chunk0_header);
+ set_lsn(lsn, log_descriptor.horizon);
+ if (translog_set_lsn_for_files(LSN_FILE_NO(*lsn), LSN_FILE_NO(*lsn),
+ *lsn, TRUE) ||
+ (log_record_type_descriptor[type].inwrite_hook &&
+ (*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
+ lsn, hook_arg)))
+ {
+ translog_unlock();
+ DBUG_RETURN(1);
+ }
+
+ rc= translog_write_parts_on_page(&log_descriptor.horizon,
+ &log_descriptor.bc,
+ parts->total_record_length, parts);
+ log_descriptor.bc.buffer->last_lsn= *lsn;
+ DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx) buffer: 0x%lx",
+ LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn),
+ (ulong) log_descriptor.bc.buffer));
+ translog_unlock();
+
+ /*
+ check if we switched buffer and need process it (current buffer is
+ unlocked already => we will not delay other threads
+ */
+ if (buffer_to_flush != NULL)
+ {
+ if (!rc)
+ rc= translog_buffer_flush(buffer_to_flush);
+ translog_buffer_unlock(buffer_to_flush);
+ }
+
+ DBUG_RETURN(rc);
+}
+
+
+/*
+ @brief Calculates and write LSN difference (compressed LSN).
+
+ @param base_lsn LSN from which we calculate difference
+ @param lsn LSN for codding
+ @param dst Result will be written to dst[-pack_length] .. dst[-1]
+
+ @note To store an LSN in a compact way we will use the following compression:
+ If a log record has LSN1, and it contains the LSN2 as a back reference,
+ Instead of LSN2 we write LSN1-LSN2, encoded as:
+ two bits the number N (see below)
+ 14 bits
+ N bytes
+ That is, LSN is encoded in 2..5 bytes, and the number of bytes minus 2
+ is stored in the first two bits.
+
+ @note function made to write the result in backward direction with no
+ special sense or tricks both directions are equal in complicity
+
+ @retval # pointer on coded LSN
+*/
+
+static uchar *translog_put_LSN_diff(LSN base_lsn, LSN lsn, uchar *dst)
+{
+ uint64 diff;
+ DBUG_ENTER("translog_put_LSN_diff");
+ DBUG_PRINT("enter", ("Base: (%lu,0x%lx) val: (%lu,0x%lx) dst: 0x%lx",
+ LSN_IN_PARTS(base_lsn), LSN_IN_PARTS(lsn),
+ (ulong) dst));
+ DBUG_ASSERT(base_lsn > lsn);
+ diff= base_lsn - lsn;
+ DBUG_PRINT("info", ("Diff: 0x%llx", (ulonglong) diff));
+ if (diff <= 0x3FFF)
+ {
+ dst-= 2;
+ /*
+ Note we store this high uchar first to ensure that first uchar has
+ 0 in the 3 upper bits.
+ */
+ dst[0]= (uchar)(diff >> 8);
+ dst[1]= (uchar)(diff & 0xFF);
+ }
+ else if (diff <= 0x3FFFFFL)
+ {
+ dst-= 3;
+ dst[0]= (uchar)(0x40 | (diff >> 16));
+ int2store(dst + 1, diff & 0xFFFF);
+ }
+ else if (diff <= 0x3FFFFFFFL)
+ {
+ dst-= 4;
+ dst[0]= (uchar)(0x80 | (diff >> 24));
+ int3store(dst + 1, diff & 0xFFFFFFL);
+ }
+ else if (diff <= LL(0x3FFFFFFFFF))
+
+ {
+ dst-= 5;
+ dst[0]= (uchar)(0xC0 | (diff >> 32));
+ int4store(dst + 1, diff & 0xFFFFFFFFL);
+ }
+ else
+ {
+ /*
+ It is full LSN after special 1 diff (which is impossible
+ in real life)
+ */
+ dst-= 2 + LSN_STORE_SIZE;
+ dst[0]= 0;
+ dst[1]= 1;
+ lsn_store(dst + 2, lsn);
+ }
+ DBUG_PRINT("info", ("new dst: 0x%lx", (ulong) dst));
+ DBUG_RETURN(dst);
+}
+
+
+/*
+ Get LSN from LSN-difference (compressed LSN)
+
+ SYNOPSIS
+ translog_get_LSN_from_diff()
+ base_lsn LSN from which we calculate difference
+ src pointer to coded lsn
+ dst pointer to buffer where to write 7byte LSN
+
+ NOTE:
+ To store an LSN in a compact way we will use the following compression:
+
+ If a log record has LSN1, and it contains the lSN2 as a back reference,
+ Instead of LSN2 we write LSN1-LSN2, encoded as:
+
+ two bits the number N (see below)
+ 14 bits
+ N bytes
+
+ That is, LSN is encoded in 2..5 bytes, and the number of bytes minus 2
+ is stored in the first two bits.
+
+ RETURN
+ pointer to buffer after decoded LSN
+*/
+
+static uchar *translog_get_LSN_from_diff(LSN base_lsn, uchar *src, uchar *dst)
+{
+ LSN lsn;
+ uint32 diff;
+ uint32 first_byte;
+ uint32 file_no, rec_offset;
+ uint8 code;
+ DBUG_ENTER("translog_get_LSN_from_diff");
+ DBUG_PRINT("enter", ("Base: (%lu,0x%lx) src: 0x%lx dst 0x%lx",
+ LSN_IN_PARTS(base_lsn), (ulong) src, (ulong) dst));
+ first_byte= *((uint8*) src);
+ code= first_byte >> 6; /* Length is in 2 most significant bits */
+ first_byte&= 0x3F;
+ src++; /* Skip length + encode */
+ file_no= LSN_FILE_NO(base_lsn); /* Assume relative */
+ DBUG_PRINT("info", ("code: %u first byte: %lu",
+ (uint) code, (ulong) first_byte));
+ switch (code) {
+ case 0:
+ if (first_byte == 0 && *((uint8*)src) == 1)
+ {
+ /*
+ It is full LSN after special 1 diff (which is impossible
+ in real life)
+ */
+ memcpy(dst, src + 1, LSN_STORE_SIZE);
+ DBUG_PRINT("info", ("Special case of full LSN, new src: 0x%lx",
+ (ulong) (src + 1 + LSN_STORE_SIZE)));
+ DBUG_RETURN(src + 1 + LSN_STORE_SIZE);
+ }
+ rec_offset= LSN_OFFSET(base_lsn) - ((first_byte << 8) + *((uint8*)src));
+ break;
+ case 1:
+ diff= uint2korr(src);
+ rec_offset= LSN_OFFSET(base_lsn) - ((first_byte << 16) + diff);
+ break;
+ case 2:
+ diff= uint3korr(src);
+ rec_offset= LSN_OFFSET(base_lsn) - ((first_byte << 24) + diff);
+ break;
+ case 3:
+ {
+ ulonglong base_offset= LSN_OFFSET(base_lsn);
+ diff= uint4korr(src);
+ if (diff > LSN_OFFSET(base_lsn))
+ {
+ /* take 1 from file offset */
+ first_byte++;
+ base_offset+= LL(0x100000000);
+ }
+ file_no= LSN_FILE_NO(base_lsn) - first_byte;
+ DBUG_ASSERT(base_offset - diff <= UINT_MAX);
+ rec_offset= (uint32)(base_offset - diff);
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ DBUG_RETURN(NULL);
+ }
+ lsn= MAKE_LSN(file_no, rec_offset);
+ src+= code + 1;
+ lsn_store(dst, lsn);
+ DBUG_PRINT("info", ("new src: 0x%lx", (ulong) src));
+ DBUG_RETURN(src);
+}
+
+
+/**
+ @brief Encodes relative LSNs listed in the parameters.
+
+ @param parts Parts list with encoded LSN(s)
+ @param base_lsn LSN which is base for encoding
+ @param lsns number of LSN(s) to encode
+ @param compressed_LSNs buffer which can be used for storing compressed LSN(s)
+*/
+
+static void translog_relative_LSN_encode(struct st_translog_parts *parts,
+ LSN base_lsn,
+ uint lsns, uchar *compressed_LSNs)
+{
+ LEX_CUSTRING *part;
+ uint lsns_len= lsns * LSN_STORE_SIZE;
+ uchar buffer_src[MAX_NUMBER_OF_LSNS_PER_RECORD * LSN_STORE_SIZE];
+ uchar *buffer= buffer_src;
+ const uchar *cbuffer;
+
+ DBUG_ENTER("translog_relative_LSN_encode");
+
+ DBUG_ASSERT(parts->current != 0);
+ part= parts->parts + parts->current;
+
+ /* collect all LSN(s) in one chunk if it (they) is (are) divided */
+ if (part->length < lsns_len)
+ {
+ uint copied= part->length;
+ LEX_CUSTRING *next_part;
+ DBUG_PRINT("info", ("Using buffer: 0x%lx", (ulong) compressed_LSNs));
+ memcpy(buffer, part->str, part->length);
+ next_part= parts->parts + parts->current + 1;
+ do
+ {
+ DBUG_ASSERT(next_part < parts->parts + parts->elements);
+ if ((next_part->length + copied) < lsns_len)
+ {
+ memcpy(buffer + copied, next_part->str,
+ next_part->length);
+ copied+= next_part->length;
+ next_part->length= 0; next_part->str= 0;
+ /* delete_dynamic_element(&parts->parts, parts->current + 1); */
+ next_part++;
+ parts->current++;
+ part= parts->parts + parts->current;
+ }
+ else
+ {
+ uint len= lsns_len - copied;
+ memcpy(buffer + copied, next_part->str, len);
+ copied= lsns_len;
+ next_part->str+= len;
+ next_part->length-= len;
+ }
+ } while (copied < lsns_len);
+ cbuffer= buffer;
+ }
+ else
+ {
+ cbuffer= part->str;
+ part->str+= lsns_len;
+ part->length-= lsns_len;
+ parts->current--;
+ part= parts->parts + parts->current;
+ }
+
+ {
+ /* Compress */
+ LSN ref;
+ int economy;
+ const uchar *src_ptr;
+ uchar *dst_ptr= compressed_LSNs + (MAX_NUMBER_OF_LSNS_PER_RECORD *
+ COMPRESSED_LSN_MAX_STORE_SIZE);
+ /*
+ We write the result in backward direction with no special sense or
+ tricks both directions are equal in complicity
+ */
+ for (src_ptr= cbuffer + lsns_len - LSN_STORE_SIZE;
+ src_ptr >= (const uchar*)cbuffer;
+ src_ptr-= LSN_STORE_SIZE)
+ {
+ ref= lsn_korr(src_ptr);
+ dst_ptr= translog_put_LSN_diff(base_lsn, ref, dst_ptr);
+ }
+ part->length= (uint)((compressed_LSNs +
+ (MAX_NUMBER_OF_LSNS_PER_RECORD *
+ COMPRESSED_LSN_MAX_STORE_SIZE)) -
+ dst_ptr);
+ parts->record_length-= (economy= lsns_len - part->length);
+ DBUG_PRINT("info", ("new length of LSNs: %lu economy: %d",
+ (ulong)part->length, economy));
+ parts->total_record_length-= economy;
+ part->str= dst_ptr;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Write multi-group variable-size record.
+
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param buffer_to_flush Buffer which have to be flushed if it is not 0
+ @param header_length Header length calculated for 1 group
+ @param buffer_rest Beginning from which we plan to write in full pages
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
+
+ @note
+ We must have a translog_lock() when entering this function
+
+ We must have buffer_to_flush locked (if not null)
+ buffer_to_flush should *NOT* be locked when calling this function.
+ (This is note is here as this is different from most other
+ translog_write...() functions which require the buffer to be locked)
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool
+translog_write_variable_record_mgroup(LSN *lsn,
+ enum translog_record_type type,
+ MARIA_HA *tbl_info,
+ SHORT_TRANSACTION_ID short_trid,
+ struct st_translog_parts *parts,
+ struct st_translog_buffer
+ *buffer_to_flush,
+ uint16 header_length,
+ translog_size_t buffer_rest,
+ TRN *trn, void *hook_arg)
+{
+ TRANSLOG_ADDRESS horizon;
+ struct st_buffer_cursor cursor;
+ int rc= 0;
+ uint i, chunk2_page, full_pages;
+ uint curr_group= 0;
+ translog_size_t record_rest, first_page, chunk3_pages, chunk0_pages= 1;
+ translog_size_t done= 0;
+ struct st_translog_group_descriptor group;
+ DYNAMIC_ARRAY groups;
+ uint16 chunk3_size;
+ uint16 page_capacity= log_descriptor.page_capacity_chunk_2 + 1;
+ uint16 last_page_capacity;
+ my_bool new_page_before_chunk0= 1, first_chunk0= 1;
+ uchar chunk0_header[1 + 2 + 5 + 2 + 2], group_desc[7 + 1];
+ uchar chunk2_header[1];
+ uint header_fixed_part= header_length + 2;
+ uint groups_per_page= (page_capacity - header_fixed_part) / (7 + 1);
+ uint file_of_the_first_group;
+ int pages_to_skip;
+ struct st_translog_buffer *buffer_of_last_lsn;
+ DBUG_ENTER("translog_write_variable_record_mgroup");
+ translog_lock_assert_owner();
+
+ chunk2_header[0]= TRANSLOG_CHUNK_NOHDR;
+
+ if (my_init_dynamic_array(&groups,
+ sizeof(struct st_translog_group_descriptor),
+ 10, 10))
+ {
+ translog_unlock();
+ DBUG_PRINT("error", ("init array failed"));
+ DBUG_RETURN(1);
+ }
+
+ first_page= translog_get_current_page_rest();
+ record_rest= parts->record_length - (first_page - 1);
+ DBUG_PRINT("info", ("Record Rest: %lu", (ulong) record_rest));
+
+ if (record_rest < buffer_rest)
+ {
+ /*
+ The record (group 1 type) is larger than the free space on the page
+ - we need to split it in two. But when we split it in two, the first
+ part is big enough to hold all the data of the record (because the
+ header of the first part of the split is smaller than the header of
+ the record as a whole when it takes only one chunk)
+ */
+ DBUG_PRINT("info", ("too many free space because changing header"));
+ buffer_rest-= log_descriptor.page_capacity_chunk_2;
+ DBUG_ASSERT(record_rest >= buffer_rest);
+ }
+
+ file_of_the_first_group= LSN_FILE_NO(log_descriptor.horizon);
+ translog_mark_file_unfinished(file_of_the_first_group);
+ do
+ {
+ group.addr= horizon= log_descriptor.horizon;
+ cursor= log_descriptor.bc;
+ cursor.chaser= 1;
+ if ((full_pages= buffer_rest / log_descriptor.page_capacity_chunk_2) > 255)
+ {
+ /* sizeof(uint8) == 256 is max number of chunk in multi-chunks group */
+ full_pages= 255;
+ buffer_rest= full_pages * log_descriptor.page_capacity_chunk_2;
+ }
+ /*
+ group chunks =
+ full pages + first page (which actually can be full, too).
+ But here we assign number of chunks - 1
+ */
+ group.num= full_pages;
+ if (insert_dynamic(&groups, (uchar*) &group))
+ {
+ DBUG_PRINT("error", ("insert into array failed"));
+ goto err_unlock;
+ }
+
+ DBUG_PRINT("info", ("chunk: #%u first_page: %u (%u) "
+ "full_pages: %lu (%lu) "
+ "Left %lu",
+ groups.elements,
+ first_page, first_page - 1,
+ (ulong) full_pages,
+ (ulong) (full_pages *
+ log_descriptor.page_capacity_chunk_2),
+ (ulong)(parts->record_length - (first_page - 1 +
+ buffer_rest) -
+ done)));
+ rc|= translog_advance_pointer((int)full_pages, 0);
+
+ translog_unlock();
+
+ if (buffer_to_flush != NULL)
+ {
+ translog_buffer_decrease_writers(buffer_to_flush);
+ if (!rc)
+ rc= translog_buffer_flush(buffer_to_flush);
+ translog_buffer_unlock(buffer_to_flush);
+ buffer_to_flush= NULL;
+ }
+ if (rc)
+ {
+ DBUG_PRINT("error", ("flush of unlock buffer failed"));
+ goto err;
+ }
+
+ translog_write_data_on_page(&horizon, &cursor, 1, chunk2_header);
+ translog_write_parts_on_page(&horizon, &cursor, first_page - 1, parts);
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx) "
+ "Left %lu",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon),
+ (ulong) (parts->record_length - (first_page - 1) -
+ done)));
+
+ for (i= 0; i < full_pages; i++)
+ {
+ if (translog_write_variable_record_chunk2_page(parts, &horizon, &cursor))
+ goto err;
+
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) "
+ "local: (%lu,0x%lx) "
+ "Left: %lu",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon),
+ (ulong) (parts->record_length - (first_page - 1) -
+ i * log_descriptor.page_capacity_chunk_2 -
+ done)));
+ }
+
+ done+= (first_page - 1 + buffer_rest);
+
+ if (translog_chaser_page_next(&horizon, &cursor))
+ {
+ DBUG_PRINT("error", ("flush of unlock buffer failed"));
+ goto err;
+ }
+ translog_buffer_lock(cursor.buffer);
+ translog_buffer_decrease_writers(cursor.buffer);
+ translog_buffer_unlock(cursor.buffer);
+
+ translog_lock();
+
+ /* Check that we have place for chunk type 2 */
+ first_page= translog_get_current_page_rest();
+ if (first_page <= 1)
+ {
+ if (translog_page_next(&log_descriptor.horizon, &log_descriptor.bc,
+ &buffer_to_flush))
+ goto err_unlock;
+ first_page= translog_get_current_page_rest();
+ }
+ buffer_rest= translog_get_current_group_size();
+ } while ((translog_size_t)(first_page + buffer_rest) <
+ (translog_size_t)(parts->record_length - done));
+
+ group.addr= horizon= log_descriptor.horizon;
+ cursor= log_descriptor.bc;
+ cursor.chaser= 1;
+ group.num= 0; /* 0 because it does not matter */
+ if (insert_dynamic(&groups, (uchar*) &group))
+ {
+ DBUG_PRINT("error", ("insert into array failed"));
+ goto err_unlock;
+ }
+ record_rest= parts->record_length - done;
+ DBUG_PRINT("info", ("Record rest: %lu", (ulong) record_rest));
+ if (first_page > record_rest + 1)
+ {
+ /*
+ We have not so much data to fill all first page
+ (no speaking about full pages)
+ so it will be:
+ <chunk0 <data>>
+ or
+ <chunk0>...<chunk0><chunk0 <data>>
+ or
+ <chunk3 <data>><chunk0>...<chunk0><chunk0 <possible data of 1 byte>>
+ */
+ chunk2_page= full_pages= 0;
+ last_page_capacity= first_page;
+ pages_to_skip= -1;
+ }
+ else
+ {
+ /*
+ We will have:
+ <chunk2 <data>>...<chunk2 <data>><chunk0 <data>>
+ or
+ <chunk2 <data>>...<chunk2 <data>><chunk0>...<chunk0><chunk0 <data>>
+ or
+ <chunk3 <data>><chunk0>...<chunk0><chunk0 <possible data of 1 byte>>
+ */
+ chunk2_page= 1;
+ record_rest-= (first_page - 1);
+ pages_to_skip= full_pages=
+ record_rest / log_descriptor.page_capacity_chunk_2;
+ record_rest= (record_rest % log_descriptor.page_capacity_chunk_2);
+ last_page_capacity= page_capacity;
+ }
+ chunk3_size= 0;
+ chunk3_pages= 0;
+ if (last_page_capacity > record_rest + 1 && record_rest != 0)
+ {
+ if (last_page_capacity >
+ record_rest + header_fixed_part + groups.elements * (7 + 1))
+ {
+ /* 1 record of type 0 */
+ chunk3_pages= 0;
+ }
+ else
+ {
+ pages_to_skip++;
+ chunk3_pages= 1;
+ if (record_rest + 2 == last_page_capacity)
+ {
+ chunk3_size= record_rest - 1;
+ record_rest= 1;
+ }
+ else
+ {
+ chunk3_size= record_rest;
+ record_rest= 0;
+ }
+ }
+ }
+ /*
+ A first non-full page will hold type 0 chunk only if it fit in it with
+ all its headers
+ */
+ while (page_capacity <
+ record_rest + header_fixed_part +
+ (groups.elements - groups_per_page * (chunk0_pages - 1)) * (7 + 1))
+ chunk0_pages++;
+ DBUG_PRINT("info", ("chunk0_pages: %u groups %u groups per full page: %u "
+ "Group on last page: %u",
+ chunk0_pages, groups.elements,
+ groups_per_page,
+ (groups.elements -
+ ((page_capacity - header_fixed_part) / (7 + 1)) *
+ (chunk0_pages - 1))));
+ DBUG_PRINT("info", ("first_page: %u chunk2: %u full_pages: %u (%lu) "
+ "chunk3: %u (%u) rest: %u",
+ first_page,
+ chunk2_page, full_pages,
+ (ulong) full_pages *
+ log_descriptor.page_capacity_chunk_2,
+ chunk3_pages, (uint) chunk3_size, (uint) record_rest));
+ rc= translog_advance_pointer(pages_to_skip + (int)(chunk0_pages - 1),
+ record_rest + header_fixed_part +
+ (groups.elements -
+ ((page_capacity -
+ header_fixed_part) / (7 + 1)) *
+ (chunk0_pages - 1)) * (7 + 1));
+ buffer_of_last_lsn= log_descriptor.bc.buffer;
+ translog_unlock();
+
+ if (buffer_to_flush != NULL)
+ {
+ translog_buffer_decrease_writers(buffer_to_flush);
+ if (!rc)
+ rc= translog_buffer_flush(buffer_to_flush);
+ translog_buffer_unlock(buffer_to_flush);
+ buffer_to_flush= NULL;
+ }
+ if (rc)
+ {
+ DBUG_PRINT("error", ("flush of unlock buffer failed"));
+ goto err;
+ }
+
+ if (rc)
+ goto err;
+
+ if (chunk2_page)
+ {
+ DBUG_PRINT("info", ("chunk 2 to finish first page"));
+ translog_write_data_on_page(&horizon, &cursor, 1, chunk2_header);
+ translog_write_parts_on_page(&horizon, &cursor, first_page - 1, parts);
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx) "
+ "Left: %lu",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon),
+ (ulong) (parts->record_length - (first_page - 1) -
+ done)));
+ }
+ else if (chunk3_pages)
+ {
+ uchar chunk3_header[3];
+ DBUG_PRINT("info", ("chunk 3"));
+ DBUG_ASSERT(full_pages == 0);
+ chunk3_pages= 0;
+ chunk3_header[0]= TRANSLOG_CHUNK_LNGTH;
+ int2store(chunk3_header + 1, chunk3_size);
+ translog_write_data_on_page(&horizon, &cursor, 3, chunk3_header);
+ translog_write_parts_on_page(&horizon, &cursor, chunk3_size, parts);
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx) "
+ "Left: %lu",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon),
+ (ulong) (parts->record_length - chunk3_size - done)));
+ }
+ else
+ {
+ DBUG_PRINT("info", ("no new_page_before_chunk0"));
+ new_page_before_chunk0= 0;
+ }
+
+ for (i= 0; i < full_pages; i++)
+ {
+ DBUG_ASSERT(chunk2_page != 0);
+ if (translog_write_variable_record_chunk2_page(parts, &horizon, &cursor))
+ goto err;
+
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx) "
+ "Left: %lu",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon),
+ (ulong) (parts->record_length - (first_page - 1) -
+ i * log_descriptor.page_capacity_chunk_2 -
+ done)));
+ }
+
+ if (chunk3_pages &&
+ translog_write_variable_record_chunk3_page(parts,
+ chunk3_size,
+ &horizon, &cursor))
+ goto err;
+ DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx) local: (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.horizon),
+ LSN_IN_PARTS(horizon)));
+
+ *chunk0_header= (uchar) (type | TRANSLOG_CHUNK_LSN);
+ int2store(chunk0_header + 1, short_trid);
+ translog_write_variable_record_1group_code_len(chunk0_header + 3,
+ parts->record_length,
+ header_length);
+ do
+ {
+ int limit;
+ if (new_page_before_chunk0 &&
+ translog_chaser_page_next(&horizon, &cursor))
+ {
+ DBUG_PRINT("error", ("flush of unlock buffer failed"));
+ goto err;
+ }
+ new_page_before_chunk0= 1;
+
+ if (first_chunk0)
+ {
+ first_chunk0= 0;
+
+ /*
+ We can drop "log_descriptor.is_everything_flushed" earlier when have
+ lock on loghandler and assign initial value of "horizon" variable or
+ before unlocking loghandler (because we will increase writers
+ counter on the buffer and every thread which wanted flush the buffer
+ will wait till we finish with it). But IMHO better here take short
+ lock and do not bother other threads with waiting.
+ */
+ translog_lock();
+ set_lsn(lsn, horizon);
+ buffer_of_last_lsn->last_lsn= *lsn;
+ DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx) buffer: 0x%lx",
+ LSN_IN_PARTS(buffer_of_last_lsn->last_lsn),
+ (ulong) buffer_of_last_lsn));
+ if (log_record_type_descriptor[type].inwrite_hook &&
+ (*log_record_type_descriptor[type].inwrite_hook) (type, trn,
+ tbl_info,
+ lsn, hook_arg))
+ goto err_unlock;
+ translog_unlock();
+ }
+
+ /*
+ A first non-full page will hold type 0 chunk only if it fit in it with
+ all its headers => the fist page is full or number of groups less then
+ possible number of full page.
+ */
+ limit= (groups_per_page < groups.elements - curr_group ?
+ groups_per_page : groups.elements - curr_group);
+ DBUG_PRINT("info", ("Groups: %u curr: %u limit: %u",
+ (uint) groups.elements, (uint) curr_group,
+ (uint) limit));
+
+ if (chunk0_pages == 1)
+ {
+ DBUG_PRINT("info", ("chunk_len: 2 + %u * (7+1) + %u = %u",
+ (uint) limit, (uint) record_rest,
+ (uint) (2 + limit * (7 + 1) + record_rest)));
+ int2store(chunk0_header + header_length - 2,
+ 2 + limit * (7 + 1) + record_rest);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("chunk_len: 2 + %u * (7+1) = %u",
+ (uint) limit, (uint) (2 + limit * (7 + 1))));
+ int2store(chunk0_header + header_length - 2, 2 + limit * (7 + 1));
+ }
+ int2store(chunk0_header + header_length, groups.elements - curr_group);
+ translog_write_data_on_page(&horizon, &cursor, header_fixed_part,
+ chunk0_header);
+ for (i= curr_group; i < limit + curr_group; i++)
+ {
+ struct st_translog_group_descriptor *grp_ptr;
+ grp_ptr= dynamic_element(&groups, i,
+ struct st_translog_group_descriptor *);
+ lsn_store(group_desc, grp_ptr->addr);
+ group_desc[7]= grp_ptr->num;
+ translog_write_data_on_page(&horizon, &cursor, (7 + 1), group_desc);
+ }
+
+ if (chunk0_pages == 1 && record_rest != 0)
+ translog_write_parts_on_page(&horizon, &cursor, record_rest, parts);
+
+ chunk0_pages--;
+ curr_group+= limit;
+ /* put special type to indicate that it is not LSN chunk */
+ *chunk0_header= (uchar) (TRANSLOG_CHUNK_LSN | TRANSLOG_CHUNK_0_CONT);
+ } while (chunk0_pages != 0);
+ translog_buffer_lock(cursor.buffer);
+ translog_buffer_decrease_writers(cursor.buffer);
+ translog_buffer_unlock(cursor.buffer);
+ rc= 0;
+
+ if (translog_set_lsn_for_files(file_of_the_first_group, LSN_FILE_NO(*lsn),
+ *lsn, FALSE))
+ goto err;
+
+ translog_mark_file_finished(file_of_the_first_group);
+
+ delete_dynamic(&groups);
+ DBUG_RETURN(rc);
+
+err_unlock:
+
+ translog_unlock();
+
+err:
+ if (buffer_to_flush != NULL)
+ {
+ /* This is to prevent locking buffer forever in case of error */
+ translog_buffer_decrease_writers(buffer_to_flush);
+ if (!rc)
+ rc= translog_buffer_flush(buffer_to_flush);
+ translog_buffer_unlock(buffer_to_flush);
+ buffer_to_flush= NULL;
+ }
+
+
+ translog_mark_file_finished(file_of_the_first_group);
+
+ delete_dynamic(&groups);
+ DBUG_RETURN(1);
+}
+
+
+/**
+ @brief Write the variable length log record.
+
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_write_variable_record(LSN *lsn,
+ enum translog_record_type type,
+ MARIA_HA *tbl_info,
+ SHORT_TRANSACTION_ID short_trid,
+ struct st_translog_parts *parts,
+ TRN *trn, void *hook_arg)
+{
+ struct st_translog_buffer *buffer_to_flush= NULL;
+ uint header_length1= 1 + 2 + 2 +
+ translog_variable_record_length_bytes(parts->record_length);
+ ulong buffer_rest;
+ uint page_rest;
+ /* Max number of such LSNs per record is 2 */
+ uchar compressed_LSNs[MAX_NUMBER_OF_LSNS_PER_RECORD *
+ COMPRESSED_LSN_MAX_STORE_SIZE];
+ my_bool res;
+ DBUG_ENTER("translog_write_variable_record");
+
+ translog_lock();
+ DBUG_PRINT("info", ("horizon: (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.horizon)));
+ page_rest= TRANSLOG_PAGE_SIZE - log_descriptor.bc.current_page_fill;
+ DBUG_PRINT("info", ("header length: %u page_rest: %u",
+ header_length1, page_rest));
+
+ /*
+ header and part which we should read have to fit in one chunk
+ TODO: allow to divide readable header
+ */
+ if (page_rest <
+ (header_length1 + log_record_type_descriptor[type].read_header_len))
+ {
+ DBUG_PRINT("info",
+ ("Next page, size: %u header: %u + %u",
+ log_descriptor.bc.current_page_fill,
+ header_length1,
+ log_record_type_descriptor[type].read_header_len));
+ translog_page_next(&log_descriptor.horizon, &log_descriptor.bc,
+ &buffer_to_flush);
+ /* Chunk 2 header is 1 byte, so full page capacity will be one uchar more */
+ page_rest= log_descriptor.page_capacity_chunk_2 + 1;
+ DBUG_PRINT("info", ("page_rest: %u", page_rest));
+ }
+
+ /*
+ To minimize compressed size we will compress always relative to
+ very first chunk address (log_descriptor.horizon for now)
+ */
+ if (log_record_type_descriptor[type].compressed_LSN > 0)
+ {
+ translog_relative_LSN_encode(parts, log_descriptor.horizon,
+ log_record_type_descriptor[type].
+ compressed_LSN, compressed_LSNs);
+ /* recalculate header length after compression */
+ header_length1= 1 + 2 + 2 +
+ translog_variable_record_length_bytes(parts->record_length);
+ DBUG_PRINT("info", ("after compressing LSN(s) header length: %u "
+ "record length: %lu",
+ header_length1, (ulong)parts->record_length));
+ }
+
+ /* TODO: check space on current page for header + few bytes */
+ if (page_rest >= parts->record_length + header_length1)
+ {
+ /* following function makes translog_unlock(); */
+ res= translog_write_variable_record_1chunk(lsn, type, tbl_info,
+ short_trid,
+ parts, buffer_to_flush,
+ header_length1, trn, hook_arg);
+ DBUG_RETURN(res);
+ }
+
+ buffer_rest= translog_get_current_group_size();
+
+ if (buffer_rest >= parts->record_length + header_length1 - page_rest)
+ {
+ /* following function makes translog_unlock(); */
+ res= translog_write_variable_record_1group(lsn, type, tbl_info,
+ short_trid,
+ parts, buffer_to_flush,
+ header_length1, trn, hook_arg);
+ DBUG_RETURN(res);
+ }
+ /* following function makes translog_unlock(); */
+ res= translog_write_variable_record_mgroup(lsn, type, tbl_info,
+ short_trid,
+ parts, buffer_to_flush,
+ header_length1,
+ buffer_rest, trn, hook_arg);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Write the fixed and pseudo-fixed log record.
+
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param short_trid Short transaction ID or 0 if it has no sense
+ @param parts Descriptor of record source parts
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param hook_arg Argument which will be passed to pre-write and
+ in-write hooks of this record.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool translog_write_fixed_record(LSN *lsn,
+ enum translog_record_type type,
+ MARIA_HA *tbl_info,
+ SHORT_TRANSACTION_ID short_trid,
+ struct st_translog_parts *parts,
+ TRN *trn, void *hook_arg)
+{
+ struct st_translog_buffer *buffer_to_flush= NULL;
+ uchar chunk1_header[1 + 2];
+ /* Max number of such LSNs per record is 2 */
+ uchar compressed_LSNs[MAX_NUMBER_OF_LSNS_PER_RECORD *
+ COMPRESSED_LSN_MAX_STORE_SIZE];
+ LEX_CUSTRING *part;
+ int rc= 1;
+ DBUG_ENTER("translog_write_fixed_record");
+ DBUG_ASSERT((log_record_type_descriptor[type].rclass ==
+ LOGRECTYPE_FIXEDLENGTH &&
+ parts->record_length ==
+ log_record_type_descriptor[type].fixed_length) ||
+ (log_record_type_descriptor[type].rclass ==
+ LOGRECTYPE_PSEUDOFIXEDLENGTH &&
+ parts->record_length ==
+ log_record_type_descriptor[type].fixed_length));
+
+ translog_lock();
+ DBUG_PRINT("info", ("horizon: (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.horizon)));
+
+ DBUG_ASSERT(log_descriptor.bc.current_page_fill <= TRANSLOG_PAGE_SIZE);
+ DBUG_PRINT("info",
+ ("Page size: %u record: %u next cond: %d",
+ log_descriptor.bc.current_page_fill,
+ (parts->record_length +
+ log_record_type_descriptor[type].compressed_LSN * 2 + 3),
+ ((((uint) log_descriptor.bc.current_page_fill) +
+ (parts->record_length +
+ log_record_type_descriptor[type].compressed_LSN * 2 + 3)) >
+ TRANSLOG_PAGE_SIZE)));
+ /*
+ check that there is enough place on current page.
+ NOTE: compressing may increase page LSN size on two bytes for every LSN
+ */
+ if ((((uint) log_descriptor.bc.current_page_fill) +
+ (parts->record_length +
+ log_record_type_descriptor[type].compressed_LSN * 2 + 3)) >
+ TRANSLOG_PAGE_SIZE)
+ {
+ DBUG_PRINT("info", ("Next page"));
+ if (translog_page_next(&log_descriptor.horizon, &log_descriptor.bc,
+ &buffer_to_flush))
+ goto err; /* rc == 1 */
+ if (buffer_to_flush)
+ translog_buffer_lock_assert_owner(buffer_to_flush);
+ }
+
+ set_lsn(lsn, log_descriptor.horizon);
+ if (translog_set_lsn_for_files(LSN_FILE_NO(*lsn), LSN_FILE_NO(*lsn),
+ *lsn, TRUE) ||
+ (log_record_type_descriptor[type].inwrite_hook &&
+ (*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
+ lsn, hook_arg)))
+ goto err;
+
+ /* compress LSNs */
+ if (log_record_type_descriptor[type].rclass ==
+ LOGRECTYPE_PSEUDOFIXEDLENGTH)
+ {
+ DBUG_ASSERT(log_record_type_descriptor[type].compressed_LSN > 0);
+ translog_relative_LSN_encode(parts, *lsn,
+ log_record_type_descriptor[type].
+ compressed_LSN, compressed_LSNs);
+ }
+
+ /*
+ Write the whole record at once (we know that there is enough place on
+ the destination page)
+ */
+ DBUG_ASSERT(parts->current != 0); /* first part is left for header */
+ part= parts->parts + (--parts->current);
+ parts->total_record_length+= (translog_size_t) (part->length= 1 + 2);
+ part->str= chunk1_header;
+ *chunk1_header= (uchar) (type | TRANSLOG_CHUNK_FIXED);
+ int2store(chunk1_header + 1, short_trid);
+
+ rc= translog_write_parts_on_page(&log_descriptor.horizon,
+ &log_descriptor.bc,
+ parts->total_record_length, parts);
+
+ log_descriptor.bc.buffer->last_lsn= *lsn;
+ DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx) buffer: 0x%lx",
+ LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn),
+ (ulong) log_descriptor.bc.buffer));
+
+err:
+ translog_unlock();
+
+ /*
+ check if we switched buffer and need process it (current buffer is
+ unlocked already => we will not delay other threads
+ */
+ if (buffer_to_flush != NULL)
+ {
+ if (!rc)
+ rc= translog_buffer_flush(buffer_to_flush);
+ translog_buffer_unlock(buffer_to_flush);
+ }
+
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief Writes the log record
+
+ If share has no 2-byte-id yet, gives an id to the share and logs
+ LOGREC_FILE_ID. If transaction has not logged LOGREC_LONG_TRANSACTION_ID
+ yet, logs it.
+
+ @param lsn LSN of the record will be written here
+ @param type the log record type
+ @param trn Transaction structure pointer for hooks by
+ record log type, for short_id
+ @param tbl_info MARIA_HA of table or NULL
+ @param rec_len record length or 0 (count it)
+ @param part_no number of parts or 0 (count it)
+ @param parts_data zero ended (in case of number of parts is 0)
+ array of LEX_STRINGs (parts), first
+ TRANSLOG_INTERNAL_PARTS positions in the log
+ should be unused (need for loghandler)
+ @param store_share_id if tbl_info!=NULL then share's id will
+ automatically be stored in the two first bytes
+ pointed (so pointer is assumed to be !=NULL)
+ @param hook_arg argument which will be passed to pre-write and
+ in-write hooks of this record.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool translog_write_record(LSN *lsn,
+ enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info,
+ translog_size_t rec_len,
+ uint part_no,
+ LEX_CUSTRING *parts_data,
+ uchar *store_share_id,
+ void *hook_arg)
+{
+ struct st_translog_parts parts;
+ LEX_CUSTRING *part;
+ int rc;
+ uint short_trid= trn->short_id;
+ DBUG_ENTER("translog_write_record");
+ DBUG_PRINT("enter", ("type: %u (%s) ShortTrID: %u rec_len: %lu",
+ (uint) type, log_record_type_descriptor[type].name,
+ (uint) short_trid, (ulong) rec_len));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+ if (unlikely(translog_status != TRANSLOG_OK))
+ {
+ DBUG_PRINT("error", ("Transaction log is write protected"));
+ DBUG_RETURN(1);
+ }
+
+ if (tbl_info)
+ {
+ MARIA_SHARE *share= tbl_info->s;
+ DBUG_ASSERT(share->now_transactional);
+ if (unlikely(share->id == 0))
+ {
+ /*
+ First log write for this MARIA_SHARE; give it a short id.
+ When the lock manager is enabled and needs a short id, it should be
+ assigned in the lock manager (because row locks will be taken before
+ log records are written; for example SELECT FOR UPDATE takes locks but
+ writes no log record.
+ */
+ if (unlikely(translog_assign_id_to_share(tbl_info, trn)))
+ DBUG_RETURN(1);
+ }
+ fileid_store(store_share_id, share->id);
+ }
+ if (unlikely(!(trn->first_undo_lsn & TRANSACTION_LOGGED_LONG_ID)))
+ {
+ LSN dummy_lsn;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ uchar log_data[6];
+ int6store(log_data, trn->trid);
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ trn->first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID; /* no recursion */
+ if (unlikely(translog_write_record(&dummy_lsn, LOGREC_LONG_TRANSACTION_ID,
+ trn, NULL, sizeof(log_data),
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL)))
+ DBUG_RETURN(1);
+ }
+
+ parts.parts= parts_data;
+
+ /* count parts if they are not counted by upper level */
+ if (part_no == 0)
+ {
+ for (part_no= TRANSLOG_INTERNAL_PARTS;
+ parts_data[part_no].length != 0;
+ part_no++);
+ }
+ parts.elements= part_no;
+ parts.current= TRANSLOG_INTERNAL_PARTS;
+
+ /* clear TRANSLOG_INTERNAL_PARTS */
+ compile_time_assert(TRANSLOG_INTERNAL_PARTS != 0);
+ parts_data[0].str= 0;
+ parts_data[0].length= 0;
+
+ /* count length of the record */
+ if (rec_len == 0)
+ {
+ for(part= parts_data + TRANSLOG_INTERNAL_PARTS;\
+ part < parts_data + part_no;
+ part++)
+ {
+ rec_len+= (translog_size_t) part->length;
+ }
+ }
+ parts.record_length= rec_len;
+
+#ifndef DBUG_OFF
+ {
+ uint i;
+ uint len= 0;
+#ifdef HAVE_purify
+ ha_checksum checksum= 0;
+#endif
+ for (i= TRANSLOG_INTERNAL_PARTS; i < part_no; i++)
+ {
+#ifdef HAVE_purify
+ /* Find unitialized bytes early */
+ checksum+= my_checksum(checksum, parts_data[i].str,
+ parts_data[i].length);
+#endif
+ len+= parts_data[i].length;
+ }
+ DBUG_ASSERT(len == rec_len);
+ }
+#endif
+ /*
+ Start total_record_length from record_length then overhead will
+ be add
+ */
+ parts.total_record_length= parts.record_length;
+ DBUG_PRINT("info", ("record length: %lu", (ulong) parts.record_length));
+
+ /* process this parts */
+ if (!(rc= (log_record_type_descriptor[type].prewrite_hook &&
+ (*log_record_type_descriptor[type].prewrite_hook) (type, trn,
+ tbl_info,
+ hook_arg))))
+ {
+ switch (log_record_type_descriptor[type].rclass) {
+ case LOGRECTYPE_VARIABLE_LENGTH:
+ rc= translog_write_variable_record(lsn, type, tbl_info,
+ short_trid, &parts, trn, hook_arg);
+ break;
+ case LOGRECTYPE_PSEUDOFIXEDLENGTH:
+ case LOGRECTYPE_FIXEDLENGTH:
+ rc= translog_write_fixed_record(lsn, type, tbl_info,
+ short_trid, &parts, trn, hook_arg);
+ break;
+ case LOGRECTYPE_NOT_ALLOWED:
+ default:
+ DBUG_ASSERT(0);
+ rc= 1;
+ }
+ }
+
+ DBUG_PRINT("info", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(*lsn)));
+ DBUG_RETURN(rc);
+}
+
+
+/*
+ Decode compressed (relative) LSN(s)
+
+ SYNOPSIS
+ translog_relative_lsn_decode()
+ base_lsn LSN for encoding
+ src Decode LSN(s) from here
+ dst Put decoded LSNs here
+ lsns number of LSN(s)
+
+ RETURN
+ position in sources after decoded LSN(s)
+*/
+
+static uchar *translog_relative_LSN_decode(LSN base_lsn,
+ uchar *src, uchar *dst, uint lsns)
+{
+ uint i;
+ for (i= 0; i < lsns; i++, dst+= LSN_STORE_SIZE)
+ {
+ src= translog_get_LSN_from_diff(base_lsn, src, dst);
+ }
+ return src;
+}
+
+/**
+ @brief Get header of fixed/pseudo length record and call hook for
+ it processing
+
+ @param page Pointer to the buffer with page where LSN chunk is
+ placed
+ @param page_offset Offset of the first chunk in the page
+ @param buff Buffer to be filled with header data
+
+ @return Length of header or operation status
+ @retval # number of bytes in TRANSLOG_HEADER_BUFFER::header where
+ stored decoded part of the header
+*/
+
+static int translog_fixed_length_header(uchar *page,
+ translog_size_t page_offset,
+ TRANSLOG_HEADER_BUFFER *buff)
+{
+ struct st_log_record_type_descriptor *desc=
+ log_record_type_descriptor + buff->type;
+ uchar *src= page + page_offset + 3;
+ uchar *dst= buff->header;
+ uchar *start= src;
+ int lsns= desc->compressed_LSN;
+ uint length= desc->fixed_length;
+ DBUG_ENTER("translog_fixed_length_header");
+
+ buff->record_length= length;
+
+ if (desc->rclass == LOGRECTYPE_PSEUDOFIXEDLENGTH)
+ {
+ DBUG_ASSERT(lsns > 0);
+ src= translog_relative_LSN_decode(buff->lsn, src, dst, lsns);
+ lsns*= LSN_STORE_SIZE;
+ dst+= lsns;
+ length-= lsns;
+ buff->compressed_LSN_economy= (lsns - (int) (src - start));
+ }
+ else
+ buff->compressed_LSN_economy= 0;
+
+ memcpy(dst, src, length);
+ buff->non_header_data_start_offset= (uint16) (page_offset +
+ ((src + length) -
+ (page + page_offset)));
+ buff->non_header_data_len= 0;
+ DBUG_RETURN(buff->record_length);
+}
+
+
+/*
+ Free resources used by TRANSLOG_HEADER_BUFFER
+
+ SYNOPSIS
+ translog_free_record_header();
+*/
+
+void translog_free_record_header(TRANSLOG_HEADER_BUFFER *buff)
+{
+ DBUG_ENTER("translog_free_record_header");
+ if (buff->groups_no != 0)
+ {
+ my_free((uchar*) buff->groups, MYF(0));
+ buff->groups_no= 0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Returns the current horizon at the end of the current log
+
+ @return Horizon
+ @retval LSN_ERROR error
+ @retvar # Horizon
+*/
+
+TRANSLOG_ADDRESS translog_get_horizon()
+{
+ TRANSLOG_ADDRESS res;
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+ translog_lock();
+ res= log_descriptor.horizon;
+ translog_unlock();
+ return res;
+}
+
+
+/**
+ @brief Returns the current horizon at the end of the current log, caller is
+ assumed to already hold the lock
+
+ @return Horizon
+ @retval LSN_ERROR error
+ @retvar # Horizon
+*/
+
+TRANSLOG_ADDRESS translog_get_horizon_no_lock()
+{
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+ translog_lock_assert_owner();
+ return log_descriptor.horizon;
+}
+
+
+/*
+ Set last page in the scanner data structure
+
+ SYNOPSIS
+ translog_scanner_set_last_page()
+ scanner Information about current chunk during scanning
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_scanner_set_last_page(TRANSLOG_SCANNER_DATA *scanner)
+{
+ my_bool page_ok;
+ if (LSN_FILE_NO(scanner->page_addr) == LSN_FILE_NO(scanner->horizon))
+ {
+ /* It is last file => we can easy find last page address by horizon */
+ uint pagegrest= LSN_OFFSET(scanner->horizon) % TRANSLOG_PAGE_SIZE;
+ scanner->last_file_page= (scanner->horizon -
+ (pagegrest ? pagegrest : TRANSLOG_PAGE_SIZE));
+ return (0);
+ }
+ scanner->last_file_page= scanner->page_addr;
+ return (translog_get_last_page_addr(&scanner->last_file_page, &page_ok, 0));
+}
+
+
+/**
+ @brief Get page from page cache according to requested method
+
+ @param scanner The scanner data
+
+ @return operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool
+translog_scanner_get_page(TRANSLOG_SCANNER_DATA *scanner)
+{
+ TRANSLOG_VALIDATOR_DATA data;
+ DBUG_ENTER("translog_scanner_get_page");
+ data.addr= &scanner->page_addr;
+ data.was_recovered= 0;
+ DBUG_RETURN((scanner->page=
+ translog_get_page(&data, scanner->buffer,
+ (scanner->use_direct_link ?
+ &scanner->direct_link :
+ NULL))) ==
+ NULL);
+}
+
+
+/**
+ @brief Initialize reader scanner.
+
+ @param lsn LSN with which it have to be inited
+ @param fixed_horizon true if it is OK do not read records which was written
+ after scanning beginning
+ @param scanner scanner which have to be inited
+ @param use_direct prefer using direct lings from page handler
+ where it is possible.
+
+ @note If direct link was used translog_destroy_scanner should be
+ called after it using
+
+ @return status of the operation
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool translog_scanner_init(LSN lsn,
+ my_bool fixed_horizon,
+ TRANSLOG_SCANNER_DATA *scanner,
+ my_bool use_direct)
+{
+ TRANSLOG_VALIDATOR_DATA data;
+ DBUG_ENTER("translog_scanner_init");
+ DBUG_PRINT("enter", ("Scanner: 0x%lx LSN: (%lu,0x%lx)",
+ (ulong) scanner, LSN_IN_PARTS(lsn)));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ data.addr= &scanner->page_addr;
+ data.was_recovered= 0;
+
+ scanner->page_offset= LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE;
+
+ scanner->fixed_horizon= fixed_horizon;
+ scanner->use_direct_link= use_direct;
+ scanner->direct_link= NULL;
+
+ scanner->horizon= translog_get_horizon();
+ DBUG_PRINT("info", ("horizon: (%lu,0x%lx)", LSN_IN_PARTS(scanner->horizon)));
+
+ /* lsn < horizon */
+ DBUG_ASSERT(lsn <= scanner->horizon);
+
+ scanner->page_addr= lsn;
+ scanner->page_addr-= scanner->page_offset; /*decrease offset */
+
+ if (translog_scanner_set_last_page(scanner))
+ DBUG_RETURN(1);
+
+ if (translog_scanner_get_page(scanner))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Destroy scanner object;
+
+ @param scanner The scanner object to destroy
+*/
+
+void translog_destroy_scanner(TRANSLOG_SCANNER_DATA *scanner)
+{
+ DBUG_ENTER("translog_destroy_scanner");
+ DBUG_PRINT("enter", ("Scanner: 0x%lx", (ulong)scanner));
+ translog_free_link(scanner->direct_link);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Checks End of the Log
+
+ SYNOPSIS
+ translog_scanner_eol()
+ scanner Information about current chunk during scanning
+
+ RETURN
+ 1 End of the Log
+ 0 OK
+*/
+
+static my_bool translog_scanner_eol(TRANSLOG_SCANNER_DATA *scanner)
+{
+ DBUG_ENTER("translog_scanner_eol");
+ DBUG_PRINT("enter",
+ ("Horizon: (%lu, 0x%lx) Current: (%lu, 0x%lx+0x%x=0x%lx)",
+ LSN_IN_PARTS(scanner->horizon),
+ LSN_IN_PARTS(scanner->page_addr),
+ (uint) scanner->page_offset,
+ (ulong) (LSN_OFFSET(scanner->page_addr) + scanner->page_offset)));
+ if (scanner->horizon > (scanner->page_addr +
+ scanner->page_offset))
+ {
+ DBUG_PRINT("info", ("Horizon is not reached"));
+ DBUG_RETURN(0);
+ }
+ if (scanner->fixed_horizon)
+ {
+ DBUG_PRINT("info", ("Horizon is fixed and reached"));
+ DBUG_RETURN(1);
+ }
+ scanner->horizon= translog_get_horizon();
+ DBUG_PRINT("info",
+ ("Horizon is re-read, EOL: %d",
+ scanner->horizon <= (scanner->page_addr +
+ scanner->page_offset)));
+ DBUG_RETURN(scanner->horizon <= (scanner->page_addr +
+ scanner->page_offset));
+}
+
+
+/**
+ @brief Cheks End of the Page
+
+ @param scanner Information about current chunk during scanning
+
+ @retval 1 End of the Page
+ @retval 0 OK
+*/
+
+static my_bool translog_scanner_eop(TRANSLOG_SCANNER_DATA *scanner)
+{
+ DBUG_ENTER("translog_scanner_eop");
+ DBUG_RETURN(scanner->page_offset >= TRANSLOG_PAGE_SIZE ||
+ scanner->page[scanner->page_offset] == TRANSLOG_FILLER);
+}
+
+
+/**
+ @brief Checks End of the File (i.e. we are scanning last page, which do not
+ mean end of this page)
+
+ @param scanner Information about current chunk during scanning
+
+ @retval 1 End of the File
+ @retval 0 OK
+*/
+
+static my_bool translog_scanner_eof(TRANSLOG_SCANNER_DATA *scanner)
+{
+ DBUG_ENTER("translog_scanner_eof");
+ DBUG_ASSERT(LSN_FILE_NO(scanner->page_addr) ==
+ LSN_FILE_NO(scanner->last_file_page));
+ DBUG_PRINT("enter", ("curr Page: 0x%lx last page: 0x%lx "
+ "normal EOF: %d",
+ (ulong) LSN_OFFSET(scanner->page_addr),
+ (ulong) LSN_OFFSET(scanner->last_file_page),
+ LSN_OFFSET(scanner->page_addr) ==
+ LSN_OFFSET(scanner->last_file_page)));
+ /*
+ TODO: detect damaged file EOF,
+ TODO: issue warning if damaged file EOF detected
+ */
+ DBUG_RETURN(scanner->page_addr ==
+ scanner->last_file_page);
+}
+
+/*
+ Move scanner to the next chunk
+
+ SYNOPSIS
+ translog_get_next_chunk()
+ scanner Information about current chunk during scanning
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool
+translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner)
+{
+ uint16 len;
+ DBUG_ENTER("translog_get_next_chunk");
+
+ if (translog_scanner_eop(scanner))
+ len= TRANSLOG_PAGE_SIZE - scanner->page_offset;
+ else if ((len= translog_get_total_chunk_length(scanner->page,
+ scanner->page_offset)) == 0)
+ DBUG_RETURN(1);
+ scanner->page_offset+= len;
+
+ if (translog_scanner_eol(scanner))
+ {
+ scanner->page= END_OF_LOG;
+ scanner->page_offset= 0;
+ DBUG_RETURN(0);
+ }
+ if (translog_scanner_eop(scanner))
+ {
+ /* before reading next page we should unpin current one if it was pinned */
+ translog_free_link(scanner->direct_link);
+ if (translog_scanner_eof(scanner))
+ {
+ DBUG_PRINT("info", ("horizon: (%lu,0x%lx) pageaddr: (%lu,0x%lx)",
+ LSN_IN_PARTS(scanner->horizon),
+ LSN_IN_PARTS(scanner->page_addr)));
+ /* if it is log end it have to be caught before */
+ DBUG_ASSERT(LSN_FILE_NO(scanner->horizon) >
+ LSN_FILE_NO(scanner->page_addr));
+ scanner->page_addr+= LSN_ONE_FILE;
+ scanner->page_addr= LSN_REPLACE_OFFSET(scanner->page_addr,
+ TRANSLOG_PAGE_SIZE);
+ if (translog_scanner_set_last_page(scanner))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ scanner->page_addr+= TRANSLOG_PAGE_SIZE; /* offset increased */
+ }
+
+ if (translog_scanner_get_page(scanner))
+ DBUG_RETURN(1);
+
+ scanner->page_offset= translog_get_first_chunk_offset(scanner->page);
+ if (translog_scanner_eol(scanner))
+ {
+ scanner->page= END_OF_LOG;
+ scanner->page_offset= 0;
+ DBUG_RETURN(0);
+ }
+ DBUG_ASSERT(scanner->page[scanner->page_offset] != TRANSLOG_FILLER);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Get header of variable length record and call hook for it processing
+
+ @param page Pointer to the buffer with page where LSN chunk is
+ placed
+ @param page_offset Offset of the first chunk in the page
+ @param buff Buffer to be filled with header data
+ @param scanner If present should be moved to the header page if
+ it differ from LSN page
+
+ @return Length of header or operation status
+ @retval RECHEADER_READ_ERROR error
+ @retval RECHEADER_READ_EOF End of the log reached during the read
+ @retval # number of bytes in
+ TRANSLOG_HEADER_BUFFER::header where
+ stored decoded part of the header
+*/
+
+static int
+translog_variable_length_header(uchar *page, translog_size_t page_offset,
+ TRANSLOG_HEADER_BUFFER *buff,
+ TRANSLOG_SCANNER_DATA *scanner)
+{
+ struct st_log_record_type_descriptor *desc= (log_record_type_descriptor +
+ buff->type);
+ uchar *src= page + page_offset + 1 + 2;
+ uchar *dst= buff->header;
+ LSN base_lsn;
+ uint lsns= desc->compressed_LSN;
+ uint16 chunk_len;
+ uint16 length= desc->read_header_len;
+ uint16 buffer_length= length;
+ uint16 body_len;
+ int rc;
+ TRANSLOG_SCANNER_DATA internal_scanner;
+ DBUG_ENTER("translog_variable_length_header");
+
+ buff->record_length= translog_variable_record_1group_decode_len(&src);
+ chunk_len= uint2korr(src);
+ DBUG_PRINT("info", ("rec len: %lu chunk len: %u length: %u bufflen: %u",
+ (ulong) buff->record_length, (uint) chunk_len,
+ (uint) length, (uint) buffer_length));
+ if (chunk_len == 0)
+ {
+ uint16 page_rest;
+ DBUG_PRINT("info", ("1 group"));
+ src+= 2;
+ page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
+
+ base_lsn= buff->lsn;
+ body_len= min(page_rest, buff->record_length);
+ }
+ else
+ {
+ uint grp_no, curr;
+ uint header_to_skip;
+ uint16 page_rest;
+
+ DBUG_PRINT("info", ("multi-group"));
+ grp_no= buff->groups_no= uint2korr(src + 2);
+ if (!(buff->groups=
+ (TRANSLOG_GROUP*) my_malloc(sizeof(TRANSLOG_GROUP) * grp_no,
+ MYF(0))))
+ DBUG_RETURN(RECHEADER_READ_ERROR);
+ DBUG_PRINT("info", ("Groups: %u", (uint) grp_no));
+ src+= (2 + 2);
+ page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
+ curr= 0;
+ header_to_skip= src - (page + page_offset);
+ buff->chunk0_pages= 0;
+
+ for (;;)
+ {
+ uint i, read_length= grp_no;
+
+ buff->chunk0_pages++;
+ if (page_rest < grp_no * (7 + 1))
+ read_length= page_rest / (7 + 1);
+ DBUG_PRINT("info", ("Read chunk0 page#%u read: %u left: %u "
+ "start from: %u",
+ buff->chunk0_pages, read_length, grp_no, curr));
+ for (i= 0; i < read_length; i++, curr++)
+ {
+ DBUG_ASSERT(curr < buff->groups_no);
+ buff->groups[curr].addr= lsn_korr(src + i * (7 + 1));
+ buff->groups[curr].num= src[i * (7 + 1) + 7];
+ DBUG_PRINT("info", ("group #%u (%lu,0x%lx) chunks: %u",
+ curr,
+ LSN_IN_PARTS(buff->groups[curr].addr),
+ (uint) buff->groups[curr].num));
+ }
+ grp_no-= read_length;
+ if (grp_no == 0)
+ {
+ if (scanner)
+ {
+ buff->chunk0_data_addr= scanner->page_addr;
+ /* offset increased */
+ buff->chunk0_data_addr+= (page_offset + header_to_skip +
+ read_length * (7 + 1));
+ }
+ else
+ {
+ buff->chunk0_data_addr= buff->lsn;
+ /* offset increased */
+ buff->chunk0_data_addr+= (header_to_skip + read_length * (7 + 1));
+ }
+ buff->chunk0_data_len= chunk_len - 2 - read_length * (7 + 1);
+ DBUG_PRINT("info", ("Data address: (%lu,0x%lx) len: %u",
+ LSN_IN_PARTS(buff->chunk0_data_addr),
+ buff->chunk0_data_len));
+ break;
+ }
+ if (scanner == NULL)
+ {
+ DBUG_PRINT("info", ("use internal scanner for header reading"));
+ scanner= &internal_scanner;
+ if (translog_scanner_init(buff->lsn, 1, scanner, 0))
+ {
+ rc= RECHEADER_READ_ERROR;
+ goto exit_and_free;
+ }
+ }
+ if (translog_get_next_chunk(scanner))
+ {
+ if (scanner == &internal_scanner)
+ translog_destroy_scanner(scanner);
+ rc= RECHEADER_READ_ERROR;
+ goto exit_and_free;
+ }
+ if (scanner->page == END_OF_LOG)
+ {
+ if (scanner == &internal_scanner)
+ translog_destroy_scanner(scanner);
+ rc= RECHEADER_READ_EOF;
+ goto exit_and_free;
+ }
+ page= scanner->page;
+ page_offset= scanner->page_offset;
+ src= page + page_offset + header_to_skip;
+ chunk_len= uint2korr(src - 2 - 2);
+ DBUG_PRINT("info", ("Chunk len: %u", (uint) chunk_len));
+ page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
+ }
+
+ if (scanner == NULL)
+ {
+ DBUG_PRINT("info", ("use internal scanner"));
+ scanner= &internal_scanner;
+ }
+ else
+ {
+ translog_destroy_scanner(scanner);
+ }
+ base_lsn= buff->groups[0].addr;
+ translog_scanner_init(base_lsn, 1, scanner, scanner == &internal_scanner);
+ /* first group chunk is always chunk type 2 */
+ page= scanner->page;
+ page_offset= scanner->page_offset;
+ src= page + page_offset + 1;
+ page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
+ body_len= page_rest;
+ if (scanner == &internal_scanner)
+ translog_destroy_scanner(scanner);
+ }
+ if (lsns)
+ {
+ uchar *start= src;
+ src= translog_relative_LSN_decode(base_lsn, src, dst, lsns);
+ lsns*= LSN_STORE_SIZE;
+ dst+= lsns;
+ length-= lsns;
+ buff->record_length+= (buff->compressed_LSN_economy=
+ (int) (lsns - (src - start)));
+ DBUG_PRINT("info", ("lsns: %u length: %u economy: %d new length: %lu",
+ lsns / LSN_STORE_SIZE, (uint) length,
+ (int) buff->compressed_LSN_economy,
+ (ulong) buff->record_length));
+ body_len-= (uint16) (src - start);
+ }
+ else
+ buff->compressed_LSN_economy= 0;
+
+ DBUG_ASSERT(body_len >= length);
+ body_len-= length;
+ memcpy(dst, src, length);
+ buff->non_header_data_start_offset= (uint16) (src + length - page);
+ buff->non_header_data_len= body_len;
+ DBUG_PRINT("info", ("non_header_data_start_offset: %u len: %u buffer: %u",
+ buff->non_header_data_start_offset,
+ buff->non_header_data_len, buffer_length));
+ DBUG_RETURN(buffer_length);
+
+exit_and_free:
+ my_free(buff->groups, MYF(0));
+ buff->groups_no= 0; /* prevent try to use of buff->groups */
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief Read record header from the given buffer
+
+ @param page page content buffer
+ @param page_offset offset of the chunk in the page
+ @param buff destination buffer
+ @param scanner If this is set the scanner will be moved to the
+ record header page (differ from LSN page in case of
+ multi-group records)
+
+ @return Length of header or operation status
+ @retval RECHEADER_READ_ERROR error
+ @retval # number of bytes in
+ TRANSLOG_HEADER_BUFFER::header where
+ stored decoded part of the header
+*/
+
+int translog_read_record_header_from_buffer(uchar *page,
+ uint16 page_offset,
+ TRANSLOG_HEADER_BUFFER *buff,
+ TRANSLOG_SCANNER_DATA *scanner)
+{
+ translog_size_t res;
+ DBUG_ENTER("translog_read_record_header_from_buffer");
+ DBUG_ASSERT(translog_is_LSN_chunk(page[page_offset]));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+ DBUG_PRINT("info", ("page byte: 0x%x offset: %u",
+ (uint) page[page_offset], (uint) page_offset));
+ buff->type= (page[page_offset] & TRANSLOG_REC_TYPE);
+ buff->short_trid= uint2korr(page + page_offset + 1);
+ DBUG_PRINT("info", ("Type %u, Short TrID %u, LSN (%lu,0x%lx)",
+ (uint) buff->type, (uint)buff->short_trid,
+ LSN_IN_PARTS(buff->lsn)));
+ /* Read required bytes from the header and call hook */
+ switch (log_record_type_descriptor[buff->type].rclass) {
+ case LOGRECTYPE_VARIABLE_LENGTH:
+ res= translog_variable_length_header(page, page_offset, buff,
+ scanner);
+ break;
+ case LOGRECTYPE_PSEUDOFIXEDLENGTH:
+ case LOGRECTYPE_FIXEDLENGTH:
+ res= translog_fixed_length_header(page, page_offset, buff);
+ break;
+ default:
+ DBUG_ASSERT(0); /* we read some junk (got no LSN) */
+ res= RECHEADER_READ_ERROR;
+ }
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Read record header and some fixed part of a record (the part depend
+ on record type).
+
+ @param lsn log record serial number (address of the record)
+ @param buff log record header buffer
+
+ @note Some type of record can be read completely by this call
+ @note "Decoded" header stored in TRANSLOG_HEADER_BUFFER::header (relative
+ LSN can be translated to absolute one), some fields can be added (like
+ actual header length in the record if the header has variable length)
+
+ @return Length of header or operation status
+ @retval RECHEADER_READ_ERROR error
+ @retval # number of bytes in
+ TRANSLOG_HEADER_BUFFER::header where
+ stored decoded part of the header
+*/
+
+int translog_read_record_header(LSN lsn, TRANSLOG_HEADER_BUFFER *buff)
+{
+ TRANSLOG_PAGE_SIZE_BUFF psize_buff;
+ uchar *page;
+ translog_size_t res, page_offset= LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE;
+ PAGECACHE_BLOCK_LINK *direct_link;
+ TRANSLOG_ADDRESS addr;
+ TRANSLOG_VALIDATOR_DATA data;
+ DBUG_ENTER("translog_read_record_header");
+ DBUG_PRINT("enter", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
+ DBUG_ASSERT(LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE != 0);
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ buff->lsn= lsn;
+ buff->groups_no= 0;
+ data.addr= &addr;
+ data.was_recovered= 0;
+ addr= lsn;
+ addr-= page_offset; /* offset decreasing */
+ res= (!(page= translog_get_page(&data, psize_buff.buffer, &direct_link))) ?
+ RECHEADER_READ_ERROR :
+ translog_read_record_header_from_buffer(page, page_offset, buff, 0);
+ translog_free_link(direct_link);
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Read record header and some fixed part of a record (the part depend
+ on record type).
+
+ @param scan scanner position to read
+ @param buff log record header buffer
+ @param move_scanner request to move scanner to the header position
+
+ @note Some type of record can be read completely by this call
+ @note "Decoded" header stored in TRANSLOG_HEADER_BUFFER::header (relative
+ LSN can be translated to absolute one), some fields can be added (like
+ actual header length in the record if the header has variable length)
+
+ @return Length of header or operation status
+ @retval RECHEADER_READ_ERROR error
+ @retval # number of bytes in
+ TRANSLOG_HEADER_BUFFER::header where stored
+ decoded part of the header
+*/
+
+int translog_read_record_header_scan(TRANSLOG_SCANNER_DATA *scanner,
+ TRANSLOG_HEADER_BUFFER *buff,
+ my_bool move_scanner)
+{
+ translog_size_t res;
+ DBUG_ENTER("translog_read_record_header_scan");
+ DBUG_PRINT("enter", ("Scanner: Cur: (%lu,0x%lx) Hrz: (%lu,0x%lx) "
+ "Lst: (%lu,0x%lx) Offset: %u(%x) fixed %d",
+ LSN_IN_PARTS(scanner->page_addr),
+ LSN_IN_PARTS(scanner->horizon),
+ LSN_IN_PARTS(scanner->last_file_page),
+ (uint) scanner->page_offset,
+ (uint) scanner->page_offset, scanner->fixed_horizon));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+ buff->groups_no= 0;
+ buff->lsn= scanner->page_addr;
+ buff->lsn+= scanner->page_offset; /* offset increasing */
+ res= translog_read_record_header_from_buffer(scanner->page,
+ scanner->page_offset,
+ buff,
+ (move_scanner ?
+ scanner : 0));
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Read record header and some fixed part of the next record (the part
+ depend on record type).
+
+ @param scanner data for scanning if lsn is NULL scanner data
+ will be used for continue scanning.
+ The scanner can be NULL.
+
+ @param buff log record header buffer
+
+ @return Length of header or operation status
+ @retval RECHEADER_READ_ERROR error
+ @retval RECHEADER_READ_EOF EOF
+ @retval # number of bytes in
+ TRANSLOG_HEADER_BUFFER::header where
+ stored decoded part of the header
+*/
+
+int translog_read_next_record_header(TRANSLOG_SCANNER_DATA *scanner,
+ TRANSLOG_HEADER_BUFFER *buff)
+{
+ translog_size_t res;
+
+ DBUG_ENTER("translog_read_next_record_header");
+ buff->groups_no= 0; /* to be sure that we will free it right */
+ DBUG_PRINT("enter", ("scanner: 0x%lx", (ulong) scanner));
+ DBUG_PRINT("info", ("Scanner: Cur: (%lu,0x%lx) Hrz: (%lu,0x%lx) "
+ "Lst: (%lu,0x%lx) Offset: %u(%x) fixed: %d",
+ LSN_IN_PARTS(scanner->page_addr),
+ LSN_IN_PARTS(scanner->horizon),
+ LSN_IN_PARTS(scanner->last_file_page),
+ (uint) scanner->page_offset,
+ (uint) scanner->page_offset, scanner->fixed_horizon));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ do
+ {
+ if (translog_get_next_chunk(scanner))
+ DBUG_RETURN(RECHEADER_READ_ERROR);
+ if (scanner->page == END_OF_LOG)
+ {
+ DBUG_PRINT("info", ("End of file from the scanner"));
+ /* Last record was read */
+ buff->lsn= LSN_IMPOSSIBLE;
+ DBUG_RETURN(RECHEADER_READ_EOF);
+ }
+ DBUG_PRINT("info", ("Page: (%lu,0x%lx) offset: %lu byte: %x",
+ LSN_IN_PARTS(scanner->page_addr),
+ (ulong) scanner->page_offset,
+ (uint) scanner->page[scanner->page_offset]));
+ } while (!translog_is_LSN_chunk(scanner->page[scanner->page_offset]) &&
+ scanner->page[scanner->page_offset] != TRANSLOG_FILLER);
+
+ if (scanner->page[scanner->page_offset] == TRANSLOG_FILLER)
+ {
+ DBUG_PRINT("info", ("End of file"));
+ /* Last record was read */
+ buff->lsn= LSN_IMPOSSIBLE;
+ /* Return 'end of log' marker */
+ res= RECHEADER_READ_EOF;
+ }
+ else
+ res= translog_read_record_header_scan(scanner, buff, 0);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Moves record data reader to the next chunk and fill the data reader
+ information about that chunk.
+
+ SYNOPSIS
+ translog_record_read_next_chunk()
+ data data cursor
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_record_read_next_chunk(TRANSLOG_READER_DATA *data)
+{
+ translog_size_t new_current_offset= data->current_offset + data->chunk_size;
+ uint16 chunk_header_len, chunk_len;
+ uint8 type;
+ DBUG_ENTER("translog_record_read_next_chunk");
+
+ if (data->eor)
+ {
+ DBUG_PRINT("info", ("end of the record flag set"));
+ DBUG_RETURN(1);
+ }
+
+ if (data->header.groups_no &&
+ data->header.groups_no - 1 != data->current_group &&
+ data->header.groups[data->current_group].num == data->current_chunk)
+ {
+ /* Goto next group */
+ data->current_group++;
+ data->current_chunk= 0;
+ DBUG_PRINT("info", ("skip to group: #%u", data->current_group));
+ translog_destroy_scanner(&data->scanner);
+ translog_scanner_init(data->header.groups[data->current_group].addr,
+ 1, &data->scanner, 1);
+ }
+ else
+ {
+ data->current_chunk++;
+ if (translog_get_next_chunk(&data->scanner))
+ DBUG_RETURN(1);
+ if (data->scanner.page == END_OF_LOG)
+ {
+ /*
+ Actually it should not happened, but we want to quit nicely in case
+ of a truncated log
+ */
+ DBUG_RETURN(1);
+ }
+ }
+ type= data->scanner.page[data->scanner.page_offset] & TRANSLOG_CHUNK_TYPE;
+
+ if (type == TRANSLOG_CHUNK_LSN && data->header.groups_no)
+ {
+ DBUG_PRINT("info",
+ ("Last chunk: data len: %u offset: %u group: %u of %u",
+ data->header.chunk0_data_len, data->scanner.page_offset,
+ data->current_group, data->header.groups_no - 1));
+ DBUG_ASSERT(data->header.groups_no - 1 == data->current_group);
+ DBUG_ASSERT(data->header.lsn ==
+ data->scanner.page_addr + data->scanner.page_offset);
+ translog_destroy_scanner(&data->scanner);
+ translog_scanner_init(data->header.chunk0_data_addr, 1, &data->scanner, 1);
+ data->chunk_size= data->header.chunk0_data_len;
+ data->body_offset= data->scanner.page_offset;
+ data->current_offset= new_current_offset;
+ data->eor= 1;
+ DBUG_RETURN(0);
+ }
+
+ if (type == TRANSLOG_CHUNK_LSN || type == TRANSLOG_CHUNK_FIXED)
+ {
+ data->eor= 1;
+ DBUG_RETURN(1); /* End of record */
+ }
+
+ chunk_header_len=
+ translog_get_chunk_header_length(data->scanner.page +
+ data->scanner.page_offset);
+ chunk_len= translog_get_total_chunk_length(data->scanner.page,
+ data->scanner.page_offset);
+ data->chunk_size= chunk_len - chunk_header_len;
+ data->body_offset= data->scanner.page_offset + chunk_header_len;
+ data->current_offset= new_current_offset;
+ DBUG_PRINT("info", ("grp: %u chunk: %u body_offset: %u chunk_size: %u "
+ "current_offset: %lu",
+ (uint) data->current_group,
+ (uint) data->current_chunk,
+ (uint) data->body_offset,
+ (uint) data->chunk_size, (ulong) data->current_offset));
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Initialize record reader data from LSN
+
+ SYNOPSIS
+ translog_init_reader_data()
+ lsn reference to LSN we should start from
+ data reader data to initialize
+
+ RETURN
+ 0 OK
+ 1 Error
+*/
+
+static my_bool translog_init_reader_data(LSN lsn,
+ TRANSLOG_READER_DATA *data)
+{
+ int read_header;
+ DBUG_ENTER("translog_init_reader_data");
+ if (translog_scanner_init(lsn, 1, &data->scanner, 1) ||
+ ((read_header=
+ translog_read_record_header_scan(&data->scanner, &data->header, 1))
+ == RECHEADER_READ_ERROR))
+ DBUG_RETURN(1);
+ data->read_header= read_header;
+ data->body_offset= data->header.non_header_data_start_offset;
+ data->chunk_size= data->header.non_header_data_len;
+ data->current_offset= data->read_header;
+ data->current_group= 0;
+ data->current_chunk= 0;
+ data->eor= 0;
+ DBUG_PRINT("info", ("read_header: %u "
+ "body_offset: %u chunk_size: %u current_offset: %lu",
+ (uint) data->read_header,
+ (uint) data->body_offset,
+ (uint) data->chunk_size, (ulong) data->current_offset));
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Destroy reader data object
+*/
+
+static void translog_destroy_reader_data(TRANSLOG_READER_DATA *data)
+{
+ translog_destroy_scanner(&data->scanner);
+ translog_free_record_header(&data->header);
+}
+
+
+/*
+ Read a part of the record.
+
+ SYNOPSIS
+ translog_read_record_header()
+ lsn log record serial number (address of the record)
+ offset From the beginning of the record beginning (read
+ by translog_read_record_header).
+ length Length of record part which have to be read.
+ buffer Buffer where to read the record part (have to be at
+ least 'length' bytes length)
+
+ RETURN
+ length of data actually read
+*/
+
+translog_size_t translog_read_record(LSN lsn,
+ translog_size_t offset,
+ translog_size_t length,
+ uchar *buffer,
+ TRANSLOG_READER_DATA *data)
+{
+ translog_size_t requested_length= length;
+ translog_size_t end= offset + length;
+ TRANSLOG_READER_DATA internal_data;
+ DBUG_ENTER("translog_read_record");
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ if (data == NULL)
+ {
+ DBUG_ASSERT(lsn != LSN_IMPOSSIBLE);
+ data= &internal_data;
+ }
+ if (lsn ||
+ (offset < data->current_offset &&
+ !(offset < data->read_header && offset + length < data->read_header)))
+ {
+ if (translog_init_reader_data(lsn, data))
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("info", ("Offset: %lu length: %lu "
+ "Scanner: Cur: (%lu,0x%lx) Hrz: (%lu,0x%lx) "
+ "Lst: (%lu,0x%lx) Offset: %u(%x) fixed: %d",
+ (ulong) offset, (ulong) length,
+ LSN_IN_PARTS(data->scanner.page_addr),
+ LSN_IN_PARTS(data->scanner.horizon),
+ LSN_IN_PARTS(data->scanner.last_file_page),
+ (uint) data->scanner.page_offset,
+ (uint) data->scanner.page_offset,
+ data->scanner.fixed_horizon));
+ if (offset < data->read_header)
+ {
+ uint16 len= min(data->read_header, end) - offset;
+ DBUG_PRINT("info",
+ ("enter header offset: %lu length: %lu",
+ (ulong) offset, (ulong) length));
+ memcpy(buffer, data->header.header + offset, len);
+ length-= len;
+ if (length == 0)
+ {
+ translog_destroy_reader_data(data);
+ DBUG_RETURN(requested_length);
+ }
+ offset+= len;
+ buffer+= len;
+ DBUG_PRINT("info",
+ ("len: %u offset: %lu curr: %lu length: %lu",
+ len, (ulong) offset, (ulong) data->current_offset,
+ (ulong) length));
+ }
+ /* TODO: find first page which we should read by offset */
+
+ /* read the record chunk by chunk */
+ for(;;)
+ {
+ uint page_end= data->current_offset + data->chunk_size;
+ DBUG_PRINT("info",
+ ("enter body offset: %lu curr: %lu "
+ "length: %lu page_end: %lu",
+ (ulong) offset, (ulong) data->current_offset, (ulong) length,
+ (ulong) page_end));
+ if (offset < page_end)
+ {
+ uint len= page_end - offset;
+ set_if_smaller(len, length); /* in case we read beyond record's end */
+ DBUG_ASSERT(offset >= data->current_offset);
+ memcpy(buffer,
+ data->scanner.page + data->body_offset +
+ (offset - data->current_offset), len);
+ length-= len;
+ if (length == 0)
+ {
+ translog_destroy_reader_data(data);
+ DBUG_RETURN(requested_length);
+ }
+ offset+= len;
+ buffer+= len;
+ DBUG_PRINT("info",
+ ("len: %u offset: %lu curr: %lu length: %lu",
+ len, (ulong) offset, (ulong) data->current_offset,
+ (ulong) length));
+ }
+ if (translog_record_read_next_chunk(data))
+ {
+ translog_destroy_reader_data(data);
+ DBUG_RETURN(requested_length - length);
+ }
+ }
+}
+
+
+/*
+ @brief Force skipping to the next buffer
+
+ @todo Do not copy old page content if all page protections are switched off
+ (because we do not need calculate something or change old parts of the page)
+*/
+
+static void translog_force_current_buffer_to_finish()
+{
+ TRANSLOG_ADDRESS new_buff_beginning;
+ uint16 old_buffer_no= log_descriptor.bc.buffer_no;
+ uint16 new_buffer_no= (old_buffer_no + 1) % TRANSLOG_BUFFERS_NO;
+ struct st_translog_buffer *new_buffer= (log_descriptor.buffers +
+ new_buffer_no);
+ struct st_translog_buffer *old_buffer= log_descriptor.bc.buffer;
+ uchar *data= log_descriptor.bc.ptr - log_descriptor.bc.current_page_fill;
+ uint16 left= TRANSLOG_PAGE_SIZE - log_descriptor.bc.current_page_fill;
+ uint16 current_page_fill, write_counter, previous_offset;
+ DBUG_ENTER("translog_force_current_buffer_to_finish");
+ DBUG_PRINT("enter", ("Buffer #%u 0x%lx "
+ "Buffer addr: (%lu,0x%lx) "
+ "Page addr: (%lu,0x%lx) "
+ "size: %lu (%lu) Pg: %u left: %u in progress %u",
+ (uint) log_descriptor.bc.buffer_no,
+ (ulong) log_descriptor.bc.buffer,
+ LSN_IN_PARTS(log_descriptor.bc.buffer->offset),
+ (ulong) LSN_FILE_NO(log_descriptor.horizon),
+ (ulong) (LSN_OFFSET(log_descriptor.horizon) -
+ log_descriptor.bc.current_page_fill),
+ (ulong) log_descriptor.bc.buffer->size,
+ (ulong) (log_descriptor.bc.ptr -log_descriptor.bc.
+ buffer->buffer),
+ (uint) log_descriptor.bc.current_page_fill,
+ (uint) left,
+ (uint) log_descriptor.bc.buffer->
+ copy_to_buffer_in_progress));
+ translog_lock_assert_owner();
+ LINT_INIT(current_page_fill);
+ new_buff_beginning= log_descriptor.bc.buffer->offset;
+ new_buff_beginning+= log_descriptor.bc.buffer->size; /* increase offset */
+
+ DBUG_ASSERT(log_descriptor.bc.ptr !=NULL);
+ DBUG_ASSERT(LSN_FILE_NO(log_descriptor.horizon) ==
+ LSN_FILE_NO(log_descriptor.bc.buffer->offset));
+ translog_check_cursor(&log_descriptor.bc);
+ DBUG_ASSERT(left < TRANSLOG_PAGE_SIZE);
+ if (left)
+ {
+ /*
+ TODO: if 'left' is so small that can't hold any other record
+ then do not move the page
+ */
+ DBUG_PRINT("info", ("left: %u", (uint) left));
+
+ /* decrease offset */
+ new_buff_beginning-= log_descriptor.bc.current_page_fill;
+ current_page_fill= log_descriptor.bc.current_page_fill;
+
+ memset(log_descriptor.bc.ptr, TRANSLOG_FILLER, left);
+ log_descriptor.bc.buffer->size+= left;
+ DBUG_PRINT("info", ("Finish Page buffer #%u: 0x%lx "
+ "Size: %lu",
+ (uint) log_descriptor.bc.buffer->buffer_no,
+ (ulong) log_descriptor.bc.buffer,
+ (ulong) log_descriptor.bc.buffer->size));
+ DBUG_ASSERT(log_descriptor.bc.buffer->buffer_no ==
+ log_descriptor.bc.buffer_no);
+ }
+ else
+ {
+ log_descriptor.bc.current_page_fill= 0;
+ }
+
+ translog_buffer_lock(new_buffer);
+#ifndef DBUG_OFF
+ {
+ TRANSLOG_ADDRESS offset= new_buffer->offset;
+ TRANSLOG_FILE *file= new_buffer->file;
+ uint8 ver= new_buffer->ver;
+ translog_lock_assert_owner();
+#endif
+ translog_wait_for_buffer_free(new_buffer);
+#ifndef DBUG_OFF
+ /* We keep the handler locked so nobody can start this new buffer */
+ DBUG_ASSERT(offset == new_buffer->offset && new_buffer->file == NULL &&
+ (file == NULL ? ver : (uint8)(ver + 1)) == new_buffer->ver);
+ }
+#endif
+
+ write_counter= log_descriptor.bc.write_counter;
+ previous_offset= log_descriptor.bc.previous_offset;
+ translog_start_buffer(new_buffer, &log_descriptor.bc, new_buffer_no);
+ /* Fix buffer offset (which was incorrectly set to horizon) */
+ log_descriptor.bc.buffer->offset= new_buff_beginning;
+ log_descriptor.bc.write_counter= write_counter;
+ log_descriptor.bc.previous_offset= previous_offset;
+ new_buffer->prev_last_lsn= BUFFER_MAX_LSN(old_buffer);
+ DBUG_PRINT("info", ("prev_last_lsn set to (%lu,0x%lx) buffer: 0x%lx",
+ LSN_IN_PARTS(new_buffer->prev_last_lsn),
+ (ulong) new_buffer));
+
+ /*
+ Advances this log pointer, increases writers and let other threads to
+ write to the log while we process old page content
+ */
+ if (left)
+ {
+ log_descriptor.bc.ptr+= current_page_fill;
+ log_descriptor.bc.buffer->size= log_descriptor.bc.current_page_fill=
+ current_page_fill;
+ new_buffer->overlay= 1;
+ }
+ else
+ translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
+ translog_buffer_increase_writers(new_buffer);
+ translog_buffer_unlock(new_buffer);
+
+ /*
+ We have to wait until all writers finish before start changing the
+ pages by applying protection and copying the page content in the
+ new buffer.
+ */
+#ifndef DBUG_OFF
+ {
+ TRANSLOG_ADDRESS offset= old_buffer->offset;
+ TRANSLOG_FILE *file= old_buffer->file;
+ uint8 ver= old_buffer->ver;
+#endif
+ /*
+ Now only one thread can flush log (buffer can flush many threads but
+ log flush log flush where this function is used can do only one thread)
+ so no other thread can set is_closing_buffer.
+ */
+ DBUG_ASSERT(!old_buffer->is_closing_buffer);
+ old_buffer->is_closing_buffer= 1; /* Other flushes will wait */
+ DBUG_PRINT("enter", ("Buffer #%u 0x%lx is_closing_buffer set",
+ (uint) old_buffer->buffer_no, (ulong) old_buffer));
+ translog_wait_for_writers(old_buffer);
+#ifndef DBUG_OFF
+ /* We blocked flushing this buffer so the buffer should not changed */
+ DBUG_ASSERT(offset == old_buffer->offset && file == old_buffer->file &&
+ ver == old_buffer->ver);
+ }
+#endif
+
+ if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
+ {
+ translog_put_sector_protection(data, &log_descriptor.bc);
+ if (left)
+ {
+ log_descriptor.bc.write_counter++;
+ log_descriptor.bc.previous_offset= current_page_fill;
+ }
+ else
+ {
+ DBUG_PRINT("info", ("drop write_counter"));
+ log_descriptor.bc.write_counter= 0;
+ log_descriptor.bc.previous_offset= 0;
+ }
+ }
+
+ if (log_descriptor.flags & TRANSLOG_PAGE_CRC)
+ {
+ uint32 crc= translog_crc(data + log_descriptor.page_overhead,
+ TRANSLOG_PAGE_SIZE -
+ log_descriptor.page_overhead);
+ DBUG_PRINT("info", ("CRC: 0x%lx", (ulong) crc));
+ int4store(data + 3 + 3 + 1, crc);
+ }
+ old_buffer->is_closing_buffer= 0;
+ DBUG_PRINT("enter", ("Buffer #%u 0x%lx is_closing_buffer cleared",
+ (uint) old_buffer->buffer_no, (ulong) old_buffer));
+ pthread_cond_broadcast(&old_buffer->waiting_filling_buffer);
+
+ if (left)
+ {
+ /*
+ TODO: do not copy beginning of the page if we have no CRC or sector
+ checks on
+ */
+ memcpy(new_buffer->buffer, data, current_page_fill);
+ }
+ old_buffer->next_buffer_offset= new_buffer->offset;
+ translog_buffer_lock(new_buffer);
+ new_buffer->prev_buffer_offset= old_buffer->offset;
+ translog_buffer_decrease_writers(new_buffer);
+ translog_buffer_unlock(new_buffer);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Waits while given lsn will be flushed
+
+ @param lsn log record serial number up to which (inclusive)
+ the log has to be flushed
+*/
+
+void translog_flush_wait_for_end(LSN lsn)
+{
+ DBUG_ENTER("translog_flush_wait_for_end");
+ DBUG_PRINT("enter", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
+ safe_mutex_assert_owner(&log_descriptor.log_flush_lock);
+ while (cmp_translog_addr(log_descriptor.flushed, lsn) < 0)
+ pthread_cond_wait(&log_descriptor.log_flush_cond,
+ &log_descriptor.log_flush_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Sets goal for the next flush pass and waits for this pass end.
+
+ @param lsn log record serial number up to which (inclusive)
+ the log has to be flushed
+*/
+
+void translog_flush_set_new_goal_and_wait(TRANSLOG_ADDRESS lsn)
+{
+ DBUG_ENTER("translog_flush_set_new_goal_and_wait");
+ DBUG_PRINT("enter", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
+ safe_mutex_assert_owner(&log_descriptor.log_flush_lock);
+ if (cmp_translog_addr(lsn, log_descriptor.next_pass_max_lsn) > 0)
+ {
+ log_descriptor.next_pass_max_lsn= lsn;
+ log_descriptor.max_lsn_requester= pthread_self();
+ }
+ while (log_descriptor.flush_in_progress)
+ {
+ pthread_cond_wait(&log_descriptor.log_flush_cond,
+ &log_descriptor.log_flush_lock);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Flush the log up to given LSN (included)
+
+ @param lsn log record serial number up to which (inclusive)
+ the log has to be flushed
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+
+*/
+
+my_bool translog_flush(TRANSLOG_ADDRESS lsn)
+{
+ LSN sent_to_disk= LSN_IMPOSSIBLE;
+ TRANSLOG_ADDRESS flush_horizon;
+ uint fn, i;
+ dirty_buffer_mask_t dirty_buffer_mask;
+ uint8 last_buffer_no, start_buffer_no;
+ my_bool rc= 0;
+ DBUG_ENTER("translog_flush");
+ DBUG_PRINT("enter", ("Flush up to LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+ LINT_INIT(sent_to_disk);
+
+ pthread_mutex_lock(&log_descriptor.log_flush_lock);
+ DBUG_PRINT("info", ("Everything is flushed up to (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.flushed)));
+ if (cmp_translog_addr(log_descriptor.flushed, lsn) >= 0)
+ {
+ pthread_mutex_unlock(&log_descriptor.log_flush_lock);
+ DBUG_RETURN(0);
+ }
+ if (log_descriptor.flush_in_progress)
+ {
+ translog_flush_set_new_goal_and_wait(lsn);
+ if (!pthread_equal(log_descriptor.max_lsn_requester, pthread_self()))
+ {
+ /* fix lsn if it was horizon */
+ if (cmp_translog_addr(lsn, log_descriptor.bc.buffer->last_lsn) > 0)
+ lsn= BUFFER_MAX_LSN(log_descriptor.bc.buffer);
+ translog_flush_wait_for_end(lsn);
+ pthread_mutex_unlock(&log_descriptor.log_flush_lock);
+ DBUG_RETURN(0);
+ }
+ log_descriptor.next_pass_max_lsn= LSN_IMPOSSIBLE;
+ }
+ log_descriptor.flush_in_progress= 1;
+ flush_horizon= log_descriptor.previous_flush_horizon;
+ DBUG_PRINT("info", ("flush_in_progress is set"));
+ pthread_mutex_unlock(&log_descriptor.log_flush_lock);
+
+ translog_lock();
+ if (log_descriptor.is_everything_flushed)
+ {
+ DBUG_PRINT("info", ("everything is flushed"));
+ rc= (translog_status == TRANSLOG_READONLY);
+ translog_unlock();
+ goto out;
+ }
+
+ /*
+ We will recheck information when will lock buffers one by
+ one so we can use unprotected read here (this is just for
+ speed up buffers processing)
+ */
+ dirty_buffer_mask= log_descriptor.dirty_buffer_mask;
+ DBUG_PRINT("info", ("Dirty buffer mask: %lx current buffer: %u",
+ (ulong) dirty_buffer_mask,
+ (uint) log_descriptor.bc.buffer_no));
+ for (i= (log_descriptor.bc.buffer_no + 1) % TRANSLOG_BUFFERS_NO;
+ i != log_descriptor.bc.buffer_no && !(dirty_buffer_mask & (1 << i));
+ i= (i + 1) % TRANSLOG_BUFFERS_NO) {}
+ start_buffer_no= i;
+
+ DBUG_PRINT("info",
+ ("start from: %u current: %u prev last lsn: (%lu,0x%lx)",
+ (uint) start_buffer_no, (uint) log_descriptor.bc.buffer_no,
+ LSN_IN_PARTS(log_descriptor.bc.buffer->prev_last_lsn)));
+
+
+ /*
+ if LSN up to which we have to flush bigger then maximum LSN of previous
+ buffer and at least one LSN was saved in the current buffer (last_lsn !=
+ LSN_IMPOSSIBLE) then we better finish the current buffer.
+ */
+ if (cmp_translog_addr(lsn, log_descriptor.bc.buffer->prev_last_lsn) > 0 &&
+ log_descriptor.bc.buffer->last_lsn != LSN_IMPOSSIBLE)
+ {
+ struct st_translog_buffer *buffer= log_descriptor.bc.buffer;
+ lsn= log_descriptor.bc.buffer->last_lsn; /* fix lsn if it was horizon */
+ DBUG_PRINT("info", ("LSN to flush fixed to last lsn: (%lu,0x%lx)",
+ LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn)));
+ last_buffer_no= log_descriptor.bc.buffer_no;
+ log_descriptor.is_everything_flushed= 1;
+ translog_force_current_buffer_to_finish();
+ translog_buffer_unlock(buffer);
+ }
+ else
+ {
+ last_buffer_no= ((log_descriptor.bc.buffer_no + TRANSLOG_BUFFERS_NO -1) %
+ TRANSLOG_BUFFERS_NO);
+ translog_unlock();
+ }
+ sent_to_disk= translog_get_sent_to_disk();
+ if (cmp_translog_addr(lsn, sent_to_disk) > 0)
+ {
+
+ DBUG_PRINT("info", ("Start buffer #: %u last buffer #: %u",
+ (uint) start_buffer_no, (uint) last_buffer_no));
+ last_buffer_no= (last_buffer_no + 1) % TRANSLOG_BUFFERS_NO;
+ i= start_buffer_no;
+ do
+ {
+ struct st_translog_buffer *buffer= log_descriptor.buffers + i;
+ translog_buffer_lock(buffer);
+ DBUG_PRINT("info", ("Check buffer: 0x%lx #: %u "
+ "prev last LSN: (%lu,0x%lx) "
+ "last LSN: (%lu,0x%lx) status: %s",
+ (ulong)(buffer),
+ (uint) i,
+ LSN_IN_PARTS(buffer->prev_last_lsn),
+ LSN_IN_PARTS(buffer->last_lsn),
+ (buffer->file ?
+ "dirty" : "closed")));
+ if (buffer->prev_last_lsn <= lsn &&
+ buffer->file != NULL)
+ {
+ DBUG_ASSERT(flush_horizon <= buffer->offset + buffer->size);
+ flush_horizon= buffer->offset + buffer->size;
+ translog_buffer_flush(buffer);
+ }
+ translog_buffer_unlock(buffer);
+ i= (i + 1) % TRANSLOG_BUFFERS_NO;
+ } while (i != last_buffer_no);
+ sent_to_disk= translog_get_sent_to_disk();
+ }
+
+ /* sync files from previous flush till current one */
+ for (fn= LSN_FILE_NO(log_descriptor.flushed); fn <= LSN_FILE_NO(lsn); fn++)
+ {
+ TRANSLOG_FILE *file= get_logfile_by_number(fn);
+ DBUG_ASSERT(file != NULL);
+ if (!file->is_sync)
+ {
+ if (my_sync(file->handler.file, MYF(MY_WME)))
+ {
+ rc= 1;
+ translog_stop_writing();
+ sent_to_disk= LSN_IMPOSSIBLE;
+ goto out;
+ }
+ file->is_sync= 1;
+ }
+ }
+
+ if (sync_log_dir >= TRANSLOG_SYNC_DIR_ALWAYS &&
+ (LSN_FILE_NO(log_descriptor.previous_flush_horizon) !=
+ LSN_FILE_NO(flush_horizon) ||
+ ((LSN_OFFSET(log_descriptor.previous_flush_horizon) - 1) /
+ TRANSLOG_PAGE_SIZE) !=
+ ((LSN_OFFSET(flush_horizon) - 1) / TRANSLOG_PAGE_SIZE)))
+ rc|= sync_dir(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD));
+ log_descriptor.previous_flush_horizon= flush_horizon;
+out:
+ pthread_mutex_lock(&log_descriptor.log_flush_lock);
+ if (sent_to_disk != LSN_IMPOSSIBLE)
+ log_descriptor.flushed= sent_to_disk;
+ log_descriptor.flush_in_progress= 0;
+ DBUG_PRINT("info", ("flush_in_progress is dropped"));
+ pthread_mutex_unlock(&log_descriptor.log_flush_lock);\
+ pthread_cond_broadcast(&log_descriptor.log_flush_cond);
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief Gives a 2-byte-id to MARIA_SHARE and logs this fact
+
+ If a MARIA_SHARE does not yet have a 2-byte-id (unique over all currently
+ open MARIA_SHAREs), give it one and record this assignment in the log
+ (LOGREC_FILE_ID log record).
+
+ @param tbl_info table
+ @param trn calling transaction
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+
+ @note Can be called even if share already has an id (then will do nothing)
+*/
+
+int translog_assign_id_to_share(MARIA_HA *tbl_info, TRN *trn)
+{
+ MARIA_SHARE *share= tbl_info->s;
+ /*
+ If you give an id to a non-BLOCK_RECORD table, you also need to release
+ this id somewhere. Then you can change the assertion.
+ */
+ DBUG_ASSERT(share->data_file_type == BLOCK_RECORD);
+ /* re-check under mutex to avoid having 2 ids for the same share */
+ pthread_mutex_lock(&share->intern_lock);
+ if (unlikely(share->id == 0))
+ {
+ LSN lsn;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ uchar log_data[FILEID_STORE_SIZE];
+ /* Inspired by set_short_trid() of trnman.c */
+ uint i= share->kfile.file % SHARE_ID_MAX + 1;
+ do
+ {
+ my_atomic_rwlock_wrlock(&LOCK_id_to_share);
+ for ( ; i <= SHARE_ID_MAX ; i++) /* the range is [1..SHARE_ID_MAX] */
+ {
+ void *tmp= NULL;
+ if (id_to_share[i] == NULL &&
+ my_atomic_casptr((void **)&id_to_share[i], &tmp, share))
+ {
+ share->id= (uint16)i;
+ break;
+ }
+ }
+ my_atomic_rwlock_wrunlock(&LOCK_id_to_share);
+ i= 1; /* scan the whole array */
+ } while (share->id == 0);
+ DBUG_PRINT("info", ("id_to_share: 0x%lx -> %u", (ulong)share, share->id));
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ /*
+ open_file_name is an unresolved name (symlinks are not resolved, datadir
+ is not realpath-ed, etc) which is good: the log can be moved to another
+ directory and continue working.
+ */
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str=
+ (uchar *)share->open_file_name.str;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length=
+ share->open_file_name.length + 1;
+ /*
+ We can't unlock share->intern_lock before the log entry is written to
+ ensure no one uses the id before it's logged.
+ */
+ if (unlikely(translog_write_record(&lsn, LOGREC_FILE_ID, trn, tbl_info,
+ (translog_size_t)
+ (sizeof(log_data) +
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 1].length),
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, log_data, NULL)))
+ {
+ pthread_mutex_unlock(&share->intern_lock);
+ return 1;
+ }
+ }
+ pthread_mutex_unlock(&share->intern_lock);
+ return 0;
+}
+
+
+/**
+ @brief Recycles a MARIA_SHARE's short id.
+
+ @param share table
+
+ @note Must be called only if share has an id (i.e. id != 0)
+*/
+
+void translog_deassign_id_from_share(MARIA_SHARE *share)
+{
+ DBUG_PRINT("info", ("id_to_share: 0x%lx id %u -> 0",
+ (ulong)share, share->id));
+ /*
+ We don't need any mutex as we are called only when closing the last
+ instance of the table or at the end of REPAIR: no writes can be
+ happening. But a Checkpoint may be reading share->id, so we require this
+ mutex:
+ */
+ safe_mutex_assert_owner(&share->intern_lock);
+ my_atomic_rwlock_rdlock(&LOCK_id_to_share);
+ my_atomic_storeptr((void **)&id_to_share[share->id], 0);
+ my_atomic_rwlock_rdunlock(&LOCK_id_to_share);
+ share->id= 0;
+ /* useless but safety: */
+ share->lsn_of_file_id= LSN_IMPOSSIBLE;
+}
+
+
+void translog_assign_id_to_share_from_recovery(MARIA_SHARE *share,
+ uint16 id)
+{
+ DBUG_ASSERT(maria_in_recovery && !maria_multi_threaded);
+ DBUG_ASSERT(share->data_file_type == BLOCK_RECORD);
+ DBUG_ASSERT(share->id == 0);
+ DBUG_ASSERT(id_to_share[id] == NULL);
+ id_to_share[share->id= id]= share;
+}
+
+
+/**
+ @brief check if such log file exists
+
+ @param file_no number of the file to test
+
+ @retval 0 no such file
+ @retval 1 there is file with such number
+*/
+
+my_bool translog_is_file(uint file_no)
+{
+ MY_STAT stat_buff;
+ char path[FN_REFLEN];
+ return (test(my_stat(translog_filename_by_fileno(file_no, path),
+ &stat_buff, MYF(0))));
+}
+
+
+/**
+ @brief returns minimum log file number
+
+ @param horizon the end of the log
+ @param is_protected true if it is under purge_log protection
+
+ @retval minimum file number
+ @retval 0 no files found
+*/
+
+static uint32 translog_first_file(TRANSLOG_ADDRESS horizon, int is_protected)
+{
+ uint min_file= 0, max_file;
+ DBUG_ENTER("translog_first_file");
+ if (!is_protected)
+ pthread_mutex_lock(&log_descriptor.purger_lock);
+ if (log_descriptor.min_file_number &&
+ translog_is_file(log_descriptor.min_file_number))
+ {
+ DBUG_PRINT("info", ("cached %lu",
+ (ulong) log_descriptor.min_file_number));
+ if (!is_protected)
+ pthread_mutex_unlock(&log_descriptor.purger_lock);
+ DBUG_RETURN(log_descriptor.min_file_number);
+ }
+
+ max_file= LSN_FILE_NO(horizon);
+
+ /* binary search for last file */
+ while (min_file != max_file && min_file != (max_file - 1))
+ {
+ uint test= (min_file + max_file) / 2;
+ DBUG_PRINT("info", ("min_file: %u test: %u max_file: %u",
+ min_file, test, max_file));
+ if (test == max_file)
+ test--;
+ if (translog_is_file(test))
+ max_file= test;
+ else
+ min_file= test;
+ }
+ log_descriptor.min_file_number= max_file;
+ if (!is_protected)
+ pthread_mutex_unlock(&log_descriptor.purger_lock);
+ DBUG_PRINT("info", ("first file :%lu", (ulong) max_file));
+ DBUG_ASSERT(max_file >= 1);
+ DBUG_RETURN(max_file);
+}
+
+
+/**
+ @brief returns the most close LSN higher the given chunk address
+
+ @param addr the chunk address to start from
+ @param horizon the horizon if it is known or LSN_IMPOSSIBLE
+
+ @retval LSN_ERROR Error
+ @retval LSN_IMPOSSIBLE no LSNs after the address
+ @retval # LSN of the most close LSN higher the given chunk address
+*/
+
+LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon)
+{
+ TRANSLOG_SCANNER_DATA scanner;
+ LSN result;
+ DBUG_ENTER("translog_next_LSN");
+
+ if (horizon == LSN_IMPOSSIBLE)
+ horizon= translog_get_horizon();
+
+ if (addr == horizon)
+ DBUG_RETURN(LSN_IMPOSSIBLE);
+
+ translog_scanner_init(addr, 0, &scanner, 1);
+ /*
+ addr can point not to a chunk beginning but page end so next
+ page beginning.
+ */
+ if (addr % TRANSLOG_PAGE_SIZE == 0)
+ {
+ /*
+ We are emulating the page end which cased such horizon value to
+ trigger translog_scanner_eop().
+
+ We can't just increase addr on page header overhead because it
+ can be file end so we allow translog_get_next_chunk() to skip
+ to the next page in correct way
+ */
+ scanner.page_addr-= TRANSLOG_PAGE_SIZE;
+ scanner.page_offset= TRANSLOG_PAGE_SIZE;
+#ifndef DBUG_OFF
+ scanner.page= NULL; /* prevent using incorrect page content */
+#endif
+ }
+ /* addr can point not to a chunk beginning but to a page end */
+ if (translog_scanner_eop(&scanner))
+ {
+ if (translog_get_next_chunk(&scanner))
+ {
+ result= LSN_ERROR;
+ goto out;
+ }
+ if (scanner.page == END_OF_LOG)
+ {
+ result= LSN_IMPOSSIBLE;
+ goto out;
+ }
+ }
+
+ while (!translog_is_LSN_chunk(scanner.page[scanner.page_offset]) &&
+ scanner.page[scanner.page_offset] != TRANSLOG_FILLER)
+ {
+ if (translog_get_next_chunk(&scanner))
+ {
+ result= LSN_ERROR;
+ goto out;
+ }
+ if (scanner.page == END_OF_LOG)
+ {
+ result= LSN_IMPOSSIBLE;
+ goto out;
+ }
+ }
+
+ if (scanner.page[scanner.page_offset] == TRANSLOG_FILLER)
+ result= LSN_IMPOSSIBLE; /* reached page filler */
+ else
+ result= scanner.page_addr + scanner.page_offset;
+out:
+ translog_destroy_scanner(&scanner);
+ DBUG_RETURN(result);
+}
+
+
+/**
+ @brief returns the LSN of the first record starting in this log
+
+ @retval LSN_ERROR Error
+ @retval LSN_IMPOSSIBLE no log or the log is empty
+ @retval # LSN of the first record
+*/
+
+LSN translog_first_lsn_in_log()
+{
+ TRANSLOG_ADDRESS addr, horizon= translog_get_horizon();
+ TRANSLOG_VALIDATOR_DATA data;
+ uint file;
+ uint16 chunk_offset;
+ uchar *page;
+ DBUG_ENTER("translog_first_lsn_in_log");
+ DBUG_PRINT("info", ("Horizon: (%lu,0x%lx)", LSN_IN_PARTS(horizon)));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ if (!(file= translog_first_file(horizon, 0)))
+ {
+ /* log has no records yet */
+ DBUG_RETURN(LSN_IMPOSSIBLE);
+ }
+
+ addr= MAKE_LSN(file, TRANSLOG_PAGE_SIZE); /* the first page of the file */
+ data.addr= &addr;
+ {
+ TRANSLOG_PAGE_SIZE_BUFF psize_buff;
+ if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL ||
+ (chunk_offset= translog_get_first_chunk_offset(page)) == 0)
+ DBUG_RETURN(LSN_ERROR);
+ }
+ addr+= chunk_offset;
+
+ DBUG_RETURN(translog_next_LSN(addr, horizon));
+}
+
+
+/**
+ @brief Returns theoretical first LSN if first log is present
+
+ @retval LSN_ERROR Error
+ @retval LSN_IMPOSSIBLE no log
+ @retval # LSN of the first record
+*/
+
+LSN translog_first_theoretical_lsn()
+{
+ TRANSLOG_ADDRESS addr= translog_get_horizon();
+ TRANSLOG_PAGE_SIZE_BUFF psize_buff;
+ uchar *page;
+ TRANSLOG_VALIDATOR_DATA data;
+ DBUG_ENTER("translog_first_theoretical_lsn");
+ DBUG_PRINT("info", ("Horizon: (%lu,0x%lx)", LSN_IN_PARTS(addr)));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ if (!translog_is_file(1))
+ DBUG_RETURN(LSN_IMPOSSIBLE);
+ if (addr == MAKE_LSN(1, TRANSLOG_PAGE_SIZE))
+ {
+ /* log has no records yet */
+ DBUG_RETURN(MAKE_LSN(1, TRANSLOG_PAGE_SIZE +
+ log_descriptor.page_overhead));
+ }
+
+ addr= MAKE_LSN(1, TRANSLOG_PAGE_SIZE); /* the first page of the file */
+ data.addr= &addr;
+ if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL)
+ DBUG_RETURN(LSN_ERROR);
+
+ DBUG_RETURN(MAKE_LSN(1, TRANSLOG_PAGE_SIZE +
+ page_overhead[page[TRANSLOG_PAGE_FLAGS]]));
+}
+
+
+/**
+ @brief Checks given low water mark and purge files if it is need
+
+ @param low the last (minimum) address which is need
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool translog_purge(TRANSLOG_ADDRESS low)
+{
+ uint32 last_need_file= LSN_FILE_NO(low);
+ TRANSLOG_ADDRESS horizon= translog_get_horizon();
+ int rc= 0;
+ DBUG_ENTER("translog_purge");
+ DBUG_PRINT("enter", ("low: (%lu,0x%lx)", LSN_IN_PARTS(low)));
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ pthread_mutex_lock(&log_descriptor.purger_lock);
+ if (LSN_FILE_NO(log_descriptor.last_lsn_checked) < last_need_file)
+ {
+ uint32 i;
+ uint32 min_file= translog_first_file(horizon, 1);
+ DBUG_ASSERT(min_file != 0); /* log is already started */
+ for(i= min_file; i < last_need_file && rc == 0; i++)
+ {
+ LSN lsn= translog_get_file_max_lsn_stored(i);
+ if (lsn == LSN_IMPOSSIBLE)
+ break; /* files are still in writing */
+ if (lsn == LSN_ERROR)
+ {
+ rc= 1;
+ break;
+ }
+ if (cmp_translog_addr(lsn, low) >= 0)
+ break;
+
+ DBUG_PRINT("info", ("purge file %lu", (ulong) i));
+
+ /* remove file descriptor from the cache */
+ /*
+ log_descriptor.min_file can be changed only here during execution
+ and the function is serialized, so we can access it without problems
+ */
+ if (i >= log_descriptor.min_file)
+ {
+ TRANSLOG_FILE *file;
+ rw_wrlock(&log_descriptor.open_files_lock);
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+ DBUG_ASSERT(log_descriptor.min_file == i);
+ file= *((TRANSLOG_FILE **)pop_dynamic(&log_descriptor.open_files));
+ DBUG_PRINT("info", ("Files : %d", log_descriptor.open_files.elements));
+ DBUG_ASSERT(i == file->number);
+ log_descriptor.min_file++;
+ DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
+ log_descriptor.open_files.elements);
+ rw_unlock(&log_descriptor.open_files_lock);
+ translog_close_log_file(file);
+ }
+ if (log_purge_type == TRANSLOG_PURGE_IMMIDIATE)
+ {
+ char path[FN_REFLEN], *file_name;
+ file_name= translog_filename_by_fileno(i, path);
+ rc= test(my_delete(file_name, MYF(MY_WME)));
+ }
+ }
+ if (unlikely(rc == 1))
+ log_descriptor.min_need_file= 0; /* impossible value */
+ else
+ log_descriptor.min_need_file= i;
+ }
+
+ pthread_mutex_unlock(&log_descriptor.purger_lock);
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief Purges files by stored min need file in case of
+ "ondemend" purge type
+
+ @note This function do real work only if it is "ondemend" purge type
+ and translog_purge() was called at least once and last time without
+ errors
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool translog_purge_at_flush()
+{
+ uint32 i, min_file;
+ int rc= 0;
+ DBUG_ENTER("translog_purge_at_flush");
+ DBUG_ASSERT(translog_status == TRANSLOG_OK ||
+ translog_status == TRANSLOG_READONLY);
+
+ if (unlikely(translog_status == TRANSLOG_READONLY))
+ {
+ DBUG_PRINT("info", ("The log is read only => exit"));
+ DBUG_RETURN(0);
+ }
+
+ if (log_purge_type != TRANSLOG_PURGE_ONDEMAND)
+ {
+ DBUG_PRINT("info", ("It is not \"at_flush\" => exit"));
+ DBUG_RETURN(0);
+ }
+
+ pthread_mutex_lock(&log_descriptor.purger_lock);
+
+ if (unlikely(log_descriptor.min_need_file == 0))
+ {
+ DBUG_PRINT("info", ("No info about min need file => exit"));
+ pthread_mutex_unlock(&log_descriptor.purger_lock);
+ DBUG_RETURN(0);
+ }
+
+ min_file= translog_first_file(translog_get_horizon(), 1);
+ DBUG_ASSERT(min_file != 0); /* log is already started */
+ for(i= min_file; i < log_descriptor.min_need_file && rc == 0; i++)
+ {
+ char path[FN_REFLEN], *file_name;
+ DBUG_PRINT("info", ("purge file %lu\n", (ulong) i));
+ file_name= translog_filename_by_fileno(i, path);
+ rc= test(my_delete(file_name, MYF(MY_WME)));
+ }
+
+ pthread_mutex_unlock(&log_descriptor.purger_lock);
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief Gets min file number
+
+ @param horizon the end of the log
+
+ @retval minimum file number
+ @retval 0 no files found
+*/
+
+uint32 translog_get_first_file(TRANSLOG_ADDRESS horizon)
+{
+ return translog_first_file(horizon, 0);
+}
+
+
+/**
+ @brief Gets min file number which is needed
+
+ @retval minimum file number
+ @retval 0 unknown
+*/
+
+uint32 translog_get_first_needed_file()
+{
+ uint32 file_no;
+ pthread_mutex_lock(&log_descriptor.purger_lock);
+ file_no= log_descriptor.min_need_file;
+ pthread_mutex_unlock(&log_descriptor.purger_lock);
+ return file_no;
+}
+
+
+/**
+ @brief Gets transaction log file size
+
+ @return transaction log file size
+*/
+
+uint32 translog_get_file_size()
+{
+ uint32 res;
+ translog_lock();
+ res= log_descriptor.log_file_max_size;
+ translog_unlock();
+ return (res);
+}
+
+
+/**
+ @brief Sets transaction log file size
+
+ @return Returns actually set transaction log size
+*/
+
+void translog_set_file_size(uint32 size)
+{
+ struct st_translog_buffer *old_buffer= NULL;
+ DBUG_ENTER("translog_set_file_size");
+ translog_lock();
+ DBUG_PRINT("enter", ("Size: %lu", (ulong) size));
+ DBUG_ASSERT(size % TRANSLOG_PAGE_SIZE == 0 &&
+ size >= TRANSLOG_MIN_FILE_SIZE);
+ log_descriptor.log_file_max_size= size;
+ /* if current file longer then finish it*/
+ if (LSN_OFFSET(log_descriptor.horizon) >= log_descriptor.log_file_max_size)
+ {
+ old_buffer= log_descriptor.bc.buffer;
+ translog_buffer_next(&log_descriptor.horizon, &log_descriptor.bc, 1);
+ translog_buffer_unlock(old_buffer);
+ }
+ translog_unlock();
+ if (old_buffer)
+ {
+ translog_buffer_lock(old_buffer);
+ translog_buffer_flush(old_buffer);
+ translog_buffer_unlock(old_buffer);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Write debug information to log if we EXTRA_DEBUG is enabled
+*/
+
+my_bool translog_log_debug_info(TRN *trn __attribute__((unused)),
+ enum translog_debug_info_type type
+ __attribute__((unused)),
+ uchar *info __attribute__((unused)),
+ size_t length __attribute__((unused)))
+{
+#ifdef EXTRA_DEBUG
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ uchar debug_type;
+ LSN lsn;
+
+ if (!trn)
+ {
+ /*
+ We can't log the current transaction because we don't have
+ an active transaction. Use a temporary transaction object instead
+ */
+ trn= &dummy_transaction_object;
+ }
+ debug_type= (uchar) type;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= &debug_type;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= 1;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= info;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= length;
+ return translog_write_record(&lsn, LOGREC_DEBUG_INFO,
+ trn, NULL,
+ (translog_size_t) (1+ length),
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL);
+#else
+ return 0;
+#endif
+}
+
+
+#ifdef MARIA_DUMP_LOG
+#include <my_getopt.h>
+extern void translog_example_table_init();
+static const char *load_default_groups[]= { "maria_dump_log",0 };
+static void get_options(int *argc,char * * *argv);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+const char *default_dbug_option= "d:t:i:O,\\maria_dump_log.trace";
+#else
+const char *default_dbug_option= "d:t:i:o,/tmp/maria_dump_log.trace";
+#endif
+#endif
+static ulonglong opt_offset;
+static ulong opt_pages;
+static const char *opt_file= NULL;
+static File handler= -1;
+static my_bool opt_unit= 0;
+static struct my_option my_long_options[] =
+{
+#ifdef IMPLTMENTED
+ {"body", 'b',
+ "Print chunk body dump",
+ (uchar **) &opt_body, (uchar **) &opt_body, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+#ifndef DBUG_OFF
+ {"debug", '#', "Output debug log. Often the argument is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"file", 'f', "Path to file which will be read",
+ (uchar**) &opt_file, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"help", '?', "Display this help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { "offset", 'o', "Start reading log from this offset",
+ (uchar**) &opt_offset, (uchar**) &opt_offset,
+ 0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 },
+ { "pages", 'n', "Number of pages to read",
+ (uchar**) &opt_pages, (uchar**) &opt_pages, 0,
+ GET_ULONG, REQUIRED_ARG, (long) ~(ulong) 0,
+ (long) 1, (long) ~(ulong) 0, (long) 0,
+ (long) 1, 0},
+ {"unit-test", 'U',
+ "Use unit test record table (for logs created by unittests",
+ (uchar **) &opt_unit, (uchar **) &opt_unit, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+static void print_version(void)
+{
+ VOID(printf("%s Ver 1.0 for %s on %s\n",
+ my_progname_short, SYSTEM_TYPE, MACHINE_TYPE));
+ NETWARE_SET_SCREEN_MODE(1);
+}
+
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 2008 MySQL AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
+ puts("and you are welcome to modify and redistribute it under the GPL license\n");
+
+ puts("Dump content of maria log pages.");
+ VOID(printf("\nUsage: %s -f file OPTIONS\n", my_progname_short));
+ my_print_help(my_long_options);
+ print_defaults("my", load_default_groups);
+ my_print_variables(my_long_options);
+}
+
+
+static my_bool
+get_one_option(int optid __attribute__((unused)),
+ const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch (optid) {
+ case '?':
+ usage();
+ exit(0);
+ case 'V':
+ print_version();
+ exit(0);
+#ifndef DBUG_OFF
+ case '#':
+ DBUG_SET_INITIAL(argument ? argument : default_dbug_option);
+ break;
+#endif
+ }
+ return 0;
+}
+
+
+static void get_options(int *argc,char ***argv)
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ if (opt_file == NULL)
+ {
+ usage();
+ exit(1);
+ }
+}
+
+
+/**
+ @brief Dump information about file header page.
+*/
+
+static void dump_header_page(uchar *buff)
+{
+ LOGHANDLER_FILE_INFO desc;
+ char strbuff[21];
+ translog_interpret_file_header(&desc, buff);
+ printf(" This can be header page:\n"
+ " Timestamp: %s\n"
+ " Maria log version: %lu\n"
+ " Server version: %lu\n"
+ " Server id %lu\n"
+ " Page size %lu\n",
+ llstr(desc.timestamp, strbuff),
+ desc.maria_version,
+ desc.mysql_version,
+ desc.server_id,
+ desc.page_size);
+ if (desc.page_size != TRANSLOG_PAGE_SIZE)
+ printf(" WARNING: page size is not equal compiled in one %lu!!!\n",
+ (ulong) TRANSLOG_PAGE_SIZE);
+ printf(" File number %lu\n"
+ " Max lsn: (%lu,0x%lx)\n",
+ desc.file_number,
+ LSN_IN_PARTS(desc.max_lsn));
+}
+
+static const char *record_class_string[]=
+{
+ "LOGRECTYPE_NOT_ALLOWED",
+ "LOGRECTYPE_VARIABLE_LENGTH",
+ "LOGRECTYPE_PSEUDOFIXEDLENGTH",
+ "LOGRECTYPE_FIXEDLENGTH"
+};
+
+
+/**
+ @brief dump information about transaction log chunk
+
+ @param buffer reference to the whole page
+ @param ptr pointer to the chunk
+
+ @reval # reference to the next chunk
+ @retval NULL can't interpret data
+*/
+
+static uchar *dump_chunk(uchar *buffer, uchar *ptr)
+{
+ uint length;
+ if (*ptr == TRANSLOG_FILLER)
+ {
+ printf(" Filler till the page end\n");
+ for (; ptr < buffer + TRANSLOG_PAGE_SIZE; ptr++)
+ {
+ if (*ptr != TRANSLOG_FILLER)
+ {
+ printf(" WARNING: non filler character met before page end "
+ "(page + 0x%04x: 0x%02x) (stop interpretation)!!!",
+ (uint) (ptr - buffer), (uint) ptr[0]);
+ return NULL;
+ }
+ }
+ return ptr;
+ }
+ if (*ptr == 0 || *ptr == 0xFF)
+ {
+ printf(" WARNING: chunk can't start from 0x0 "
+ "(stop interpretation)!!!\n");
+ return NULL;
+ }
+ switch (ptr[0] & TRANSLOG_CHUNK_TYPE) {
+ case TRANSLOG_CHUNK_LSN:
+ printf(" LSN chunk type 0 (variable length)\n");
+ if (likely((ptr[0] & TRANSLOG_REC_TYPE) != TRANSLOG_CHUNK_0_CONT))
+ {
+ printf(" Record type %u: %s record class %s compressed LSNs: %u\n",
+ ptr[0] & TRANSLOG_REC_TYPE,
+ (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name ?
+ log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name :
+ "NULL"),
+ record_class_string[log_record_type_descriptor[ptr[0] &
+ TRANSLOG_REC_TYPE].
+ rclass],
+ log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].
+ compressed_LSN);
+ if (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].rclass !=
+ LOGRECTYPE_VARIABLE_LENGTH)
+ {
+ printf(" WARNING: this record class here can't be used "
+ "(stop interpretation)!!!\n");
+ break;
+ }
+ }
+ else
+ printf(" Continuation of previous chunk 0 header \n");
+ printf(" Short transaction id: %u\n", (uint) uint2korr(ptr + 1));
+ {
+ uchar *hdr_ptr= ptr + 1 + 2; /* chunk type and short trid */
+ uint16 chunk_len;
+ printf (" Record length: %lu\n",
+ (ulong) translog_variable_record_1group_decode_len(&hdr_ptr));
+ chunk_len= uint2korr(hdr_ptr);
+ if (chunk_len == 0)
+ printf (" It is 1 group record (chunk length == 0)\n");
+ else
+ {
+ uint16 groups, i;
+
+ printf (" Chunk length %u\n", (uint) chunk_len);
+ groups= uint2korr(hdr_ptr + 2);
+ hdr_ptr+= 4;
+ printf (" Number of groups left to the end %u:\n", (uint) groups);
+ for(i= 0;
+ i < groups && hdr_ptr < buffer + TRANSLOG_PAGE_SIZE;
+ i++, hdr_ptr+= LSN_STORE_SIZE + 1)
+ {
+ TRANSLOG_ADDRESS gpr_addr= lsn_korr(hdr_ptr);
+ uint pages= hdr_ptr[LSN_STORE_SIZE];
+ printf (" Group +#%u: (%lu,0x%lx) pages: %u\n",
+ (uint) i, LSN_IN_PARTS(gpr_addr), pages);
+ }
+ }
+ }
+ break;
+ case TRANSLOG_CHUNK_FIXED:
+ printf(" LSN chunk type 1 (fixed size)\n");
+ printf(" Record type %u: %s record class %s compressed LSNs: %u\n",
+ ptr[0] & TRANSLOG_REC_TYPE,
+ (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name ?
+ log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name :
+ "NULL"),
+ record_class_string[log_record_type_descriptor[ptr[0] &
+ TRANSLOG_REC_TYPE].
+ rclass],
+ log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].
+ compressed_LSN);
+ if (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].rclass !=
+ LOGRECTYPE_PSEUDOFIXEDLENGTH &&
+ log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].rclass !=
+ LOGRECTYPE_FIXEDLENGTH)
+ {
+ printf(" WARNING: this record class here can't be used "
+ "(stop interpretation)!!!\n");
+ }
+ printf(" Short transaction id: %u\n", (uint) uint2korr(ptr + 1));
+ break;
+ case TRANSLOG_CHUNK_NOHDR:
+ printf(" No header chunk type 2(till the end of the page)\n");
+ if (ptr[0] & TRANSLOG_REC_TYPE)
+ {
+ printf(" WARNING: chunk header content record type: 0x%02x "
+ "(dtop interpretation)!!!",
+ (uint) ptr[0]);
+ return NULL;
+ }
+ break;
+ case TRANSLOG_CHUNK_LNGTH:
+ printf(" Chunk with length type 3\n");
+ if (ptr[0] & TRANSLOG_REC_TYPE)
+ {
+ printf(" WARNING: chunk header content record type: 0x%02x "
+ "(dtop interpretation)!!!",
+ (uint) ptr[0]);
+ return NULL;
+ }
+ break;
+ }
+ {
+ intptr offset= ptr - buffer;
+ DBUG_ASSERT(offset >= 0 && offset <= UINT_MAX16);
+ length= translog_get_total_chunk_length(buffer, (uint16)offset);
+ }
+ printf(" Length %u\n", length);
+ ptr+= length;
+ return ptr;
+}
+
+
+/**
+ @brief Dump information about page with data.
+*/
+
+static void dump_datapage(uchar *buffer)
+{
+ uchar *ptr;
+ ulong offset;
+ uint32 page, file;
+ uint header_len;
+ printf(" Page: %ld File number: %ld\n",
+ (ulong) (page= uint3korr(buffer)),
+ (ulong) (file= uint3korr(buffer + 3)));
+ if (page == 0)
+ printf(" WARNING: page == 0!!!\n");
+ if (file == 0)
+ printf(" WARNING: file == 0!!!\n");
+ offset= page * TRANSLOG_PAGE_SIZE;
+ printf(" Flags (0x%x):\n", (uint) buffer[TRANSLOG_PAGE_FLAGS]);
+ if (buffer[TRANSLOG_PAGE_FLAGS])
+ {
+ if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_PAGE_CRC)
+ printf(" Page CRC\n");
+ if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION)
+ printf(" Sector protection\n");
+ if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_RECORD_CRC)
+ printf(" Record CRC (WARNING: not yet implemented!!!)\n");
+ if (buffer[TRANSLOG_PAGE_FLAGS] & ~(TRANSLOG_PAGE_CRC |
+ TRANSLOG_SECTOR_PROTECTION |
+ TRANSLOG_RECORD_CRC))
+ {
+ printf(" WARNING: unknown flags (stop interpretation)!!!\n");
+ return;
+ }
+ }
+ else
+ printf(" No flags\n");
+ printf(" Page header length: %u\n",
+ (header_len= page_overhead[buffer[TRANSLOG_PAGE_FLAGS]]));
+ if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_RECORD_CRC)
+ {
+ uint32 crc= uint4korr(buffer + TRANSLOG_PAGE_FLAGS + 1);
+ uint32 ccrc;
+ printf (" Page CRC 0x%04lx\n", (ulong) crc);
+ ccrc= translog_crc(buffer + header_len, TRANSLOG_PAGE_SIZE - header_len);
+ if (crc != ccrc)
+ printf(" WARNING: calculated CRC: 0x%04lx!!!\n", (ulong) ccrc);
+ }
+ if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION)
+ {
+ TRANSLOG_FILE tfile;
+ {
+ uchar *table= buffer + header_len -
+ TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
+ uint i;
+ printf(" Sector protection current value: 0x%02x\n", (uint) table[0]);
+ for (i= 1; i < TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE; i++)
+ {
+ printf(" Sector protection in sector: 0x%02x saved value 0x%02x\n",
+ (uint)buffer[i * DISK_DRIVE_SECTOR_SIZE],
+ (uint)table[i]);
+ }
+ }
+ tfile.number= file;
+ tfile.handler.file= handler;
+ pagecache_file_init(tfile.handler, NULL, NULL, NULL, NULL, NULL);
+ tfile.was_recovered= 0;
+ tfile.is_sync= 1;
+ if (translog_check_sector_protection(buffer, &tfile))
+ printf(" WARNING: sector protection found problems!!!\n");
+ }
+ ptr= buffer + header_len;
+ while (ptr && ptr < buffer + TRANSLOG_PAGE_SIZE)
+ {
+ printf(" Chunk (%lu,0x%lx):\n",
+ (ulong)file, (ulong) offset + (ptr - buffer));
+ ptr= dump_chunk(buffer, ptr);
+ }
+}
+
+
+/**
+ @brief Dump information about page.
+*/
+
+static void dump_page(uchar *buffer)
+{
+ printf("Page by offset %llu (0x%llx)\n", opt_offset, opt_offset);
+ if (strncmp((char*)maria_trans_file_magic, (char*)buffer,
+ sizeof(maria_trans_file_magic)) == 0)
+ {
+ dump_header_page(buffer);
+ }
+ dump_datapage(buffer);
+}
+
+
+/**
+ @brief maria_dump_log main function.
+*/
+
+int main(int argc, char **argv)
+{
+ char **default_argv;
+ uchar buffer[TRANSLOG_PAGE_SIZE];
+ MY_INIT(argv[0]);
+
+ load_defaults("my", load_default_groups, &argc, &argv);
+ default_argv= argv;
+ get_options(&argc, &argv);
+
+ if (opt_unit)
+ translog_example_table_init();
+ else
+ translog_table_init();
+ translog_fill_overhead_table();
+
+ maria_data_root= (char *)".";
+
+ if ((handler= my_open(opt_file, O_RDONLY, MYF(MY_WME))) < 0)
+ {
+ fprintf(stderr, "Can't open file: '%s' errno: %d\n",
+ opt_file, my_errno);
+ goto err;
+ }
+ if (my_seek(handler, opt_offset, SEEK_SET, MYF(MY_WME)) !=
+ opt_offset)
+ {
+ fprintf(stderr, "Can't set position %lld file: '%s' errno: %d\n",
+ opt_offset, opt_file, my_errno);
+ goto err;
+ }
+ for (;
+ opt_pages;
+ opt_offset+= TRANSLOG_PAGE_SIZE, opt_pages--)
+ {
+ if (my_pread(handler, buffer, TRANSLOG_PAGE_SIZE, opt_offset,
+ MYF(MY_NABP)))
+ {
+ if (my_errno == HA_ERR_FILE_TOO_SHORT)
+ goto end;
+ fprintf(stderr, "Can't read page at position %lld file: '%s' "
+ "errno: %d\n", opt_offset, opt_file, my_errno);
+ goto err;
+ }
+ dump_page(buffer);
+ }
+
+end:
+ my_close(handler, MYF(0));
+ free_defaults(default_argv);
+ exit(0);
+ return 0; /* No compiler warning */
+
+err:
+ my_close(handler, MYF(0));
+ fprintf(stderr, "%s: FAILED\n", my_progname_short);
+ free_defaults(default_argv);
+ exit(1);
+}
+#endif
diff --git a/storage/maria/ma_loghandler.h b/storage/maria/ma_loghandler.h
new file mode 100644
index 00000000000..dba6283e303
--- /dev/null
+++ b/storage/maria/ma_loghandler.h
@@ -0,0 +1,460 @@
+/* Copyright (C) 2007 MySQL AB & Sanja Belkin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _ma_loghandler_h
+#define _ma_loghandler_h
+
+/* transaction log default cache size (TODO: make it global variable) */
+#define TRANSLOG_PAGECACHE_SIZE (1024U*1024*2)
+/* transaction log default file size */
+#define TRANSLOG_FILE_SIZE (1024U*1024*1024)
+/* minimum possible transaction log size */
+#define TRANSLOG_MIN_FILE_SIZE (1024U*1024*8)
+/* transaction log default flags (TODO: make it global variable) */
+#define TRANSLOG_DEFAULT_FLAGS 0
+
+/*
+ Transaction log flags.
+
+ We allow all kind protections to be switched on together for people who
+ really unsure in their hardware/OS.
+*/
+#define TRANSLOG_PAGE_CRC 1
+#define TRANSLOG_SECTOR_PROTECTION (1<<1)
+#define TRANSLOG_RECORD_CRC (1<<2)
+#define TRANSLOG_FLAGS_NUM ((TRANSLOG_PAGE_CRC | TRANSLOG_SECTOR_PROTECTION | \
+ TRANSLOG_RECORD_CRC) + 1)
+
+#define RECHEADER_READ_ERROR -1
+#define RECHEADER_READ_EOF -2
+
+/*
+ Page size in transaction log
+ It should be Power of 2 and multiple of DISK_DRIVE_SECTOR_SIZE
+ (DISK_DRIVE_SECTOR_SIZE * 2^N)
+*/
+#define TRANSLOG_PAGE_SIZE (8U*1024)
+
+#include "ma_loghandler_lsn.h"
+#include "trnman_public.h"
+
+/* short transaction ID type */
+typedef uint16 SHORT_TRANSACTION_ID;
+
+struct st_maria_handler;
+
+/* Changing one of the "SIZE" below will break backward-compatibility! */
+/* Length of CRC at end of pages */
+#define ROW_EXTENT_PAGE_SIZE 5
+#define ROW_EXTENT_COUNT_SIZE 2
+/* Size of file id in logs */
+#define FILEID_STORE_SIZE 2
+/* Size of page reference in log */
+#define PAGE_STORE_SIZE ROW_EXTENT_PAGE_SIZE
+/* Size of page ranges in log */
+#define PAGERANGE_STORE_SIZE ROW_EXTENT_COUNT_SIZE
+#define DIRPOS_STORE_SIZE 1
+#define CLR_TYPE_STORE_SIZE 1
+/* If table has live checksum we store its changes in UNDOs */
+#define HA_CHECKSUM_STORE_SIZE 4
+#define KEY_NR_STORE_SIZE 1
+#define PAGE_LENGTH_STORE_SIZE 2
+
+/* Store methods to match the above sizes */
+#define fileid_store(T,A) int2store(T,A)
+#define page_store(T,A) int5store(T,((ulonglong)(A)))
+#define dirpos_store(T,A) ((*(uchar*) (T)) = A)
+#define pagerange_store(T,A) int2store(T,A)
+#define clr_type_store(T,A) ((*(uchar*) (T)) = A)
+#define key_nr_store(T, A) ((*(uchar*) (T)) = A)
+#define ha_checksum_store(T,A) int4store(T,A)
+#define fileid_korr(P) uint2korr(P)
+#define page_korr(P) uint5korr(P)
+#define dirpos_korr(P) (*(const uchar *) (P))
+#define pagerange_korr(P) uint2korr(P)
+#define clr_type_korr(P) (*(const uchar *) (P))
+#define key_nr_korr(P) (*(const uchar *) (P))
+#define ha_checksum_korr(P) uint4korr(P)
+
+/*
+ Length of disk drive sector size (we assume that writing it
+ to disk is an atomic operation)
+*/
+#define DISK_DRIVE_SECTOR_SIZE 512U
+
+/* position reserved in an array of parts of a log record */
+#define TRANSLOG_INTERNAL_PARTS 2
+
+/* types of records in the transaction log */
+/* TODO: Set numbers for these when we have all entries figured out */
+
+enum translog_record_type
+{
+ LOGREC_RESERVED_FOR_CHUNKS23= 0,
+ LOGREC_REDO_INSERT_ROW_HEAD,
+ LOGREC_REDO_INSERT_ROW_TAIL,
+ LOGREC_REDO_NEW_ROW_HEAD,
+ LOGREC_REDO_NEW_ROW_TAIL,
+ LOGREC_REDO_INSERT_ROW_BLOBS,
+ LOGREC_REDO_PURGE_ROW_HEAD,
+ LOGREC_REDO_PURGE_ROW_TAIL,
+ LOGREC_REDO_FREE_BLOCKS,
+ LOGREC_REDO_FREE_HEAD_OR_TAIL,
+ LOGREC_REDO_DELETE_ROW, /* unused */
+ LOGREC_REDO_UPDATE_ROW_HEAD, /* unused */
+ LOGREC_REDO_INDEX,
+ LOGREC_REDO_INDEX_NEW_PAGE,
+ LOGREC_REDO_INDEX_FREE_PAGE,
+ LOGREC_REDO_UNDELETE_ROW,
+ LOGREC_CLR_END,
+ LOGREC_PURGE_END,
+ LOGREC_UNDO_ROW_INSERT,
+ LOGREC_UNDO_ROW_DELETE,
+ LOGREC_UNDO_ROW_UPDATE,
+ LOGREC_UNDO_KEY_INSERT,
+ LOGREC_UNDO_KEY_INSERT_WITH_ROOT,
+ LOGREC_UNDO_KEY_DELETE,
+ LOGREC_UNDO_KEY_DELETE_WITH_ROOT,
+ LOGREC_PREPARE,
+ LOGREC_PREPARE_WITH_UNDO_PURGE,
+ LOGREC_COMMIT,
+ LOGREC_COMMIT_WITH_UNDO_PURGE,
+ LOGREC_CHECKPOINT,
+ LOGREC_REDO_CREATE_TABLE,
+ LOGREC_REDO_RENAME_TABLE,
+ LOGREC_REDO_DROP_TABLE,
+ LOGREC_REDO_DELETE_ALL,
+ LOGREC_REDO_REPAIR_TABLE,
+ LOGREC_FILE_ID,
+ LOGREC_LONG_TRANSACTION_ID,
+ LOGREC_INCOMPLETE_LOG,
+ LOGREC_INCOMPLETE_GROUP,
+ LOGREC_UNDO_BULK_INSERT,
+ LOGREC_REDO_BITMAP_NEW_PAGE,
+ LOGREC_IMPORTED_TABLE,
+ LOGREC_DEBUG_INFO,
+ LOGREC_FIRST_FREE,
+ LOGREC_RESERVED_FUTURE_EXTENSION= 63
+};
+#define LOGREC_NUMBER_OF_TYPES 64 /* Maximum, can't be extended */
+
+/* Type of operations in LOGREC_REDO_INDEX */
+
+enum en_key_op
+{
+ KEY_OP_NONE, /* Not used */
+ KEY_OP_OFFSET, /* Set current position */
+ KEY_OP_SHIFT, /* Shift up/or down at current position */
+ KEY_OP_CHANGE, /* Change data at current position */
+ KEY_OP_ADD_PREFIX, /* Insert data at start of page */
+ KEY_OP_DEL_PREFIX, /* Delete data at start of page */
+ KEY_OP_ADD_SUFFIX, /* Insert data at end of page */
+ KEY_OP_DEL_SUFFIX, /* Delete data at end of page */
+ KEY_OP_CHECK, /* For debugging; CRC of used part of page */
+ KEY_OP_MULTI_COPY, /* List of memcpy()s with fixed-len sources in page */
+ KEY_OP_SET_PAGEFLAG, /* Set pageflag from next byte */
+ KEY_OP_COMPACT_PAGE /* Compact key page */
+};
+
+
+enum translog_debug_info_type
+{
+ LOGREC_DEBUG_INFO_QUERY
+};
+
+/* Size of log file; One log file is restricted to 4G */
+typedef uint32 translog_size_t;
+
+#define TRANSLOG_RECORD_HEADER_MAX_SIZE 1024U
+
+typedef struct st_translog_group_descriptor
+{
+ TRANSLOG_ADDRESS addr;
+ uint8 num;
+} TRANSLOG_GROUP;
+
+
+typedef struct st_translog_header_buffer
+{
+ /* LSN of the read record */
+ LSN lsn;
+ /* array of groups descriptors, can be used only if groups_no > 0 */
+ TRANSLOG_GROUP *groups;
+ /* short transaction ID or 0 if it has no sense for the record */
+ SHORT_TRANSACTION_ID short_trid;
+ /*
+ The Record length in buffer (including read header, but excluding
+ hidden part of record (type, short TrID, length)
+ */
+ translog_size_t record_length;
+ /*
+ Buffer for write decoded header of the record (depend on the record
+ type)
+ */
+ uchar header[TRANSLOG_RECORD_HEADER_MAX_SIZE];
+ /* number of groups listed in */
+ uint groups_no;
+ /* in multi-group number of chunk0 pages (valid only if groups_no > 0) */
+ uint chunk0_pages;
+ /* type of the read record */
+ enum translog_record_type type;
+ /* chunk 0 data address (valid only if groups_no > 0) */
+ TRANSLOG_ADDRESS chunk0_data_addr;
+ /*
+ Real compressed LSN(s) size economy (<number of LSN(s)>*7 - <real_size>)
+ */
+ int16 compressed_LSN_economy;
+ /* short transaction ID or 0 if it has no sense for the record */
+ uint16 non_header_data_start_offset;
+ /* non read body data length in this first chunk */
+ uint16 non_header_data_len;
+ /* chunk 0 data size (valid only if groups_no > 0) */
+ uint16 chunk0_data_len;
+} TRANSLOG_HEADER_BUFFER;
+
+
+typedef struct st_translog_scanner_data
+{
+ uchar buffer[TRANSLOG_PAGE_SIZE]; /* buffer for page content */
+ TRANSLOG_ADDRESS page_addr; /* current page address */
+ /* end of the log which we saw last time */
+ TRANSLOG_ADDRESS horizon;
+ TRANSLOG_ADDRESS last_file_page; /* Last page on in this file */
+ uchar *page; /* page content pointer */
+ /* direct link on the current page or NULL if not supported/requested */
+ PAGECACHE_BLOCK_LINK *direct_link;
+ /* offset of the chunk in the page */
+ translog_size_t page_offset;
+ /* set horizon only once at init */
+ my_bool fixed_horizon;
+ /* try to get direct link on the page if it is possible */
+ my_bool use_direct_link;
+} TRANSLOG_SCANNER_DATA;
+
+
+typedef struct st_translog_reader_data
+{
+ TRANSLOG_HEADER_BUFFER header; /* Header */
+ TRANSLOG_SCANNER_DATA scanner; /* chunks scanner */
+ translog_size_t body_offset; /* current chunk body offset */
+ /* data offset from the record beginning */
+ translog_size_t current_offset;
+ /* number of bytes read in header */
+ uint16 read_header;
+ uint16 chunk_size; /* current chunk size */
+ uint current_group; /* current group */
+ uint current_chunk; /* current chunk in the group */
+ my_bool eor; /* end of the record */
+} TRANSLOG_READER_DATA;
+
+C_MODE_START
+
+/* Records types for unittests */
+#define LOGREC_FIXED_RECORD_0LSN_EXAMPLE 1
+#define LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE 2
+#define LOGREC_FIXED_RECORD_1LSN_EXAMPLE 3
+#define LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE 4
+#define LOGREC_FIXED_RECORD_2LSN_EXAMPLE 5
+#define LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE 6
+
+extern void translog_example_table_init();
+extern void translog_table_init();
+#define translog_init(D,M,V,I,C,F,R) \
+ translog_init_with_table(D,M,V,I,C,F,R,&translog_table_init,0)
+extern my_bool translog_init_with_table(const char *directory,
+ uint32 log_file_max_size,
+ uint32 server_version,
+ uint32 server_id,
+ PAGECACHE *pagecache,
+ uint flags,
+ my_bool readonly,
+ void (*init_table_func)(),
+ my_bool no_error);
+
+extern my_bool
+translog_write_record(LSN *lsn, enum translog_record_type type, TRN *trn,
+ MARIA_HA *tbl_info,
+ translog_size_t rec_len, uint part_no,
+ LEX_CUSTRING *parts_data, uchar *store_share_id,
+ void *hook_arg);
+
+extern void translog_destroy();
+
+extern int translog_read_record_header(LSN lsn, TRANSLOG_HEADER_BUFFER *buff);
+
+extern void translog_free_record_header(TRANSLOG_HEADER_BUFFER *buff);
+
+extern translog_size_t translog_read_record(LSN lsn,
+ translog_size_t offset,
+ translog_size_t length,
+ uchar *buffer,
+ struct st_translog_reader_data
+ *data);
+
+extern my_bool translog_flush(TRANSLOG_ADDRESS lsn);
+
+extern my_bool translog_scanner_init(LSN lsn,
+ my_bool fixed_horizon,
+ struct st_translog_scanner_data *scanner,
+ my_bool use_direct_link);
+extern void translog_destroy_scanner(TRANSLOG_SCANNER_DATA *scanner);
+
+extern int translog_read_next_record_header(TRANSLOG_SCANNER_DATA *scanner,
+ TRANSLOG_HEADER_BUFFER *buff);
+extern LSN translog_get_file_max_lsn_stored(uint32 file);
+extern my_bool translog_purge(TRANSLOG_ADDRESS low);
+extern my_bool translog_is_file(uint file_no);
+extern void translog_lock();
+extern void translog_unlock();
+extern void translog_lock_handler_assert_owner();
+extern TRANSLOG_ADDRESS translog_get_horizon();
+extern TRANSLOG_ADDRESS translog_get_horizon_no_lock();
+extern int translog_assign_id_to_share(struct st_maria_handler *tbl_info,
+ TRN *trn);
+extern void translog_deassign_id_from_share(struct st_maria_share *share);
+extern void
+translog_assign_id_to_share_from_recovery(struct st_maria_share *share,
+ uint16 id);
+extern my_bool translog_walk_filenames(const char *directory,
+ my_bool (*callback)(const char *,
+ const char *));
+extern my_bool translog_log_debug_info(TRN *trn,
+ enum translog_debug_info_type type,
+ uchar *info, size_t length);
+
+enum enum_translog_status
+{
+ TRANSLOG_UNINITED, /* no initialization done or error during initialization */
+ TRANSLOG_OK, /* transaction log is functioning */
+ TRANSLOG_READONLY, /* read only mode due to write errors */
+ TRANSLOG_SHUTDOWN /* going to shutdown the loghandler */
+};
+extern enum enum_translog_status translog_status;
+
+/*
+ all the rest added because of recovery; should we make
+ ma_loghandler_for_recovery.h ?
+*/
+
+#define SHARE_ID_MAX 65535 /* array's size */
+
+extern LSN translog_first_lsn_in_log();
+extern LSN translog_first_theoretical_lsn();
+extern LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon);
+extern my_bool translog_purge_at_flush();
+extern uint32 translog_get_first_file(TRANSLOG_ADDRESS horizon);
+extern uint32 translog_get_first_needed_file();
+extern char *translog_filename_by_fileno(uint32 file_no, char *path);
+extern void translog_set_file_size(uint32 size);
+
+/* record parts descriptor */
+struct st_translog_parts
+{
+ /* full record length */
+ translog_size_t record_length;
+ /* full record length with chunk headers */
+ translog_size_t total_record_length;
+ /* current part index */
+ uint current;
+ /* total number of elements in parts */
+ uint elements;
+ /* array of parts */
+ LEX_CUSTRING *parts;
+};
+
+typedef my_bool(*prewrite_rec_hook) (enum translog_record_type type,
+ TRN *trn,
+ struct st_maria_handler *tbl_info,
+ void *hook_arg);
+
+typedef my_bool(*inwrite_rec_hook) (enum translog_record_type type,
+ TRN *trn,
+ struct st_maria_handler *tbl_info,
+ LSN *lsn, void *hook_arg);
+
+typedef uint16(*read_rec_hook) (enum translog_record_type type,
+ uint16 read_length, uchar *read_buff,
+ uchar *decoded_buff);
+
+
+/* record classes */
+enum record_class
+{
+ LOGRECTYPE_NOT_ALLOWED,
+ LOGRECTYPE_VARIABLE_LENGTH,
+ LOGRECTYPE_PSEUDOFIXEDLENGTH,
+ LOGRECTYPE_FIXEDLENGTH
+};
+
+enum enum_record_in_group {
+ LOGREC_NOT_LAST_IN_GROUP= 0, LOGREC_LAST_IN_GROUP, LOGREC_IS_GROUP_ITSELF
+};
+
+/*
+ Descriptor of log record type
+*/
+typedef struct st_log_record_type_descriptor
+{
+ /* internal class of the record */
+ enum record_class rclass;
+ /*
+ length for fixed-size record, pseudo-fixed record
+ length with uncompressed LSNs
+ */
+ uint16 fixed_length;
+ /* how much record body (belonged to headers too) read with headers */
+ uint16 read_header_len;
+ /* HOOK for writing the record called before lock */
+ prewrite_rec_hook prewrite_hook;
+ /* HOOK for writing the record called when LSN is known, inside lock */
+ inwrite_rec_hook inwrite_hook;
+ /* HOOK for reading headers */
+ read_rec_hook read_hook;
+ /*
+ For pseudo fixed records number of compressed LSNs followed by
+ system header
+ */
+ int16 compressed_LSN;
+ /* the rest is for maria_read_log & Recovery */
+ /** @brief for debug error messages or "maria_read_log" command-line tool */
+ const char *name;
+ enum enum_record_in_group record_in_group;
+ /* a function to execute when we see the record during the REDO phase */
+ int (*record_execute_in_redo_phase)(const TRANSLOG_HEADER_BUFFER *);
+ /* a function to execute when we see the record during the UNDO phase */
+ int (*record_execute_in_undo_phase)(const TRANSLOG_HEADER_BUFFER *, TRN *);
+} LOG_DESC;
+
+extern LOG_DESC log_record_type_descriptor[LOGREC_NUMBER_OF_TYPES];
+
+typedef enum
+{
+ TRANSLOG_PURGE_IMMIDIATE,
+ TRANSLOG_PURGE_EXTERNAL,
+ TRANSLOG_PURGE_ONDEMAND
+} enum_maria_translog_purge_type;
+extern ulong log_purge_type;
+extern ulong log_file_size;
+
+typedef enum
+{
+ TRANSLOG_SYNC_DIR_NEVER,
+ TRANSLOG_SYNC_DIR_NEWFILE,
+ TRANSLOG_SYNC_DIR_ALWAYS
+} enum_maria_sync_log_dir;
+extern ulong sync_log_dir;
+
+C_MODE_END
+#endif
diff --git a/storage/maria/ma_loghandler_lsn.h b/storage/maria/ma_loghandler_lsn.h
new file mode 100644
index 00000000000..7fa53bc0a50
--- /dev/null
+++ b/storage/maria/ma_loghandler_lsn.h
@@ -0,0 +1,111 @@
+/* Copyright (C) 2007 MySQL AB & Sanja Belkin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _ma_loghandler_lsn_h
+#define _ma_loghandler_lsn_h
+
+/*
+ Transaction log record address:
+ file_no << 32 | offset
+ file_no is only 3 bytes so we can use signed integer to make
+ comparison simpler.
+*/
+typedef int64 TRANSLOG_ADDRESS;
+
+/*
+ Compare addresses
+ A1 > A2 -> result > 0
+ A1 == A2 -> 0
+ A1 < A2 -> result < 0
+*/
+#define cmp_translog_addr(A1,A2) ((A1) - (A2))
+
+/*
+ TRANSLOG_ADDRESS is just address of some byte in the log (usually some
+ chunk)
+ LSN used where address of some record in the log needed (not just any
+ address)
+*/
+typedef TRANSLOG_ADDRESS LSN;
+
+/* Gets file number part of a LSN/log address */
+#define LSN_FILE_NO(L) (uint32) ((L) >> 32)
+
+/* Gets raw file number part of a LSN/log address */
+#define LSN_FILE_NO_PART(L) ((L) & ((int64)0xFFFFFF00000000LL))
+
+/* Parts of LSN for printing */
+#define LSN_IN_PARTS(L) (ulong)LSN_FILE_NO(L),(ulong)LSN_OFFSET(L)
+
+/* Gets record offset of a LSN/log address */
+#define LSN_OFFSET(L) (ulong) ((L) & 0xFFFFFFFFL)
+
+/* Makes lsn/log address from file number and record offset */
+#define MAKE_LSN(F,S) ((LSN) ((((uint64)(F)) << 32) | (S)))
+
+/* checks LSN */
+#define LSN_VALID(L) \
+ ((LSN_FILE_NO_PART(L) != FILENO_IMPOSSIBLE) && \
+ (LSN_OFFSET(L) != LOG_OFFSET_IMPOSSIBLE))
+
+/* size of stored LSN on a disk, don't change it! */
+#define LSN_STORE_SIZE 7
+
+/* Puts LSN into buffer (dst) */
+#define lsn_store(dst, lsn) \
+ do { \
+ int3store((dst), LSN_FILE_NO(lsn)); \
+ int4store((char*)(dst) + 3, LSN_OFFSET(lsn)); \
+ } while (0)
+
+/* Unpacks LSN from the buffer (P) */
+#define lsn_korr(P) MAKE_LSN(uint3korr(P), uint4korr((const char*)(P) + 3))
+
+/* what we need to add to LSN to increase it on one file */
+#define LSN_ONE_FILE ((int64)0x100000000LL)
+
+#define LSN_REPLACE_OFFSET(L, S) (LSN_FILE_NO_PART(L) | (S))
+
+/*
+ an 8-byte type whose most significant uchar is used for "flags"; 7
+ other bytes are a LSN.
+*/
+typedef LSN LSN_WITH_FLAGS;
+#define LSN_WITH_FLAGS_TO_LSN(x) (x & ULL(0x00FFFFFFFFFFFFFF))
+#define LSN_WITH_FLAGS_TO_FLAGS(x) (x & ULL(0xFF00000000000000))
+
+#define FILENO_IMPOSSIBLE 0 /**< log file's numbering starts at 1 */
+#define LOG_OFFSET_IMPOSSIBLE 0 /**< log always has a header */
+#define LSN_IMPOSSIBLE ((LSN)0)
+/* following LSN also is impossible */
+#define LSN_ERROR ((LSN)1)
+
+/** @brief some impossible LSN serve as markers */
+
+/**
+ When table is modified by maria_chk, or auto-zerofilled, old REDOs don't
+ apply, table is freshly born again somehow: its state's LSNs need to be
+ updated to the new instance which receives this table.
+*/
+#define LSN_NEEDS_NEW_STATE_LSNS ((LSN)2)
+
+/**
+ @brief the maximum valid LSN.
+ Unlike ULONGLONG_MAX, it can be safely used in comparison with valid LSNs
+ (ULONGLONG_MAX is too big for correctness of cmp_translog_addr()).
+*/
+#define LSN_MAX (LSN)ULL(0x00FFFFFFFFFFFFFF)
+
+#endif
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
new file mode 100644
index 00000000000..c6c786910db
--- /dev/null
+++ b/storage/maria/ma_open.c
@@ -0,0 +1,1913 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* open a isam-database */
+
+#include "ma_fulltext.h"
+#include "ma_sp_defs.h"
+#include "ma_rt_index.h"
+#include "ma_blockrec.h"
+#include <m_ctype.h>
+
+#if defined(MSDOS) || defined(__WIN__)
+#ifdef __WIN__
+#include <fcntl.h>
+#else
+#include <process.h> /* Prototype for getpid */
+#endif
+#endif
+
+static void setup_key_functions(MARIA_KEYDEF *keyinfo);
+static my_bool maria_scan_init_dummy(MARIA_HA *info);
+static void maria_scan_end_dummy(MARIA_HA *info);
+static my_bool maria_once_init_dummy(MARIA_SHARE *, File);
+static my_bool maria_once_end_dummy(MARIA_SHARE *);
+static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base);
+static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state);
+
+#define get_next_element(to,pos,size) { memcpy((char*) to,pos,(size_t) size); \
+ pos+=size;}
+
+
+#define disk_pos_assert(pos, end_pos) \
+if (pos > end_pos) \
+{ \
+ my_errno=HA_ERR_CRASHED; \
+ goto err; \
+}
+
+
+/******************************************************************************
+** Return the shared struct if the table is already open.
+** In MySQL the server will handle version issues.
+******************************************************************************/
+
+MARIA_HA *_ma_test_if_reopen(const char *filename)
+{
+ LIST *pos;
+
+ for (pos=maria_open_list ; pos ; pos=pos->next)
+ {
+ MARIA_HA *info=(MARIA_HA*) pos->data;
+ MARIA_SHARE *share= info->s;
+ if (!strcmp(share->unique_file_name.str,filename) && share->last_version)
+ return info;
+ }
+ return 0;
+}
+
+
+/*
+ Open a new instance of an already opened Maria table
+
+ SYNOPSIS
+ maria_clone_internal()
+ share Share of already open table
+ mode Mode of table (O_RDONLY | O_RDWR)
+ data_file Filedescriptor of data file to use < 0 if one should open
+ open it.
+
+ RETURN
+ # Maria handler
+ 0 Error
+*/
+
+
+static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, const char *name,
+ int mode, File data_file)
+{
+ int save_errno;
+ uint errpos;
+ MARIA_HA info,*m_info;
+ my_bitmap_map *changed_fields_bitmap;
+ DBUG_ENTER("maria_clone_internal");
+
+ errpos= 0;
+ bzero((uchar*) &info,sizeof(info));
+
+ if (mode == O_RDWR && share->mode == O_RDONLY)
+ {
+ my_errno=EACCES; /* Can't open in write mode */
+ goto err;
+ }
+ if (data_file >= 0)
+ info.dfile.file= data_file;
+ else if (_ma_open_datafile(&info, share, name, -1))
+ goto err;
+ errpos= 5;
+
+ /* alloc and set up private structure parts */
+ if (!my_multi_malloc(MY_WME,
+ &m_info,sizeof(MARIA_HA),
+ &info.blobs,sizeof(MARIA_BLOB)*share->base.blobs,
+ &info.buff,(share->base.max_key_block_length*2+
+ share->base.max_key_length),
+ &info.lastkey_buff,share->base.max_key_length*2+1,
+ &info.first_mbr_key, share->base.max_key_length,
+ &info.maria_rtree_recursion_state,
+ share->have_rtree ? 1024 : 0,
+ &changed_fields_bitmap,
+ bitmap_buffer_size(share->base.fields),
+ NullS))
+ goto err;
+ errpos= 6;
+
+ memcpy(info.blobs,share->blobs,sizeof(MARIA_BLOB)*share->base.blobs);
+ info.lastkey_buff2= info.lastkey_buff + share->base.max_key_length;
+ info.last_key.data= info.lastkey_buff;
+
+ info.s=share;
+ info.cur_row.lastpos= HA_OFFSET_ERROR;
+ info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
+ info.opt_flag=READ_CHECK_USED;
+ info.this_unique= (ulong) info.dfile.file; /* Uniq number in process */
+#ifdef EXTERNAL_LOCKING
+ if (share->data_file_type == COMPRESSED_RECORD)
+ info.this_unique= share->state.unique;
+ info.this_loop=0; /* Update counter */
+ info.last_unique= share->state.unique;
+ info.last_loop= share->state.update_count;
+#endif
+ info.errkey= -1;
+ info.page_changed=1;
+ info.keyread_buff= info.buff + share->base.max_key_block_length;
+
+ info.lock_type= F_UNLCK;
+ if (share->options & HA_OPTION_TMP_TABLE)
+ info.lock_type= F_WRLCK;
+
+ _ma_set_data_pagecache_callbacks(&info.dfile, share);
+ bitmap_init(&info.changed_fields, changed_fields_bitmap,
+ share->base.fields, 0);
+ if ((*share->init)(&info))
+ goto err;
+
+ /* The following should be big enough for all pinning purposes */
+ if (my_init_dynamic_array(&info.pinned_pages,
+ sizeof(MARIA_PINNED_PAGE),
+ max(share->base.blobs*2 + 4,
+ MARIA_MAX_TREE_LEVELS*3), 16))
+ goto err;
+
+
+ pthread_mutex_lock(&share->intern_lock);
+ info.read_record= share->read_record;
+ share->reopen++;
+ share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ info.lock_type=F_RDLCK;
+ share->r_locks++;
+ share->tot_locks++;
+ }
+ if ((share->options & HA_OPTION_DELAY_KEY_WRITE) &&
+ maria_delay_key_write)
+ share->delay_key_write=1;
+
+ if (!share->base.born_transactional) /* For transactional ones ... */
+ {
+ /* ... force crash if no trn given */
+ _ma_set_trn_for_table(&info, &dummy_transaction_object);
+ info.state= &share->state.state; /* Change global values by default */
+ }
+ else
+ {
+ info.state= &share->state.common;
+ *info.state= share->state.state; /* Initial values */
+ }
+ info.state_start= info.state; /* Initial values */
+
+ pthread_mutex_unlock(&share->intern_lock);
+
+ /* Allocate buffer for one record */
+ /* prerequisites: info->rec_buffer == 0 && info->rec_buff_size == 0 */
+ if (_ma_alloc_buffer(&info.rec_buff, &info.rec_buff_size,
+ share->base.default_rec_buff_size))
+ goto err;
+
+ bzero(info.rec_buff, share->base.default_rec_buff_size);
+
+ *m_info=info;
+#ifdef THREAD
+ thr_lock_data_init(&share->lock,&m_info->lock,(void*) m_info);
+#endif
+ m_info->open_list.data=(void*) m_info;
+ maria_open_list=list_add(maria_open_list,&m_info->open_list);
+
+ DBUG_RETURN(m_info);
+
+err:
+ save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
+ if ((save_errno == HA_ERR_CRASHED) ||
+ (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
+ (save_errno == HA_ERR_CRASHED_ON_REPAIR))
+ _ma_report_error(save_errno, &share->open_file_name);
+ switch (errpos) {
+ case 6:
+ (*share->end)(&info);
+ delete_dynamic(&info.pinned_pages);
+ my_free(m_info, MYF(0));
+ /* fall through */
+ case 5:
+ if (data_file < 0)
+ VOID(my_close(info.dfile.file, MYF(0)));
+ break;
+ }
+ my_errno=save_errno;
+ DBUG_RETURN (NULL);
+} /* maria_clone_internal */
+
+
+/* Make a clone of a maria table */
+
+MARIA_HA *maria_clone(MARIA_SHARE *share, int mode)
+{
+ MARIA_HA *new_info;
+ pthread_mutex_lock(&THR_LOCK_maria);
+ new_info= maria_clone_internal(share, NullS, mode,
+ share->data_file_type == BLOCK_RECORD ?
+ share->bitmap.file.file : -1);
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ return new_info;
+}
+
+
+/******************************************************************************
+ open a MARIA table
+
+ See my_base.h for the handle_locking argument
+ if handle_locking and HA_OPEN_ABORT_IF_CRASHED then abort if the table
+ is marked crashed or if we are not using locking and the table doesn't
+ have an open count of 0.
+******************************************************************************/
+
+MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
+{
+ int kfile,open_mode,save_errno;
+ uint i,j,len,errpos,head_length,base_pos,info_length,keys, realpath_err,
+ key_parts,unique_key_parts,fulltext_keys,uniques;
+ char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN],
+ data_name[FN_REFLEN];
+ uchar *disk_cache, *disk_pos, *end_pos;
+ MARIA_HA info,*m_info,*old_info;
+ MARIA_SHARE share_buff,*share;
+ double rec_per_key_part[HA_MAX_POSSIBLE_KEY*HA_MAX_KEY_SEG];
+ ulong nulls_per_key_part[HA_MAX_POSSIBLE_KEY*HA_MAX_KEY_SEG];
+ my_off_t key_root[HA_MAX_POSSIBLE_KEY];
+ ulonglong max_key_file_length, max_data_file_length;
+ my_bool versioning= 1;
+ File data_file= -1;
+ DBUG_ENTER("maria_open");
+
+ LINT_INIT(m_info);
+ kfile= -1;
+ errpos= 0;
+ head_length=sizeof(share_buff.state.header);
+ bzero((uchar*) &info,sizeof(info));
+
+ realpath_err= my_realpath(name_buff, fn_format(org_name, name, "",
+ MARIA_NAME_IEXT,
+ MY_UNPACK_FILENAME),MYF(0));
+ if (my_is_symlink(org_name) &&
+ (realpath_err || (*maria_test_invalid_symlink)(name_buff)))
+ {
+ my_errno= HA_WRONG_CREATE_OPTION;
+ DBUG_RETURN(0);
+ }
+
+ pthread_mutex_lock(&THR_LOCK_maria);
+ old_info= 0;
+ if ((open_flags & HA_OPEN_COPY) ||
+ !(old_info=_ma_test_if_reopen(name_buff)))
+ {
+ share= &share_buff;
+ bzero((uchar*) &share_buff,sizeof(share_buff));
+ share_buff.state.rec_per_key_part= rec_per_key_part;
+ share_buff.state.nulls_per_key_part= nulls_per_key_part;
+ share_buff.state.key_root=key_root;
+ share_buff.pagecache= multi_pagecache_search((uchar*) name_buff,
+ (uint) strlen(name_buff),
+ maria_pagecache);
+
+ DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_open",
+ if (strstr(name, "/t1"))
+ {
+ my_errno= HA_ERR_CRASHED;
+ goto err;
+ });
+ if ((kfile=my_open(name_buff,(open_mode=O_RDWR) | O_SHARE,MYF(0))) < 0)
+ {
+ if ((errno != EROFS && errno != EACCES) ||
+ mode != O_RDONLY ||
+ (kfile=my_open(name_buff,(open_mode=O_RDONLY) | O_SHARE,MYF(0))) < 0)
+ goto err;
+ }
+ share->mode=open_mode;
+ errpos= 1;
+ if (my_pread(kfile,share->state.header.file_version, head_length, 0,
+ MYF(MY_NABP)))
+ {
+ my_errno= HA_ERR_NOT_A_TABLE;
+ goto err;
+ }
+ if (memcmp((uchar*) share->state.header.file_version,
+ (uchar*) maria_file_magic, 4))
+ {
+ DBUG_PRINT("error",("Wrong header in %s",name_buff));
+ DBUG_DUMP("error_dump", share->state.header.file_version,
+ head_length);
+ my_errno=HA_ERR_NOT_A_TABLE;
+ goto err;
+ }
+ share->options= mi_uint2korr(share->state.header.options);
+ if (share->options &
+ ~(HA_OPTION_PACK_RECORD | HA_OPTION_PACK_KEYS |
+ HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
+ HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
+ HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
+ HA_OPTION_RELIES_ON_SQL_LAYER | HA_OPTION_NULL_FIELDS |
+ HA_OPTION_PAGE_CHECKSUM))
+ {
+ DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
+ my_errno=HA_ERR_NEW_FILE;
+ goto err;
+ }
+ if ((share->options & HA_OPTION_RELIES_ON_SQL_LAYER) &&
+ ! (open_flags & HA_OPEN_FROM_SQL_LAYER))
+ {
+ DBUG_PRINT("error", ("table cannot be opened from non-sql layer"));
+ my_errno= HA_ERR_UNSUPPORTED;
+ goto err;
+ }
+ /* Don't call realpath() if the name can't be a link */
+ if (!strcmp(name_buff, org_name) ||
+ my_readlink(index_name, org_name, MYF(0)) == -1)
+ (void) strmov(index_name, org_name);
+ *strrchr(org_name, FN_EXTCHAR)= '\0';
+ (void) fn_format(data_name,org_name,"",MARIA_NAME_DEXT,
+ MY_APPEND_EXT|MY_UNPACK_FILENAME|MY_RESOLVE_SYMLINKS);
+
+ info_length=mi_uint2korr(share->state.header.header_length);
+ base_pos= mi_uint2korr(share->state.header.base_pos);
+ if (!(disk_cache= (uchar*) my_alloca(info_length+128)))
+ {
+ my_errno=ENOMEM;
+ goto err;
+ }
+ end_pos=disk_cache+info_length;
+ errpos= 3;
+ if (my_pread(kfile, disk_cache, info_length, 0L, MYF(MY_NABP)))
+ {
+ my_errno=HA_ERR_CRASHED;
+ goto err;
+ }
+ len=mi_uint2korr(share->state.header.state_info_length);
+ keys= (uint) share->state.header.keys;
+ uniques= (uint) share->state.header.uniques;
+ fulltext_keys= (uint) share->state.header.fulltext_keys;
+ key_parts= mi_uint2korr(share->state.header.key_parts);
+ unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts);
+ if (len != MARIA_STATE_INFO_SIZE)
+ {
+ DBUG_PRINT("warning",
+ ("saved_state_info_length: %d state_info_length: %d",
+ len,MARIA_STATE_INFO_SIZE));
+ }
+ share->state_diff_length=len-MARIA_STATE_INFO_SIZE;
+
+ _ma_state_info_read(disk_cache, &share->state);
+ len= mi_uint2korr(share->state.header.base_info_length);
+ if (len != MARIA_BASE_INFO_SIZE)
+ {
+ DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
+ len,MARIA_BASE_INFO_SIZE));
+ }
+ disk_pos= _ma_base_info_read(disk_cache + base_pos, &share->base);
+ share->state.state_length=base_pos;
+
+ if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
+ ((share->state.changed & STATE_CRASHED) ||
+ ((open_flags & HA_OPEN_ABORT_IF_CRASHED) &&
+ (my_disable_locking && share->state.open_count))))
+ {
+ DBUG_PRINT("error",("Table is marked as crashed. open_flags: %u "
+ "changed: %u open_count: %u !locking: %d",
+ open_flags, share->state.changed,
+ share->state.open_count, my_disable_locking));
+ my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
+ HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
+ goto err;
+ }
+
+ /*
+ We can ignore testing uuid if STATE_NOT_MOVABLE is set, as in this
+ case the uuid will be set in _ma_mark_file_changed()
+ */
+ if ((share->state.changed & STATE_NOT_MOVABLE) &&
+ share->base.born_transactional &&
+ ((!(open_flags & HA_OPEN_IGNORE_MOVED_STATE) &&
+ memcmp(share->base.uuid, maria_uuid, MY_UUID_SIZE)) ||
+ share->state.create_trid > trnman_get_max_trid()))
+ {
+ if (open_flags & HA_OPEN_FOR_REPAIR)
+ share->state.changed|= STATE_MOVED;
+ else
+ {
+ my_errno= HA_ERR_OLD_FILE;
+ goto err;
+ }
+ }
+
+ /* sanity check */
+ if (share->base.keystart > 65535 || share->base.rec_reflength > 8)
+ {
+ my_errno=HA_ERR_CRASHED;
+ goto err;
+ }
+
+ key_parts+=fulltext_keys*FT_SEGS;
+ if (share->base.max_key_length > maria_max_key_length() ||
+ keys > MARIA_MAX_KEY || key_parts > MARIA_MAX_KEY * HA_MAX_KEY_SEG)
+ {
+ DBUG_PRINT("error",("Wrong key info: Max_key_length: %d keys: %d key_parts: %d", share->base.max_key_length, keys, key_parts));
+ my_errno=HA_ERR_UNSUPPORTED;
+ goto err;
+ }
+
+ /* Ensure we have space in the key buffer for transaction id's */
+ if (share->base.born_transactional)
+ share->base.max_key_length= ALIGN_SIZE(share->base.max_key_length +
+ MARIA_MAX_PACK_TRANSID_SIZE);
+
+ /*
+ If page cache is not initialized, then assume we will create the
+ page_cache after the table is opened!
+ This is only used by maria_check to allow it to check/repair tables
+ with different block sizes.
+ */
+ if (share->base.block_size != maria_block_size &&
+ share_buff.pagecache->inited != 0)
+ {
+ DBUG_PRINT("error", ("Wrong block size %u; Expected %u",
+ (uint) share->base.block_size,
+ (uint) maria_block_size));
+ my_errno=HA_ERR_UNSUPPORTED;
+ goto err;
+ }
+
+ /* Correct max_file_length based on length of sizeof(off_t) */
+ max_data_file_length=
+ (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
+ (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
+ (_ma_safe_mul(share->base.pack_reclength,
+ (ulonglong) 1 << (share->base.rec_reflength*8))-1);
+
+ max_key_file_length=
+ _ma_safe_mul(maria_block_size,
+ ((ulonglong) 1 << (share->base.key_reflength*8))-1);
+#if SIZEOF_OFF_T == 4
+ set_if_smaller(max_data_file_length, INT_MAX32);
+ set_if_smaller(max_key_file_length, INT_MAX32);
+#endif
+ share->base.max_data_file_length=(my_off_t) max_data_file_length;
+ share->base.max_key_file_length=(my_off_t) max_key_file_length;
+
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ share->base.max_key_length+=2; /* For safety */
+ /* Add space for node pointer */
+ share->base.max_key_length+= share->base.key_reflength;
+
+ share->unique_file_name.length= strlen(name_buff);
+ share->index_file_name.length= strlen(index_name);
+ share->data_file_name.length= strlen(data_name);
+ share->open_file_name.length= strlen(name);
+ if (!my_multi_malloc(MY_WME,
+ &share,sizeof(*share),
+ &share->state.rec_per_key_part,
+ sizeof(double) * key_parts,
+ &share->state.nulls_per_key_part,
+ sizeof(long)* key_parts,
+ &share->keyinfo,keys*sizeof(MARIA_KEYDEF),
+ &share->uniqueinfo,uniques*sizeof(MARIA_UNIQUEDEF),
+ &share->keyparts,
+ (key_parts+unique_key_parts+keys+uniques) *
+ sizeof(HA_KEYSEG),
+ &share->columndef,
+ (share->base.fields+1)*sizeof(MARIA_COLUMNDEF),
+ &share->column_nr, share->base.fields*sizeof(uint16),
+ &share->blobs,sizeof(MARIA_BLOB)*share->base.blobs,
+ &share->unique_file_name.str,
+ share->unique_file_name.length+1,
+ &share->index_file_name.str,
+ share->index_file_name.length+1,
+ &share->data_file_name.str,
+ share->data_file_name.length+1,
+ &share->open_file_name.str,
+ share->open_file_name.length+1,
+ &share->state.key_root,keys*sizeof(my_off_t),
+ &share->mmap_lock,sizeof(rw_lock_t),
+ NullS))
+ goto err;
+ errpos= 4;
+
+ *share=share_buff;
+ memcpy((char*) share->state.rec_per_key_part,
+ (char*) rec_per_key_part, sizeof(double)*key_parts);
+ memcpy((char*) share->state.nulls_per_key_part,
+ (char*) nulls_per_key_part, sizeof(long)*key_parts);
+ memcpy((char*) share->state.key_root,
+ (char*) key_root, sizeof(my_off_t)*keys);
+ strmov(share->unique_file_name.str, name_buff);
+ strmov(share->index_file_name.str, index_name);
+ strmov(share->data_file_name.str, data_name);
+ strmov(share->open_file_name.str, name);
+
+ share->block_size= share->base.block_size; /* Convenience */
+ {
+ HA_KEYSEG *pos=share->keyparts;
+ for (i=0 ; i < keys ; i++)
+ {
+ share->keyinfo[i].share= share;
+ disk_pos=_ma_keydef_read(disk_pos, &share->keyinfo[i]);
+ share->keyinfo[i].key_nr= i;
+ disk_pos_assert(disk_pos + share->keyinfo[i].keysegs * HA_KEYSEG_SIZE,
+ end_pos);
+ if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE)
+ share->have_rtree= 1;
+ share->keyinfo[i].seg=pos;
+ for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
+ {
+ disk_pos=_ma_keyseg_read(disk_pos, pos);
+ if (pos->type == HA_KEYTYPE_TEXT ||
+ pos->type == HA_KEYTYPE_VARTEXT1 ||
+ pos->type == HA_KEYTYPE_VARTEXT2)
+ {
+ if (!pos->language)
+ pos->charset=default_charset_info;
+ else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
+ {
+ my_errno=HA_ERR_UNKNOWN_CHARSET;
+ goto err;
+ }
+ }
+ else if (pos->type == HA_KEYTYPE_BINARY)
+ pos->charset= &my_charset_bin;
+ }
+ if (share->keyinfo[i].flag & HA_SPATIAL)
+ {
+#ifdef HAVE_SPATIAL
+ uint sp_segs=SPDIMS*2;
+ share->keyinfo[i].seg=pos-sp_segs;
+ share->keyinfo[i].keysegs--;
+ versioning= 0;
+#else
+ my_errno=HA_ERR_UNSUPPORTED;
+ goto err;
+#endif
+ }
+ else if (share->keyinfo[i].flag & HA_FULLTEXT)
+ {
+ versioning= 0;
+ DBUG_ASSERT(fulltext_keys);
+ {
+ uint k;
+ share->keyinfo[i].seg=pos;
+ for (k=0; k < FT_SEGS; k++)
+ {
+ *pos= ft_keysegs[k];
+ pos[0].language= pos[-1].language;
+ if (!(pos[0].charset= pos[-1].charset))
+ {
+ my_errno=HA_ERR_CRASHED;
+ goto err;
+ }
+ pos++;
+ }
+ }
+ if (!share->ft2_keyinfo.seg)
+ {
+ memcpy(&share->ft2_keyinfo, &share->keyinfo[i],
+ sizeof(MARIA_KEYDEF));
+ share->ft2_keyinfo.keysegs=1;
+ share->ft2_keyinfo.flag=0;
+ share->ft2_keyinfo.keylength=
+ share->ft2_keyinfo.minlength=
+ share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength;
+ share->ft2_keyinfo.seg=pos-1;
+ share->ft2_keyinfo.end=pos;
+ setup_key_functions(& share->ft2_keyinfo);
+ }
+ }
+ setup_key_functions(share->keyinfo+i);
+ share->keyinfo[i].end=pos;
+ pos->type=HA_KEYTYPE_END; /* End */
+ pos->length=share->base.rec_reflength;
+ pos->null_bit=0;
+ pos->flag=0; /* For purify */
+ pos++;
+ }
+ for (i=0 ; i < uniques ; i++)
+ {
+ disk_pos=_ma_uniquedef_read(disk_pos, &share->uniqueinfo[i]);
+ disk_pos_assert(disk_pos + share->uniqueinfo[i].keysegs *
+ HA_KEYSEG_SIZE, end_pos);
+ share->uniqueinfo[i].seg=pos;
+ for (j=0 ; j < share->uniqueinfo[i].keysegs; j++,pos++)
+ {
+ disk_pos=_ma_keyseg_read(disk_pos, pos);
+ if (pos->type == HA_KEYTYPE_TEXT ||
+ pos->type == HA_KEYTYPE_VARTEXT1 ||
+ pos->type == HA_KEYTYPE_VARTEXT2)
+ {
+ if (!pos->language)
+ pos->charset=default_charset_info;
+ else if (!(pos->charset= get_charset(pos->language, MYF(MY_WME))))
+ {
+ my_errno=HA_ERR_UNKNOWN_CHARSET;
+ goto err;
+ }
+ }
+ }
+ share->uniqueinfo[i].end=pos;
+ pos->type=HA_KEYTYPE_END; /* End */
+ pos->null_bit=0;
+ pos->flag=0;
+ pos++;
+ }
+ share->ftparsers= 0;
+ }
+ share->data_file_type= share->state.header.data_file_type;
+ share->base_length= (BASE_ROW_HEADER_SIZE +
+ share->base.is_nulls_extended +
+ share->base.null_bytes +
+ share->base.pack_bytes +
+ test(share->options & HA_OPTION_CHECKSUM));
+ share->keypage_header= ((share->base.born_transactional ?
+ LSN_STORE_SIZE + TRANSID_SIZE :
+ 0) + KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE +
+ KEYPAGE_USED_SIZE);
+ share->kfile.file= kfile;
+
+ if (open_flags & HA_OPEN_COPY)
+ {
+ /*
+ this instance will be a temporary one used just to create a data
+ file for REPAIR. Don't do logging. This base information will not go
+ to disk.
+ */
+ share->base.born_transactional= FALSE;
+ }
+ if (share->base.born_transactional)
+ {
+ share->page_type= PAGECACHE_LSN_PAGE;
+ if (share->state.create_rename_lsn == LSN_NEEDS_NEW_STATE_LSNS)
+ {
+ /*
+ Was repaired with maria_chk, maybe later maria_pack-ed. Some sort of
+ import into the server. It starts its existence (from the point of
+ view of the server, including server's recovery) now.
+ */
+ if (((open_flags & HA_OPEN_FROM_SQL_LAYER) &&
+ (share->state.changed & STATE_NOT_MOVABLE)) || maria_in_recovery)
+ _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE,
+ trnman_get_min_safe_trid(), TRUE, TRUE);
+ }
+ else if ((!LSN_VALID(share->state.create_rename_lsn) ||
+ !LSN_VALID(share->state.is_of_horizon) ||
+ (cmp_translog_addr(share->state.create_rename_lsn,
+ share->state.is_of_horizon) > 0) ||
+ !LSN_VALID(share->state.skip_redo_lsn) ||
+ (cmp_translog_addr(share->state.create_rename_lsn,
+ share->state.skip_redo_lsn) > 0)) &&
+ !(open_flags & HA_OPEN_FOR_REPAIR))
+ {
+ /*
+ If in Recovery, it will not work. If LSN is invalid and not
+ LSN_NEEDS_NEW_STATE_LSNS, header must be corrupted.
+ In both cases, must repair.
+ */
+ my_errno=((share->state.changed & STATE_CRASHED_ON_REPAIR) ?
+ HA_ERR_CRASHED_ON_REPAIR : HA_ERR_CRASHED_ON_USAGE);
+ goto err;
+ }
+ }
+ else
+ share->page_type= PAGECACHE_PLAIN_PAGE;
+ share->now_transactional= share->base.born_transactional;
+
+ /* Use pack_reclength as we don't want to modify base.pack_recklength */
+ if (share->state.header.org_data_file_type == DYNAMIC_RECORD)
+ {
+ /* add bits used to pack data to pack_reclength for faster allocation */
+ share->base.pack_reclength+= share->base.pack_bytes;
+ share->base.extra_rec_buff_size=
+ (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER) + MARIA_SPLIT_LENGTH +
+ MARIA_REC_BUFF_OFFSET);
+ }
+ if (share->data_file_type == COMPRESSED_RECORD)
+ {
+ /* Need some extra bytes for decode_bytes */
+ share->base.extra_rec_buff_size+= 7;
+ }
+ share->base.default_rec_buff_size= max(share->base.pack_reclength +
+ share->base.extra_rec_buff_size,
+ share->base.max_key_length);
+
+ disk_pos_assert(disk_pos + share->base.fields *MARIA_COLUMNDEF_SIZE,
+ end_pos);
+ for (i= j= 0 ; i < share->base.fields ; i++)
+ {
+ disk_pos=_ma_columndef_read(disk_pos,&share->columndef[i]);
+ share->columndef[i].pack_type=0;
+ share->columndef[i].huff_tree=0;
+ if (share->columndef[i].type == FIELD_BLOB)
+ {
+ share->blobs[j].pack_length=
+ share->columndef[i].length-portable_sizeof_char_ptr;
+ share->blobs[j].offset= share->columndef[i].offset;
+ j++;
+ }
+ }
+ share->columndef[i].type= FIELD_LAST; /* End marker */
+ disk_pos= _ma_column_nr_read(disk_pos, share->column_nr,
+ share->base.fields);
+
+ if ((share->data_file_type == BLOCK_RECORD ||
+ share->data_file_type == COMPRESSED_RECORD))
+ {
+ if (_ma_open_datafile(&info, share, name, -1))
+ goto err;
+ data_file= info.dfile.file;
+ }
+ errpos= 5;
+
+ if (open_flags & HA_OPEN_DELAY_KEY_WRITE)
+ share->options|= HA_OPTION_DELAY_KEY_WRITE;
+ if (mode == O_RDONLY)
+ share->options|= HA_OPTION_READ_ONLY_DATA;
+ share->is_log_table= FALSE;
+
+ if (open_flags & HA_OPEN_TMP_TABLE)
+ {
+ share->options|= HA_OPTION_TMP_TABLE;
+ share->temporary= share->delay_key_write= 1;
+ share->write_flag=MYF(MY_NABP);
+ share->w_locks++; /* We don't have to update status */
+ share->tot_locks++;
+ }
+
+ _ma_set_index_pagecache_callbacks(&share->kfile, share);
+ share->this_process=(ulong) getpid();
+#ifdef EXTERNAL_LOCKING
+ share->last_process= share->state.process;
+#endif
+ share->base.key_parts=key_parts;
+ share->base.all_key_parts=key_parts+unique_key_parts;
+ if (!(share->last_version=share->state.version))
+ share->last_version=1; /* Safety */
+ share->rec_reflength=share->base.rec_reflength; /* May be changed */
+ share->base.margin_key_file_length=(share->base.max_key_file_length -
+ (keys ? MARIA_INDEX_BLOCK_MARGIN *
+ share->block_size * keys : 0));
+ share->block_size= share->base.block_size;
+ my_afree(disk_cache);
+ _ma_setup_functions(share);
+ if ((*share->once_init)(share, info.dfile.file))
+ goto err;
+ if (share->now_transactional)
+ {
+ /* Setup initial state that is visible for all */
+ MARIA_STATE_HISTORY_CLOSED *history;
+ if ((history= (MARIA_STATE_HISTORY_CLOSED *)
+ hash_search(&maria_stored_state,
+ (uchar*) &share->state.create_rename_lsn, 0)))
+ {
+ /*
+ Move history from hash to share. This is safe to do as we
+ don't have a lock on share->intern_lock.
+ */
+ share->state_history=
+ _ma_remove_not_visible_states(history->state_history, 0, 0);
+ history->state_history= 0;
+ (void) hash_delete(&maria_stored_state, (uchar*) history);
+ }
+ else
+ {
+ /* Table is not part of any active transaction; Create new history */
+ if (!(share->state_history= (MARIA_STATE_HISTORY *)
+ my_malloc(sizeof(*share->state_history), MYF(MY_WME))))
+ goto err;
+ share->state_history->trid= 0; /* Visible by all */
+ share->state_history->state= share->state.state;
+ share->state_history->next= 0;
+ }
+ }
+#ifdef THREAD
+ thr_lock_init(&share->lock);
+ pthread_mutex_init(&share->intern_lock, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&share->key_del_lock, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&share->key_del_cond, 0);
+ pthread_mutex_init(&share->close_lock, MY_MUTEX_INIT_FAST);
+ for (i=0; i<keys; i++)
+ VOID(my_rwlock_init(&share->keyinfo[i].root_lock, NULL));
+ VOID(my_rwlock_init(&share->mmap_lock, NULL));
+
+ share->row_is_visible= _ma_row_visible_always;
+ share->lock.get_status= _ma_reset_update_flag;
+ if (!thr_lock_inited)
+ {
+ /* Probably a single threaded program; Don't use concurrent inserts */
+ maria_concurrent_insert=0;
+ }
+ else if (maria_concurrent_insert)
+ {
+ share->non_transactional_concurrent_insert=
+ ((share->options & (HA_OPTION_READ_ONLY_DATA | HA_OPTION_TMP_TABLE |
+ HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD)) ||
+ (open_flags & HA_OPEN_TMP_TABLE) ||
+ share->data_file_type == BLOCK_RECORD ||
+ share->have_rtree) ? 0 : 1;
+ if (share->non_transactional_concurrent_insert ||
+ (!share->temporary && share->now_transactional && versioning))
+ {
+ share->lock_key_trees= 1;
+ if (share->data_file_type == BLOCK_RECORD)
+ {
+ DBUG_ASSERT(share->now_transactional);
+ share->have_versioning= 1;
+ share->row_is_visible= _ma_row_visible_transactional_table;
+ share->lock.get_status= _ma_block_get_status;
+ share->lock.update_status= _ma_block_update_status;
+ share->lock.check_status= _ma_block_check_status;
+ /*
+ We can for the moment only allow multiple concurrent inserts
+ only if there is no auto-increment key. To lift this restriction
+ we have to:
+ - Extend statement base replication to support auto-increment
+ intervalls.
+ - Fix that we allocate auto-increment in intervals and that
+ it's properly reset if the interval was not used
+ */
+ share->lock.allow_multiple_concurrent_insert=
+ share->base.auto_key == 0;
+ share->lock_restore_status= 0;
+ }
+ else
+ {
+ share->row_is_visible= _ma_row_visible_non_transactional_table;
+ share->lock.get_status= _ma_get_status;
+ share->lock.copy_status= _ma_copy_status;
+ share->lock.update_status= _ma_update_status;
+ share->lock.restore_status= _ma_restore_status;
+ share->lock.check_status= _ma_check_status;
+ share->lock_restore_status= _ma_restore_status;
+ }
+ }
+ }
+#endif
+ /*
+ Memory mapping can only be requested after initializing intern_lock.
+ */
+ if (open_flags & HA_OPEN_MMAP)
+ {
+ info.s= share;
+ maria_extra(&info, HA_EXTRA_MMAP, 0);
+ }
+ }
+ else
+ {
+ share= old_info->s;
+ if (share->data_file_type == BLOCK_RECORD)
+ data_file= share->bitmap.file.file; /* Only opened once */
+ }
+
+ if (!(m_info= maria_clone_internal(share, name, mode, data_file)))
+ goto err;
+
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ DBUG_RETURN(m_info);
+
+err:
+ save_errno=my_errno ? my_errno : HA_ERR_END_OF_FILE;
+ if ((save_errno == HA_ERR_CRASHED) ||
+ (save_errno == HA_ERR_CRASHED_ON_USAGE) ||
+ (save_errno == HA_ERR_CRASHED_ON_REPAIR))
+ {
+ LEX_STRING tmp_name;
+ tmp_name.str= (char*) name;
+ tmp_name.length= strlen(name);
+ _ma_report_error(save_errno, &tmp_name);
+ }
+ if (save_errno == HA_ERR_OLD_FILE) /* uuid is different ? */
+ save_errno= HA_ERR_CRASHED_ON_USAGE; /* the code to trigger auto-repair */
+ switch (errpos) {
+ case 5:
+ if (data_file >= 0)
+ VOID(my_close(data_file, MYF(0)));
+ if (old_info)
+ break; /* Don't remove open table */
+ (*share->once_end)(share);
+ /* fall through */
+ case 4:
+ my_free((uchar*) share,MYF(0));
+ /* fall through */
+ case 3:
+ /* fall through */
+ case 2:
+ my_afree((uchar*) disk_cache);
+ /* fall through */
+ case 1:
+ VOID(my_close(kfile,MYF(0)));
+ /* fall through */
+ case 0:
+ default:
+ break;
+ }
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ my_errno= save_errno;
+ DBUG_RETURN (NULL);
+} /* maria_open */
+
+
+/*
+ Reallocate a buffer, if the current buffer is not large enough
+*/
+
+my_bool _ma_alloc_buffer(uchar **old_addr, size_t *old_size,
+ size_t new_size)
+{
+ if (*old_size < new_size)
+ {
+ uchar *addr;
+ if (!(addr= (uchar*) my_realloc((uchar*) *old_addr, new_size,
+ MYF(MY_ALLOW_ZERO_PTR))))
+ return 1;
+ *old_addr= addr;
+ *old_size= new_size;
+ }
+ return 0;
+}
+
+
+ulonglong _ma_safe_mul(ulonglong a, ulonglong b)
+{
+ ulonglong max_val= ~ (ulonglong) 0; /* my_off_t is unsigned */
+
+ if (!a || max_val / a < b)
+ return max_val;
+ return a*b;
+}
+
+ /* Set up functions in structs */
+
+void _ma_setup_functions(register MARIA_SHARE *share)
+{
+ share->once_init= maria_once_init_dummy;
+ share->once_end= maria_once_end_dummy;
+ share->init= maria_scan_init_dummy;
+ share->end= maria_scan_end_dummy;
+ share->scan_init= maria_scan_init_dummy;/* Compat. dummy function */
+ share->scan_end= maria_scan_end_dummy;/* Compat. dummy function */
+ share->scan_remember_pos= _ma_def_scan_remember_pos;
+ share->scan_restore_pos= _ma_def_scan_restore_pos;
+
+ share->write_record_init= _ma_write_init_default;
+ share->write_record_abort= _ma_write_abort_default;
+ share->keypos_to_recpos= _ma_transparent_recpos;
+ share->recpos_to_keypos= _ma_transparent_recpos;
+
+ switch (share->data_file_type) {
+ case COMPRESSED_RECORD:
+ share->read_record= _ma_read_pack_record;
+ share->scan= _ma_read_rnd_pack_record;
+ share->once_init= _ma_once_init_pack_row;
+ share->once_end= _ma_once_end_pack_row;
+ /*
+ Calculate checksum according to data in the original, not compressed,
+ row.
+ */
+ if (share->state.header.org_data_file_type == STATIC_RECORD &&
+ ! (share->options & HA_OPTION_NULL_FIELDS))
+ share->calc_checksum= _ma_static_checksum;
+ else
+ share->calc_checksum= _ma_checksum;
+ share->calc_write_checksum= share->calc_checksum;
+ break;
+ case DYNAMIC_RECORD:
+ share->read_record= _ma_read_dynamic_record;
+ share->scan= _ma_read_rnd_dynamic_record;
+ share->delete_record= _ma_delete_dynamic_record;
+ share->compare_record= _ma_cmp_dynamic_record;
+ share->compare_unique= _ma_cmp_dynamic_unique;
+ share->calc_checksum= share->calc_write_checksum= _ma_checksum;
+ if (share->base.blobs)
+ {
+ share->update_record= _ma_update_blob_record;
+ share->write_record= _ma_write_blob_record;
+ }
+ else
+ {
+ share->write_record= _ma_write_dynamic_record;
+ share->update_record= _ma_update_dynamic_record;
+ }
+ break;
+ case STATIC_RECORD:
+ share->read_record= _ma_read_static_record;
+ share->scan= _ma_read_rnd_static_record;
+ share->delete_record= _ma_delete_static_record;
+ share->compare_record= _ma_cmp_static_record;
+ share->update_record= _ma_update_static_record;
+ share->write_record= _ma_write_static_record;
+ share->compare_unique= _ma_cmp_static_unique;
+ share->keypos_to_recpos= _ma_static_keypos_to_recpos;
+ share->recpos_to_keypos= _ma_static_recpos_to_keypos;
+ if (share->state.header.org_data_file_type == STATIC_RECORD &&
+ ! (share->options & HA_OPTION_NULL_FIELDS))
+ share->calc_checksum= _ma_static_checksum;
+ else
+ share->calc_checksum= _ma_checksum;
+ break;
+ case BLOCK_RECORD:
+ share->once_init= _ma_once_init_block_record;
+ share->once_end= _ma_once_end_block_record;
+ share->init= _ma_init_block_record;
+ share->end= _ma_end_block_record;
+ share->write_record_init= _ma_write_init_block_record;
+ share->write_record_abort= _ma_write_abort_block_record;
+ share->scan_init= _ma_scan_init_block_record;
+ share->scan_end= _ma_scan_end_block_record;
+ share->scan= _ma_scan_block_record;
+ share->scan_remember_pos= _ma_scan_remember_block_record;
+ share->scan_restore_pos= _ma_scan_restore_block_record;
+ share->read_record= _ma_read_block_record;
+ share->delete_record= _ma_delete_block_record;
+ share->compare_record= _ma_compare_block_record;
+ share->update_record= _ma_update_block_record;
+ share->write_record= _ma_write_block_record;
+ share->compare_unique= _ma_cmp_block_unique;
+ share->calc_checksum= _ma_checksum;
+ share->keypos_to_recpos= _ma_transaction_keypos_to_recpos;
+ share->recpos_to_keypos= _ma_transaction_recpos_to_keypos;
+
+ /*
+ write_block_record() will calculate the checksum; Tell maria_write()
+ that it doesn't have to do this.
+ */
+ share->calc_write_checksum= 0;
+ break;
+ }
+ share->file_read= _ma_nommap_pread;
+ share->file_write= _ma_nommap_pwrite;
+ share->calc_check_checksum= share->calc_checksum;
+
+ if (!(share->options & HA_OPTION_CHECKSUM) &&
+ share->data_file_type != COMPRESSED_RECORD)
+ share->calc_checksum= share->calc_write_checksum= 0;
+ return;
+}
+
+
+static void setup_key_functions(register MARIA_KEYDEF *keyinfo)
+{
+ if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
+ {
+#ifdef HAVE_RTREE_KEYS
+ keyinfo->ck_insert = maria_rtree_insert;
+ keyinfo->ck_delete = maria_rtree_delete;
+#else
+ DBUG_ASSERT(0); /* maria_open should check it never happens */
+#endif
+ }
+ else
+ {
+ keyinfo->ck_insert = _ma_ck_write;
+ keyinfo->ck_delete = _ma_ck_delete;
+ }
+ if (keyinfo->flag & HA_SPATIAL)
+ keyinfo->make_key= _ma_sp_make_key;
+ else
+ keyinfo->make_key= _ma_make_key;
+
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ { /* Simple prefix compression */
+ keyinfo->bin_search= _ma_seq_search;
+ keyinfo->get_key= _ma_get_binary_pack_key;
+ keyinfo->skip_key= _ma_skip_binary_pack_key;
+ keyinfo->pack_key= _ma_calc_bin_pack_key_length;
+ keyinfo->store_key= _ma_store_bin_pack_key;
+ }
+ else if (keyinfo->flag & HA_VAR_LENGTH_KEY)
+ {
+ keyinfo->get_key= _ma_get_pack_key;
+ keyinfo->skip_key= _ma_skip_pack_key;
+ if (keyinfo->seg[0].flag & HA_PACK_KEY)
+ { /* Prefix compression */
+ /*
+ _ma_prefix_search() compares end-space against ASCII blank (' ').
+ It cannot be used for character sets, that do not encode the
+ blank character like ASCII does. UCS2 is an example. All
+ character sets with a fixed width > 1 or a mimimum width > 1
+ cannot represent blank like ASCII does. In these cases we have
+ to use _ma_seq_search() for the search.
+ */
+ if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) ||
+ (keyinfo->seg->flag & HA_NULL_PART) ||
+ keyinfo->seg->charset->mbminlen > 1)
+ keyinfo->bin_search= _ma_seq_search;
+ else
+ keyinfo->bin_search= _ma_prefix_search;
+ keyinfo->pack_key= _ma_calc_var_pack_key_length;
+ keyinfo->store_key= _ma_store_var_pack_key;
+ }
+ else
+ {
+ keyinfo->bin_search= _ma_seq_search;
+ keyinfo->pack_key= _ma_calc_var_key_length; /* Variable length key */
+ keyinfo->store_key= _ma_store_static_key;
+ }
+ }
+ else
+ {
+ keyinfo->bin_search= _ma_bin_search;
+ keyinfo->get_key= _ma_get_static_key;
+ keyinfo->skip_key= _ma_skip_static_key;
+ keyinfo->pack_key= _ma_calc_static_key_length;
+ keyinfo->store_key= _ma_store_static_key;
+ }
+
+ /* set keyinfo->write_comp_flag */
+ if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
+ keyinfo->write_comp_flag=SEARCH_BIGGER; /* Put after same key */
+ else if (keyinfo->flag & ( HA_NOSAME | HA_FULLTEXT))
+ {
+ keyinfo->write_comp_flag= SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */
+ if (keyinfo->flag & HA_NULL_ARE_EQUAL)
+ keyinfo->write_comp_flag|= SEARCH_NULL_ARE_EQUAL;
+ }
+ else
+ keyinfo->write_comp_flag= SEARCH_SAME; /* Keys in rec-pos order */
+ keyinfo->write_comp_flag|= SEARCH_INSERT;
+ return;
+}
+
+
+/**
+ @brief Function to save and store the header in the index file (.MYI)
+
+ Operates under MARIA_SHARE::intern_lock if requested.
+ Sets MARIA_SHARE::MARIA_STATE_INFO::is_of_horizon if transactional table.
+ Then calls _ma_state_info_write_sub().
+
+ @param share table
+ @param pWrite bitmap: if 1 (MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)
+ is set my_pwrite() is used otherwise my_write();
+ if 2 (MA_STATE_INFO_WRITE_FULL_INFO) is set, info
+ about keys is written (should only be needed
+ after ALTER TABLE ENABLE/DISABLE KEYS, and
+ REPAIR/OPTIMIZE); if 4 (MA_STATE_INFO_WRITE_LOCK)
+ is set, MARIA_SHARE::intern_lock is taken.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite)
+{
+ uint res;
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ return 0;
+
+ if (pWrite & MA_STATE_INFO_WRITE_LOCK)
+ pthread_mutex_lock(&share->intern_lock);
+ else if (maria_multi_threaded)
+ {
+ safe_mutex_assert_owner(&share->intern_lock);
+ }
+ if (share->base.born_transactional && translog_status == TRANSLOG_OK &&
+ !maria_in_recovery)
+ {
+ /*
+ In a recovery, we want to set is_of_horizon to the LSN of the last
+ record executed by Recovery, not the current EOF of the log (which
+ is too new). Recovery does it by itself.
+ */
+ share->state.is_of_horizon= translog_get_horizon();
+ DBUG_PRINT("info", ("is_of_horizon set to LSN (%lu,0x%lx)",
+ LSN_IN_PARTS(share->state.is_of_horizon)));
+ }
+ res= _ma_state_info_write_sub(share->kfile.file, &share->state, pWrite);
+ if (pWrite & MA_STATE_INFO_WRITE_LOCK)
+ pthread_mutex_unlock(&share->intern_lock);
+ share->changed= 0;
+ return res;
+}
+
+
+/**
+ @brief Function to save and store the header in the index file (.MYI).
+
+ Shortcut to use instead of _ma_state_info_write() when appropriate.
+
+ @param file descriptor of the index file to write
+ @param state state information to write to the file
+ @param pWrite bitmap: if 1 (MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET)
+ is set my_pwrite() is used otherwise my_write();
+ if 2 (MA_STATE_INFO_WRITE_FULL_INFO) is set, info
+ about keys is written (should only be needed
+ after ALTER TABLE ENABLE/DISABLE KEYS, and
+ REPAIR/OPTIMIZE).
+
+ @notes
+ For transactional multiuser tables, this function is called
+ with intern_lock & translog_lock or when the last thread who
+ is using the table is closing it.
+ Because of the translog_lock we don't need to have a lock on
+ key_del_lock.
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+uint _ma_state_info_write_sub(File file, MARIA_STATE_INFO *state, uint pWrite)
+{
+ uchar buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
+ uchar *ptr=buff;
+ uint i, keys= (uint) state->header.keys;
+ size_t res;
+ DBUG_ENTER("_ma_state_info_write_sub");
+
+ memcpy_fixed(ptr,&state->header,sizeof(state->header));
+ ptr+=sizeof(state->header);
+
+ /* open_count must be first because of _ma_mark_file_changed ! */
+ mi_int2store(ptr,state->open_count); ptr+= 2;
+ /* changed must be second, because of _ma_mark_file_crashed */
+ mi_int2store(ptr,state->changed); ptr+= 2;
+
+ /*
+ If you change the offset of these LSNs, note that some functions do a
+ direct write of them without going through this function.
+ */
+ lsn_store(ptr, state->create_rename_lsn); ptr+= LSN_STORE_SIZE;
+ lsn_store(ptr, state->is_of_horizon); ptr+= LSN_STORE_SIZE;
+ lsn_store(ptr, state->skip_redo_lsn); ptr+= LSN_STORE_SIZE;
+ mi_rowstore(ptr,state->state.records); ptr+= 8;
+ mi_rowstore(ptr,state->state.del); ptr+= 8;
+ mi_rowstore(ptr,state->split); ptr+= 8;
+ mi_sizestore(ptr,state->dellink); ptr+= 8;
+ mi_sizestore(ptr,state->first_bitmap_with_space); ptr+= 8;
+ mi_sizestore(ptr,state->state.key_file_length); ptr+= 8;
+ mi_sizestore(ptr,state->state.data_file_length); ptr+= 8;
+ mi_sizestore(ptr,state->state.empty); ptr+= 8;
+ mi_sizestore(ptr,state->state.key_empty); ptr+= 8;
+ mi_int8store(ptr,state->auto_increment); ptr+= 8;
+ mi_int8store(ptr,(ulonglong) state->state.checksum); ptr+= 8;
+ mi_int8store(ptr,state->create_trid); ptr+= 8;
+ mi_int4store(ptr,state->status); ptr+= 4;
+ mi_int4store(ptr,state->update_count); ptr+= 4;
+ *ptr++= state->sortkey;
+ *ptr++= 0; /* Reserved */
+ ptr+= state->state_diff_length;
+
+ for (i=0; i < keys; i++)
+ {
+ mi_sizestore(ptr,state->key_root[i]); ptr+= 8;
+ }
+ mi_sizestore(ptr,state->key_del); ptr+= 8;
+ if (pWrite & MA_STATE_INFO_WRITE_FULL_INFO) /* From maria_chk */
+ {
+ uint key_parts= mi_uint2korr(state->header.key_parts);
+ mi_int4store(ptr,state->sec_index_changed); ptr+= 4;
+ mi_int4store(ptr,state->sec_index_used); ptr+= 4;
+ mi_int4store(ptr,state->version); ptr+= 4;
+ mi_int8store(ptr,state->key_map); ptr+= 8;
+ mi_int8store(ptr,(ulonglong) state->create_time); ptr+= 8;
+ mi_int8store(ptr,(ulonglong) state->recover_time); ptr+= 8;
+ mi_int8store(ptr,(ulonglong) state->check_time); ptr+= 8;
+ mi_sizestore(ptr, state->records_at_analyze); ptr+= 8;
+ /* reserve place for some information per key */
+ bzero(ptr, keys*4); ptr+= keys*4;
+ for (i=0 ; i < key_parts ; i++)
+ {
+ float8store(ptr, state->rec_per_key_part[i]); ptr+= 8;
+ mi_int4store(ptr, state->nulls_per_key_part[i]); ptr+= 4;
+ }
+ }
+
+ res= (pWrite & MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET) ?
+ my_pwrite(file, buff, (size_t) (ptr-buff), 0L,
+ MYF(MY_NABP | MY_THREADSAFE)) :
+ my_write(file, buff, (size_t) (ptr-buff),
+ MYF(MY_NABP));
+ DBUG_RETURN(res != 0);
+}
+
+
+static uchar *_ma_state_info_read(uchar *ptr, MARIA_STATE_INFO *state)
+{
+ uint i,keys,key_parts;
+ memcpy_fixed(&state->header,ptr, sizeof(state->header));
+ ptr+= sizeof(state->header);
+ keys= (uint) state->header.keys;
+ key_parts= mi_uint2korr(state->header.key_parts);
+
+ state->open_count = mi_uint2korr(ptr); ptr+= 2;
+ state->changed= mi_uint2korr(ptr); ptr+= 2;
+ state->create_rename_lsn= lsn_korr(ptr); ptr+= LSN_STORE_SIZE;
+ state->is_of_horizon= lsn_korr(ptr); ptr+= LSN_STORE_SIZE;
+ state->skip_redo_lsn= lsn_korr(ptr); ptr+= LSN_STORE_SIZE;
+ state->state.records= mi_rowkorr(ptr); ptr+= 8;
+ state->state.del = mi_rowkorr(ptr); ptr+= 8;
+ state->split = mi_rowkorr(ptr); ptr+= 8;
+ state->dellink= mi_sizekorr(ptr); ptr+= 8;
+ state->first_bitmap_with_space= mi_sizekorr(ptr); ptr+= 8;
+ state->state.key_file_length = mi_sizekorr(ptr); ptr+= 8;
+ state->state.data_file_length= mi_sizekorr(ptr); ptr+= 8;
+ state->state.empty = mi_sizekorr(ptr); ptr+= 8;
+ state->state.key_empty= mi_sizekorr(ptr); ptr+= 8;
+ state->auto_increment=mi_uint8korr(ptr); ptr+= 8;
+ state->state.checksum=(ha_checksum) mi_uint8korr(ptr);ptr+= 8;
+ state->create_trid= mi_uint8korr(ptr); ptr+= 8;
+ state->status = mi_uint4korr(ptr); ptr+= 4;
+ state->update_count=mi_uint4korr(ptr); ptr+= 4;
+ state->sortkey= (uint) *ptr++;
+ ptr++; /* reserved */
+
+ ptr+= state->state_diff_length;
+
+ for (i=0; i < keys; i++)
+ {
+ state->key_root[i]= mi_sizekorr(ptr); ptr+= 8;
+ }
+ state->key_del= mi_sizekorr(ptr); ptr+= 8;
+ state->sec_index_changed = mi_uint4korr(ptr); ptr+= 4;
+ state->sec_index_used = mi_uint4korr(ptr); ptr+= 4;
+ state->version = mi_uint4korr(ptr); ptr+= 4;
+ state->key_map = mi_uint8korr(ptr); ptr+= 8;
+ state->create_time = (time_t) mi_sizekorr(ptr); ptr+= 8;
+ state->recover_time =(time_t) mi_sizekorr(ptr); ptr+= 8;
+ state->check_time = (time_t) mi_sizekorr(ptr); ptr+= 8;
+ state->records_at_analyze= mi_sizekorr(ptr); ptr+= 8;
+ ptr+= keys * 4; /* Skip reserved bytes */
+ for (i=0 ; i < key_parts ; i++)
+ {
+ float8get(state->rec_per_key_part[i], ptr); ptr+= 8;
+ state->nulls_per_key_part[i]= mi_uint4korr(ptr); ptr+= 4;
+ }
+ return ptr;
+}
+
+
+/**
+ @brief Fills the state by reading its copy on disk.
+
+ Should not be called for transactional tables, as their state on disk is
+ rarely current and so is often misleading for a reader.
+ Does nothing in single user mode.
+
+ @param file file to read from
+ @param state state which will be filled
+*/
+
+uint _ma_state_info_read_dsk(File file __attribute__((unused)),
+ MARIA_STATE_INFO *state __attribute__((unused)))
+{
+#ifdef EXTERNAL_LOCKING
+ uchar buff[MARIA_STATE_INFO_SIZE + MARIA_STATE_EXTRA_SIZE];
+
+ /* trick to detect transactional tables */
+ DBUG_ASSERT(state->create_rename_lsn == LSN_IMPOSSIBLE);
+ if (!maria_single_user)
+ {
+ if (my_pread(file, buff, state->state_length, 0L, MYF(MY_NABP)))
+ return 1;
+ _ma_state_info_read(buff, state);
+ }
+#endif
+ return 0;
+}
+
+
+/****************************************************************************
+** store and read of MARIA_BASE_INFO
+****************************************************************************/
+
+uint _ma_base_info_write(File file, MARIA_BASE_INFO *base)
+{
+ uchar buff[MARIA_BASE_INFO_SIZE], *ptr=buff;
+
+ bmove(ptr, maria_uuid, MY_UUID_SIZE);
+ ptr+= MY_UUID_SIZE;
+ mi_sizestore(ptr,base->keystart); ptr+= 8;
+ mi_sizestore(ptr,base->max_data_file_length); ptr+= 8;
+ mi_sizestore(ptr,base->max_key_file_length); ptr+= 8;
+ mi_rowstore(ptr,base->records); ptr+= 8;
+ mi_rowstore(ptr,base->reloc); ptr+= 8;
+ mi_int4store(ptr,base->mean_row_length); ptr+= 4;
+ mi_int4store(ptr,base->reclength); ptr+= 4;
+ mi_int4store(ptr,base->pack_reclength); ptr+= 4;
+ mi_int4store(ptr,base->min_pack_length); ptr+= 4;
+ mi_int4store(ptr,base->max_pack_length); ptr+= 4;
+ mi_int4store(ptr,base->min_block_length); ptr+= 4;
+ mi_int2store(ptr,base->fields); ptr+= 2;
+ mi_int2store(ptr,base->fixed_not_null_fields); ptr+= 2;
+ mi_int2store(ptr,base->fixed_not_null_fields_length); ptr+= 2;
+ mi_int2store(ptr,base->max_field_lengths); ptr+= 2;
+ mi_int2store(ptr,base->pack_fields); ptr+= 2;
+ mi_int2store(ptr,base->extra_options) ptr+= 2;
+ mi_int2store(ptr,base->null_bytes); ptr+= 2;
+ mi_int2store(ptr,base->original_null_bytes); ptr+= 2;
+ mi_int2store(ptr,base->field_offsets); ptr+= 2;
+ mi_int2store(ptr,0); ptr+= 2; /* reserved */
+ mi_int2store(ptr,base->block_size); ptr+= 2;
+ *ptr++= base->rec_reflength;
+ *ptr++= base->key_reflength;
+ *ptr++= base->keys;
+ *ptr++= base->auto_key;
+ *ptr++= base->born_transactional;
+ *ptr++= 0; /* Reserved */
+ mi_int2store(ptr,base->pack_bytes); ptr+= 2;
+ mi_int2store(ptr,base->blobs); ptr+= 2;
+ mi_int2store(ptr,base->max_key_block_length); ptr+= 2;
+ mi_int2store(ptr,base->max_key_length); ptr+= 2;
+ mi_int2store(ptr,base->extra_alloc_bytes); ptr+= 2;
+ *ptr++= base->extra_alloc_procent;
+ bzero(ptr,16); ptr+= 16; /* extra */
+ DBUG_ASSERT((ptr - buff) == MARIA_BASE_INFO_SIZE);
+ return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
+}
+
+
+static uchar *_ma_base_info_read(uchar *ptr, MARIA_BASE_INFO *base)
+{
+ bmove(base->uuid, ptr, MY_UUID_SIZE); ptr+= MY_UUID_SIZE;
+ base->keystart= mi_sizekorr(ptr); ptr+= 8;
+ base->max_data_file_length= mi_sizekorr(ptr); ptr+= 8;
+ base->max_key_file_length= mi_sizekorr(ptr); ptr+= 8;
+ base->records= (ha_rows) mi_sizekorr(ptr); ptr+= 8;
+ base->reloc= (ha_rows) mi_sizekorr(ptr); ptr+= 8;
+ base->mean_row_length= mi_uint4korr(ptr); ptr+= 4;
+ base->reclength= mi_uint4korr(ptr); ptr+= 4;
+ base->pack_reclength= mi_uint4korr(ptr); ptr+= 4;
+ base->min_pack_length= mi_uint4korr(ptr); ptr+= 4;
+ base->max_pack_length= mi_uint4korr(ptr); ptr+= 4;
+ base->min_block_length= mi_uint4korr(ptr); ptr+= 4;
+ base->fields= mi_uint2korr(ptr); ptr+= 2;
+ base->fixed_not_null_fields= mi_uint2korr(ptr); ptr+= 2;
+ base->fixed_not_null_fields_length= mi_uint2korr(ptr);ptr+= 2;
+ base->max_field_lengths= mi_uint2korr(ptr); ptr+= 2;
+ base->pack_fields= mi_uint2korr(ptr); ptr+= 2;
+ base->extra_options= mi_uint2korr(ptr); ptr+= 2;
+ base->null_bytes= mi_uint2korr(ptr); ptr+= 2;
+ base->original_null_bytes= mi_uint2korr(ptr); ptr+= 2;
+ base->field_offsets= mi_uint2korr(ptr); ptr+= 2;
+ ptr+= 2;
+ base->block_size= mi_uint2korr(ptr); ptr+= 2;
+
+ base->rec_reflength= *ptr++;
+ base->key_reflength= *ptr++;
+ base->keys= *ptr++;
+ base->auto_key= *ptr++;
+ base->born_transactional= *ptr++;
+ ptr++;
+ base->pack_bytes= mi_uint2korr(ptr); ptr+= 2;
+ base->blobs= mi_uint2korr(ptr); ptr+= 2;
+ base->max_key_block_length= mi_uint2korr(ptr); ptr+= 2;
+ base->max_key_length= mi_uint2korr(ptr); ptr+= 2;
+ base->extra_alloc_bytes= mi_uint2korr(ptr); ptr+= 2;
+ base->extra_alloc_procent= *ptr++;
+ ptr+= 16;
+ return ptr;
+}
+
+/*--------------------------------------------------------------------------
+ maria_keydef
+---------------------------------------------------------------------------*/
+
+my_bool _ma_keydef_write(File file, MARIA_KEYDEF *keydef)
+{
+ uchar buff[MARIA_KEYDEF_SIZE];
+ uchar *ptr=buff;
+
+ *ptr++= (uchar) keydef->keysegs;
+ *ptr++= keydef->key_alg; /* Rtree or Btree */
+ mi_int2store(ptr,keydef->flag); ptr+= 2;
+ mi_int2store(ptr,keydef->block_length); ptr+= 2;
+ mi_int2store(ptr,keydef->keylength); ptr+= 2;
+ mi_int2store(ptr,keydef->minlength); ptr+= 2;
+ mi_int2store(ptr,keydef->maxlength); ptr+= 2;
+ return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
+}
+
+uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef)
+{
+ keydef->keysegs = (uint) *ptr++;
+ keydef->key_alg = *ptr++; /* Rtree or Btree */
+
+ keydef->flag = mi_uint2korr(ptr); ptr+= 2;
+ keydef->block_length = mi_uint2korr(ptr); ptr+= 2;
+ keydef->keylength = mi_uint2korr(ptr); ptr+= 2;
+ keydef->minlength = mi_uint2korr(ptr); ptr+= 2;
+ keydef->maxlength = mi_uint2korr(ptr); ptr+= 2;
+ keydef->underflow_block_length=keydef->block_length/3;
+ keydef->version = 0; /* Not saved */
+ keydef->parser = &ft_default_parser;
+ keydef->ftparser_nr = 0;
+ return ptr;
+}
+
+/***************************************************************************
+** maria_keyseg
+***************************************************************************/
+
+my_bool _ma_keyseg_write(File file, const HA_KEYSEG *keyseg)
+{
+ uchar buff[HA_KEYSEG_SIZE];
+ uchar *ptr=buff;
+ ulong pos;
+
+ *ptr++= keyseg->type;
+ *ptr++= keyseg->language;
+ *ptr++= keyseg->null_bit;
+ *ptr++= keyseg->bit_start;
+ *ptr++= keyseg->bit_end;
+ *ptr++= keyseg->bit_length;
+ mi_int2store(ptr,keyseg->flag); ptr+= 2;
+ mi_int2store(ptr,keyseg->length); ptr+= 2;
+ mi_int4store(ptr,keyseg->start); ptr+= 4;
+ pos= keyseg->null_bit ? keyseg->null_pos : keyseg->bit_pos;
+ mi_int4store(ptr, pos);
+ ptr+=4;
+
+ return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
+}
+
+
+uchar *_ma_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg)
+{
+ keyseg->type = *ptr++;
+ keyseg->language = *ptr++;
+ keyseg->null_bit = *ptr++;
+ keyseg->bit_start = *ptr++;
+ keyseg->bit_end = *ptr++;
+ keyseg->bit_length = *ptr++;
+ keyseg->flag = mi_uint2korr(ptr); ptr+= 2;
+ keyseg->length = mi_uint2korr(ptr); ptr+= 2;
+ keyseg->start = mi_uint4korr(ptr); ptr+= 4;
+ keyseg->null_pos = mi_uint4korr(ptr); ptr+= 4;
+ keyseg->charset=0; /* Will be filled in later */
+ if (keyseg->null_bit)
+ keyseg->bit_pos= (uint16)(keyseg->null_pos + (keyseg->null_bit == 7));
+ else
+ {
+ keyseg->bit_pos= (uint16)keyseg->null_pos;
+ keyseg->null_pos= 0;
+ }
+ return ptr;
+}
+
+/*--------------------------------------------------------------------------
+ maria_uniquedef
+---------------------------------------------------------------------------*/
+
+my_bool _ma_uniquedef_write(File file, MARIA_UNIQUEDEF *def)
+{
+ uchar buff[MARIA_UNIQUEDEF_SIZE];
+ uchar *ptr=buff;
+
+ mi_int2store(ptr,def->keysegs); ptr+=2;
+ *ptr++= (uchar) def->key;
+ *ptr++ = (uchar) def->null_are_equal;
+
+ return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
+}
+
+uchar *_ma_uniquedef_read(uchar *ptr, MARIA_UNIQUEDEF *def)
+{
+ def->keysegs = mi_uint2korr(ptr);
+ def->key = ptr[2];
+ def->null_are_equal=ptr[3];
+ return ptr+4; /* 1 extra uchar */
+}
+
+/***************************************************************************
+** MARIA_COLUMNDEF
+***************************************************************************/
+
+my_bool _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef)
+{
+ uchar buff[MARIA_COLUMNDEF_SIZE];
+ uchar *ptr=buff;
+
+ mi_int2store(ptr,(ulong) columndef->column_nr); ptr+= 2;
+ mi_int2store(ptr,(ulong) columndef->offset); ptr+= 2;
+ mi_int2store(ptr,columndef->type); ptr+= 2;
+ mi_int2store(ptr,columndef->length); ptr+= 2;
+ mi_int2store(ptr,columndef->fill_length); ptr+= 2;
+ mi_int2store(ptr,columndef->null_pos); ptr+= 2;
+ mi_int2store(ptr,columndef->empty_pos); ptr+= 2;
+
+ (*ptr++)= columndef->null_bit;
+ (*ptr++)= columndef->empty_bit;
+ ptr[0]= ptr[1]= ptr[2]= ptr[3]= 0; ptr+= 4; /* For future */
+ return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0;
+}
+
+uchar *_ma_columndef_read(uchar *ptr, MARIA_COLUMNDEF *columndef)
+{
+ columndef->column_nr= mi_uint2korr(ptr); ptr+= 2;
+ columndef->offset= mi_uint2korr(ptr); ptr+= 2;
+ columndef->type= mi_sint2korr(ptr); ptr+= 2;
+ columndef->length= mi_uint2korr(ptr); ptr+= 2;
+ columndef->fill_length= mi_uint2korr(ptr); ptr+= 2;
+ columndef->null_pos= mi_uint2korr(ptr); ptr+= 2;
+ columndef->empty_pos= mi_uint2korr(ptr); ptr+= 2;
+ columndef->null_bit= (uint8) *ptr++;
+ columndef->empty_bit= (uint8) *ptr++;
+ ptr+= 4;
+ return ptr;
+}
+
+my_bool _ma_column_nr_write(File file, uint16 *offsets, uint columns)
+{
+ uchar *buff, *ptr, *end;
+ size_t size= columns*2;
+ my_bool res;
+
+ if (!(buff= (uchar*) my_alloca(size)))
+ return 1;
+ for (ptr= buff, end= ptr + size; ptr < end ; ptr+= 2, offsets++)
+ int2store(ptr, *offsets);
+ res= my_write(file, buff, size, MYF(MY_NABP)) != 0;
+ my_afree(buff);
+ return res;
+}
+
+
+uchar *_ma_column_nr_read(uchar *ptr, uint16 *offsets, uint columns)
+{
+ uchar *end;
+ size_t size= columns*2;
+ for (end= ptr + size; ptr < end ; ptr+=2, offsets++)
+ *offsets= uint2korr(ptr);
+ return ptr;
+}
+
+/**
+ @brief Set callbacks for data pages
+
+ @note
+ We don't use pagecache_file_init here, as we want to keep the
+ code readable
+*/
+
+void _ma_set_data_pagecache_callbacks(PAGECACHE_FILE *file,
+ MARIA_SHARE *share)
+{
+ file->callback_data= (uchar*) share;
+ file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */
+
+ if (share->temporary)
+ {
+ file->read_callback= &maria_page_crc_check_none;
+ file->write_callback= &maria_page_filler_set_none;
+ }
+ else
+ {
+ file->read_callback= &maria_page_crc_check_data;
+ if (share->options & HA_OPTION_PAGE_CHECKSUM)
+ file->write_callback= &maria_page_crc_set_normal;
+ else
+ file->write_callback= &maria_page_filler_set_normal;
+ if (share->now_transactional)
+ file->flush_log_callback= maria_flush_log_for_page;
+ }
+}
+
+
+/**
+ @brief Set callbacks for index pages
+
+ @note
+ We don't use pagecache_file_init here, as we want to keep the
+ code readable
+*/
+
+void _ma_set_index_pagecache_callbacks(PAGECACHE_FILE *file,
+ MARIA_SHARE *share)
+{
+ file->callback_data= (uchar*) share;
+ file->flush_log_callback= &maria_flush_log_for_page_none; /* Do nothing */
+ file->write_fail= maria_page_write_failure;
+
+ if (share->temporary)
+ {
+ file->read_callback= &maria_page_crc_check_none;
+ file->write_callback= &maria_page_filler_set_none;
+ }
+ else
+ {
+ file->read_callback= &maria_page_crc_check_index;
+ if (share->options & HA_OPTION_PAGE_CHECKSUM)
+ file->write_callback= &maria_page_crc_set_index;
+ else
+ file->write_callback= &maria_page_filler_set_normal;
+
+ if (share->now_transactional)
+ file->flush_log_callback= maria_flush_log_for_page;
+ }
+}
+
+
+/**************************************************************************
+ Open data file
+ We can't use dup() here as the data file descriptors need to have different
+ active seek-positions.
+
+ The argument file_to_dup is here for the future if there would on some OS
+ exist a dup()-like call that would give us two different file descriptors.
+*************************************************************************/
+
+int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share, const char *org_name,
+ File file_to_dup __attribute__((unused)))
+{
+ char *data_name= share->data_file_name.str;
+ char real_data_name[FN_REFLEN];
+
+ if (org_name)
+ {
+ fn_format(real_data_name, org_name, "", MARIA_NAME_DEXT, 4);
+ if (my_is_symlink(real_data_name))
+ {
+ if (my_realpath(real_data_name, real_data_name, MYF(0)) ||
+ (*maria_test_invalid_symlink)(real_data_name))
+ {
+ my_errno= HA_WRONG_CREATE_OPTION;
+ return 1;
+ }
+ data_name= real_data_name;
+ }
+ }
+
+ info->dfile.file= share->bitmap.file.file=
+ my_open(share->data_file_name.str, share->mode | O_SHARE,
+ MYF(MY_WME));
+ return info->dfile.file >= 0 ? 0 : 1;
+}
+
+
+int _ma_open_keyfile(MARIA_SHARE *share)
+{
+ /*
+ Modifications to share->kfile should be under intern_lock to protect
+ against a concurrent checkpoint.
+ */
+ pthread_mutex_lock(&share->intern_lock);
+ share->kfile.file= my_open(share->unique_file_name.str,
+ share->mode | O_SHARE,
+ MYF(MY_WME));
+ pthread_mutex_unlock(&share->intern_lock);
+ return (share->kfile.file < 0);
+}
+
+
+/*
+ Disable all indexes.
+
+ SYNOPSIS
+ maria_disable_indexes()
+ info A pointer to the MARIA storage engine MARIA_HA struct.
+
+ DESCRIPTION
+ Disable all indexes.
+
+ RETURN
+ 0 ok
+*/
+
+int maria_disable_indexes(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+
+ maria_clear_all_keys_active(share->state.key_map);
+ return 0;
+}
+
+
+/*
+ Enable all indexes
+
+ SYNOPSIS
+ maria_enable_indexes()
+ info A pointer to the MARIA storage engine MARIA_HA struct.
+
+ DESCRIPTION
+ Enable all indexes. The indexes might have been disabled
+ by maria_disable_index() before.
+ The function works only if both data and indexes are empty,
+ otherwise a repair is required.
+ To be sure, call handler::delete_all_rows() before.
+
+ RETURN
+ 0 ok
+ HA_ERR_CRASHED data or index is non-empty.
+*/
+
+int maria_enable_indexes(MARIA_HA *info)
+{
+ int error= 0;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_enable_indexes");
+
+ if ((share->state.state.data_file_length !=
+ (share->data_file_type == BLOCK_RECORD ? share->block_size : 0)) ||
+ (share->state.state.key_file_length != share->base.keystart))
+ {
+ DBUG_PRINT("error", ("data_file_length: %lu key_file_length: %lu",
+ (ulong) share->state.state.data_file_length,
+ (ulong) share->state.state.key_file_length));
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ error= HA_ERR_CRASHED;
+ }
+ else
+ maria_set_all_keys_active(share->state.key_map, share->base.keys);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Test if indexes are disabled.
+
+ SYNOPSIS
+ maria_indexes_are_disabled()
+ info A pointer to the MARIA storage engine MARIA_HA struct.
+
+ DESCRIPTION
+ Test if indexes are disabled.
+
+ RETURN
+ 0 indexes are not disabled
+ 1 all indexes are disabled
+ 2 non-unique indexes are disabled
+*/
+
+int maria_indexes_are_disabled(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+
+ /*
+ No keys or all are enabled. keys is the number of keys. Left shifted
+ gives us only one bit set. When decreased by one, gives us all all bits
+ up to this one set and it gets unset.
+ */
+ if (!share->base.keys ||
+ (maria_is_all_keys_active(share->state.key_map, share->base.keys)))
+ return 0;
+
+ /* All are disabled */
+ if (maria_is_any_key_active(share->state.key_map))
+ return 1;
+
+ /*
+ We have keys. Some enabled, some disabled.
+ Don't check for any non-unique disabled but return directly 2
+ */
+ return 2;
+}
+
+
+static my_bool maria_scan_init_dummy(MARIA_HA *info __attribute__((unused)))
+{
+ return 0;
+}
+
+static void maria_scan_end_dummy(MARIA_HA *info __attribute__((unused)))
+{
+}
+
+static my_bool maria_once_init_dummy(MARIA_SHARE *share
+ __attribute__((unused)),
+ File dfile __attribute__((unused)))
+{
+ return 0;
+}
+
+static my_bool maria_once_end_dummy(MARIA_SHARE *share __attribute__((unused)))
+{
+ return 0;
+}
diff --git a/storage/maria/ma_packrec.c b/storage/maria/ma_packrec.c
new file mode 100644
index 00000000000..bc0646975ee
--- /dev/null
+++ b/storage/maria/ma_packrec.c
@@ -0,0 +1,1723 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to compressed records */
+
+#include "maria_def.h"
+
+#define IS_CHAR ((uint) 32768) /* Bit if char (not offset) in tree */
+
+/* Some definitions to keep in sync with maria_pack.c */
+#define HEAD_LENGTH 32 /* Length of fixed header */
+
+#if INT_MAX > 32767
+#define BITS_SAVED 32
+#define MAX_QUICK_TABLE_BITS 9 /* Because we may shift in 24 bits */
+#else
+#define BITS_SAVED 16
+#define MAX_QUICK_TABLE_BITS 6
+#endif
+
+#define get_bit(BU) ((BU)->bits ? \
+ (BU)->current_byte & ((maria_bit_type) 1 << --(BU)->bits) :\
+ (fill_buffer(BU), (BU)->bits= BITS_SAVED-1,\
+ (BU)->current_byte & ((maria_bit_type) 1 << (BITS_SAVED-1))))
+#define skip_to_next_byte(BU) ((BU)->bits&=~7)
+#define get_bits(BU,count) (((BU)->bits >= count) ? (((BU)->current_byte >> ((BU)->bits-=count)) & mask[count]) : fill_and_get_bits(BU,count))
+
+#define decode_bytes_test_bit(bit) \
+ if (low_byte & (1 << (7-bit))) \
+ pos++; \
+ if (*pos & IS_CHAR) \
+ { bits-=(bit+1); break; } \
+ pos+= *pos
+
+/*
+ Size in uint16 of a Huffman tree for uchar compression of 256 uchar values
+*/
+#define OFFSET_TABLE_SIZE 512
+
+static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
+ pbool fix_keys);
+static uint read_huff_table(MARIA_BIT_BUFF *bit_buff,
+ MARIA_DECODE_TREE *decode_tree,
+ uint16 **decode_table,uchar **intervall_buff,
+ uint16 *tmp_buff);
+static void make_quick_table(uint16 *to_table,uint16 *decode_table,
+ uint *next_free,uint value,uint bits,
+ uint max_bits);
+static void fill_quick_table(uint16 *table,uint bits, uint max_bits,
+ uint value);
+static uint copy_decode_table(uint16 *to_pos,uint offset,
+ uint16 *decode_table);
+static uint find_longest_bitstream(uint16 *table, uint16 *end);
+static void (*get_unpack_function(MARIA_COLUMNDEF *rec))(MARIA_COLUMNDEF *field,
+ MARIA_BIT_BUFF *buff,
+ uchar *to,
+ uchar *end);
+static void uf_zerofill_skip_zero(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_skip_zero(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_normal(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_endspace_selected(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_endspace_selected(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_endspace(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_endspace(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_prespace_selected(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_prespace_selected(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_space_prespace(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_prespace(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_zerofill_normal(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_constant(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_intervall(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_zero(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static void uf_blob(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_varchar1(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void uf_varchar2(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end);
+static void decode_bytes(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to,uchar *end);
+static uint decode_pos(MARIA_BIT_BUFF *bit_buff,
+ MARIA_DECODE_TREE *decode_tree);
+static void init_bit_buffer(MARIA_BIT_BUFF *bit_buff,uchar *buffer,
+ uint length);
+static uint fill_and_get_bits(MARIA_BIT_BUFF *bit_buff,uint count);
+static void fill_buffer(MARIA_BIT_BUFF *bit_buff);
+static uint max_bit(uint value);
+static uint read_pack_length(uint version, const uchar *buf, ulong *length);
+#ifdef HAVE_MMAP
+static uchar *_ma_mempack_get_block_info(MARIA_HA *maria,
+ MARIA_BIT_BUFF *bit_buff,
+ MARIA_BLOCK_INFO *info,
+ uchar **rec_buff_p,
+ size_t *rec_buff_size_p,
+ uchar *header);
+#endif
+
+static maria_bit_type mask[]=
+{
+ 0x00000000,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+ 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+ 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+#if BITS_SAVED > 16
+ 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+ 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+ 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+ 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
+#endif
+};
+
+
+my_bool _ma_once_init_pack_row(MARIA_SHARE *share, File dfile)
+{
+ share->options|= HA_OPTION_READ_ONLY_DATA;
+ return (_ma_read_pack_info(share, dfile,
+ (pbool)
+ test(!(share->options &
+ (HA_OPTION_PACK_RECORD |
+ HA_OPTION_TEMP_COMPRESS_RECORD)))));
+}
+
+
+my_bool _ma_once_end_pack_row(MARIA_SHARE *share)
+{
+ if (share->decode_trees)
+ {
+ my_free((uchar*) share->decode_trees,MYF(0));
+ my_free((uchar*) share->decode_tables,MYF(0));
+ }
+ return 0;
+}
+
+
+/* Read all packed info, allocate memory and fix field structs */
+
+static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
+ pbool fix_keys)
+{
+ int diff_length;
+ uint i,trees,huff_tree_bits,rec_reflength,length;
+ uint16 *decode_table,*tmp_buff;
+ ulong elements,intervall_length;
+ uchar *disk_cache;
+ uchar *intervall_buff;
+ uchar header[HEAD_LENGTH];
+ MARIA_BIT_BUFF bit_buff;
+ DBUG_ENTER("_ma_read_pack_info");
+
+ if (maria_quick_table_bits < 4)
+ maria_quick_table_bits=4;
+ else if (maria_quick_table_bits > MAX_QUICK_TABLE_BITS)
+ maria_quick_table_bits=MAX_QUICK_TABLE_BITS;
+
+ my_errno=0;
+ if (my_read(file,(uchar*) header,sizeof(header),MYF(MY_NABP)))
+ {
+ if (!my_errno)
+ my_errno=HA_ERR_END_OF_FILE;
+ goto err0;
+ }
+ /* Only the first three bytes of magic number are independent of version. */
+ if (memcmp((uchar*) header, (uchar*) maria_pack_file_magic, 3))
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err0;
+ }
+ share->pack.version= header[3]; /* fourth uchar of magic number */
+ share->pack.header_length= uint4korr(header+4);
+ share->min_pack_length=(uint) uint4korr(header+8);
+ share->max_pack_length=(uint) uint4korr(header+12);
+ set_if_bigger(share->base.default_rec_buff_size,
+ share->max_pack_length + 7);
+ elements=uint4korr(header+16);
+ intervall_length=uint4korr(header+20);
+ trees=uint2korr(header+24);
+ share->pack.ref_length=header[26];
+ rec_reflength=header[27];
+ diff_length=(int) rec_reflength - (int) share->base.rec_reflength;
+ if (fix_keys)
+ share->rec_reflength=rec_reflength;
+ DBUG_PRINT("info", ("fixed header length: %u", HEAD_LENGTH));
+ DBUG_PRINT("info", ("total header length: %lu", share->pack.header_length));
+ DBUG_PRINT("info", ("pack file version: %u", share->pack.version));
+ DBUG_PRINT("info", ("min pack length: %lu", share->min_pack_length));
+ DBUG_PRINT("info", ("max pack length: %lu", share->max_pack_length));
+ DBUG_PRINT("info", ("elements of all trees: %lu", elements));
+ DBUG_PRINT("info", ("distinct values bytes: %lu", intervall_length));
+ DBUG_PRINT("info", ("number of code trees: %u", trees));
+ DBUG_PRINT("info", ("bytes for record lgt: %u", share->pack.ref_length));
+ DBUG_PRINT("info", ("record pointer length: %u", rec_reflength));
+
+
+ /*
+ Memory segment #1:
+ - Decode tree heads
+ - Distinct column values
+ */
+ if (!(share->decode_trees=(MARIA_DECODE_TREE*)
+ my_malloc((uint) (trees*sizeof(MARIA_DECODE_TREE)+
+ intervall_length*sizeof(uchar)),
+ MYF(MY_WME))))
+ goto err0;
+ intervall_buff=(uchar*) (share->decode_trees+trees);
+
+ /*
+ Memory segment #2:
+ - Decode tables
+ - Quick decode tables
+ - Temporary decode table
+ - Compressed data file header cache
+ This segment will be reallocated after construction of the tables.
+ */
+ length=(uint) (elements*2+trees*(1 << maria_quick_table_bits));
+ if (!(share->decode_tables=(uint16*)
+ my_malloc((length+OFFSET_TABLE_SIZE)*sizeof(uint16)+
+ (uint) (share->pack.header_length - sizeof(header)) +
+ share->base.extra_rec_buff_size,
+ MYF(MY_WME | MY_ZEROFILL))))
+ goto err1;
+ tmp_buff=share->decode_tables+length;
+ disk_cache=(uchar*) (tmp_buff+OFFSET_TABLE_SIZE);
+
+ if (my_read(file,disk_cache,
+ (uint) (share->pack.header_length-sizeof(header)),
+ MYF(MY_NABP)))
+ goto err2;
+#ifdef HAVE_purify
+ /* Zero bytes accessed by fill_buffer */
+ bzero(disk_cache + (share->pack.header_length-sizeof(header)),
+ share->base.extra_rec_buff_size);
+#endif
+
+ huff_tree_bits=max_bit(trees ? trees-1 : 0);
+ init_bit_buffer(&bit_buff, disk_cache,
+ (uint) (share->pack.header_length-sizeof(header)));
+ /* Read new info for each field */
+ for (i=0 ; i < share->base.fields ; i++)
+ {
+ share->columndef[i].base_type=(enum en_fieldtype) get_bits(&bit_buff,5);
+ share->columndef[i].pack_type=(uint) get_bits(&bit_buff,6);
+ share->columndef[i].space_length_bits=get_bits(&bit_buff,5);
+ share->columndef[i].huff_tree=share->decode_trees+(uint) get_bits(&bit_buff,
+ huff_tree_bits);
+ share->columndef[i].unpack= get_unpack_function(share->columndef + i);
+ DBUG_PRINT("info", ("col: %2u type: %2u pack: %u slbits: %2u",
+ i, share->columndef[i].base_type,
+ share->columndef[i].pack_type,
+ share->columndef[i].space_length_bits));
+ }
+ skip_to_next_byte(&bit_buff);
+ /*
+ Construct the decoding tables from the file header. Keep track of
+ the used memory.
+ */
+ decode_table=share->decode_tables;
+ for (i=0 ; i < trees ; i++)
+ if (read_huff_table(&bit_buff,share->decode_trees+i,&decode_table,
+ &intervall_buff,tmp_buff))
+ goto err3;
+ /* Reallocate the decoding tables to the used size. */
+ decode_table=(uint16*)
+ my_realloc((uchar*) share->decode_tables,
+ (uint) ((uchar*) decode_table - (uchar*) share->decode_tables),
+ MYF(MY_HOLD_ON_ERROR));
+ /* Fix the table addresses in the tree heads. */
+ {
+ my_ptrdiff_t diff= PTR_BYTE_DIFF(decode_table,share->decode_tables);
+ share->decode_tables=decode_table;
+ for (i=0 ; i < trees ; i++)
+ share->decode_trees[i].table=ADD_TO_PTR(share->decode_trees[i].table,
+ diff, uint16*);
+ }
+
+ /* Fix record-ref-length for keys */
+ if (fix_keys)
+ {
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ MARIA_KEYDEF *keyinfo= &share->keyinfo[i];
+ keyinfo->keylength+= (uint16) diff_length;
+ keyinfo->minlength+= (uint16) diff_length;
+ keyinfo->maxlength+= (uint16) diff_length;
+ keyinfo->seg[keyinfo->flag & HA_FULLTEXT ?
+ FT_SEGS : keyinfo->keysegs].length= (uint16) rec_reflength;
+ }
+ if (share->ft2_keyinfo.seg)
+ {
+ MARIA_KEYDEF *ft2_keyinfo= &share->ft2_keyinfo;
+ ft2_keyinfo->keylength+= (uint16) diff_length;
+ ft2_keyinfo->minlength+= (uint16) diff_length;
+ ft2_keyinfo->maxlength+= (uint16) diff_length;
+ }
+ }
+
+ if (bit_buff.error || bit_buff.pos < bit_buff.end)
+ goto err3;
+
+ DBUG_RETURN(0);
+
+err3:
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+err2:
+ my_free((uchar*) share->decode_tables,MYF(0));
+err1:
+ my_free((uchar*) share->decode_trees,MYF(0));
+err0:
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Read a huff-code-table from datafile.
+
+ SYNOPSIS
+ read_huff_table()
+ bit_buff Bit buffer pointing at start of the
+ decoding table in the file header cache.
+ decode_tree Pointer to the decode tree head.
+ decode_table IN/OUT Address of a pointer to the next free space.
+ intervall_buff IN/OUT Address of a pointer to the next unused values.
+ tmp_buff Buffer for temporary extraction of a full
+ decoding table as read from bit_buff.
+
+ RETURN
+ 0 OK.
+ 1 Error.
+*/
+static uint read_huff_table(MARIA_BIT_BUFF *bit_buff,
+ MARIA_DECODE_TREE *decode_tree,
+ uint16 **decode_table, uchar **intervall_buff,
+ uint16 *tmp_buff)
+{
+ uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits,
+ next_free_offset;
+ uint16 *ptr,*end;
+ DBUG_ENTER("read_huff_table");
+
+ if (!get_bits(bit_buff,1))
+ {
+ /* Byte value compression. */
+ min_chr=get_bits(bit_buff,8);
+ elements=get_bits(bit_buff,9);
+ char_bits=get_bits(bit_buff,5);
+ offset_bits=get_bits(bit_buff,5);
+ intervall_length=0;
+ ptr=tmp_buff;
+ ptr=tmp_buff;
+ DBUG_PRINT("info", ("byte value compression"));
+ DBUG_PRINT("info", ("minimum uchar value: %u", min_chr));
+ DBUG_PRINT("info", ("number of tree nodes: %u", elements));
+ DBUG_PRINT("info", ("bits for values: %u", char_bits));
+ DBUG_PRINT("info", ("bits for tree offsets: %u", offset_bits));
+ if (elements > 256)
+ {
+ DBUG_PRINT("error", ("ERROR: illegal number of tree elements: %u",
+ elements));
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ /* Distinct column value compression. */
+ min_chr=0;
+ elements=get_bits(bit_buff,15);
+ intervall_length=get_bits(bit_buff,16);
+ char_bits=get_bits(bit_buff,5);
+ offset_bits=get_bits(bit_buff,5);
+ decode_tree->quick_table_bits=0;
+ ptr= *decode_table;
+ DBUG_PRINT("info", ("distinct column value compression"));
+ DBUG_PRINT("info", ("number of tree nodes: %u", elements));
+ DBUG_PRINT("info", ("value buffer length: %u", intervall_length));
+ DBUG_PRINT("info", ("bits for value index: %u", char_bits));
+ DBUG_PRINT("info", ("bits for tree offsets: %u", offset_bits));
+ }
+ size=elements*2-2;
+ DBUG_PRINT("info", ("tree size in uint16: %u", size));
+ DBUG_PRINT("info", ("tree size in bytes: %u",
+ size * (uint) sizeof(uint16)));
+
+ for (end=ptr+size ; ptr < end ; ptr++)
+ {
+ if (get_bit(bit_buff))
+ {
+ *ptr= (uint16) get_bits(bit_buff,offset_bits);
+ if ((ptr + *ptr >= end) || !*ptr)
+ {
+ DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree"));
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ *ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr));
+ }
+ skip_to_next_byte(bit_buff);
+
+ decode_tree->table= *decode_table;
+ decode_tree->intervalls= *intervall_buff;
+ if (! intervall_length)
+ {
+ /* Byte value compression. ptr started from tmp_buff. */
+ /* Find longest Huffman code from begin to end of tree in bits. */
+ table_bits= find_longest_bitstream(tmp_buff, ptr);
+ if (table_bits >= OFFSET_TABLE_SIZE)
+ DBUG_RETURN(1);
+ if (table_bits > maria_quick_table_bits)
+ table_bits=maria_quick_table_bits;
+ DBUG_PRINT("info", ("table bits: %u", table_bits));
+
+ next_free_offset= (1 << table_bits);
+ make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits,
+ table_bits);
+ (*decode_table)+= next_free_offset;
+ decode_tree->quick_table_bits=table_bits;
+ }
+ else
+ {
+ /* Distinct column value compression. ptr started from *decode_table */
+ (*decode_table)=end;
+ /*
+ get_bits() moves some bytes to a cache buffer in advance. May need
+ to step back.
+ */
+ bit_buff->pos-= bit_buff->bits/8;
+ /* Copy the distinct column values from the buffer. */
+ memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length);
+ (*intervall_buff)+=intervall_length;
+ bit_buff->pos+=intervall_length;
+ bit_buff->bits=0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Make a quick_table for faster decoding.
+
+ SYNOPSIS
+ make_quick_table()
+ to_table Target quick_table and remaining decode table.
+ decode_table Source Huffman (sub-)tree within tmp_buff.
+ next_free_offset IN/OUT Next free offset from to_table.
+ Starts behind quick_table on the top-level.
+ value Huffman bits found so far.
+ bits Remaining bits to be collected.
+ max_bits Total number of bits to collect (table_bits).
+
+ DESCRIPTION
+
+ The quick table is an array of 16-bit values. There exists one value
+ for each possible code representable by max_bits (table_bits) bits.
+ In most cases table_bits is 9. So there are 512 16-bit values.
+
+ If the high-order bit (16) is set (IS_CHAR) then the array slot for
+ this value is a valid Huffman code for a resulting uchar value.
+
+ The low-order 8 bits (1..8) are the resulting uchar value.
+
+ Bits 9..14 are the length of the Huffman code for this uchar value.
+ This means so many bits from the input stream were needed to
+ represent this uchar value. The remaining bits belong to later
+ Huffman codes. This also means that for every Huffman code shorter
+ than table_bits there are multiple entires in the array, which
+ differ just in the unused bits.
+
+ If the high-order bit (16) is clear (0) then the remaining bits are
+ the position of the remaining Huffman decode tree segment behind the
+ quick table.
+
+ RETURN
+ void
+*/
+
+static void make_quick_table(uint16 *to_table, uint16 *decode_table,
+ uint *next_free_offset, uint value, uint bits,
+ uint max_bits)
+{
+ DBUG_ENTER("make_quick_table");
+
+ /*
+ When down the table to the requested maximum, copy the rest of the
+ Huffman table.
+ */
+ if (!bits--)
+ {
+ /*
+ Remaining left Huffman tree segment starts behind quick table.
+ Remaining right Huffman tree segment starts behind left segment.
+ */
+ to_table[value]= (uint16) *next_free_offset;
+ /*
+ Re-construct the remaining Huffman tree segment at
+ next_free_offset in to_table.
+ */
+ *next_free_offset=copy_decode_table(to_table, *next_free_offset,
+ decode_table);
+ DBUG_VOID_RETURN;
+ }
+
+ /* Descent on the left side. Left side bits are clear (0). */
+ if (!(*decode_table & IS_CHAR))
+ {
+ /* Not a leaf. Follow the pointer. */
+ make_quick_table(to_table,decode_table+ *decode_table,
+ next_free_offset,value,bits,max_bits);
+ }
+ else
+ {
+ /*
+ A leaf. A Huffman code is complete. Fill the quick_table
+ array for all possible bit strings starting with this Huffman
+ code.
+ */
+ fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
+ }
+
+ /* Descent on the right side. Right side bits are set (1). */
+ decode_table++;
+ value|= (1 << bits);
+ if (!(*decode_table & IS_CHAR))
+ {
+ /* Not a leaf. Follow the pointer. */
+ make_quick_table(to_table,decode_table+ *decode_table,
+ next_free_offset,value,bits,max_bits);
+ }
+ else
+ {
+ /*
+ A leaf. A Huffman code is complete. Fill the quick_table
+ array for all possible bit strings starting with this Huffman
+ code.
+ */
+ fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Fill quick_table for all possible values starting with this Huffman code.
+
+ SYNOPSIS
+ fill_quick_table()
+ table Target quick_table position.
+ bits Unused bits from max_bits.
+ max_bits Total number of bits to collect (table_bits).
+ value The uchar encoded by the found Huffman code.
+
+ DESCRIPTION
+
+ Fill the segment (all slots) of the quick_table array with the
+ resulting value for the found Huffman code. There are as many slots
+ as there are combinations representable by the unused bits.
+
+ In most cases we use 9 table bits. Assume a 3-bit Huffman code. Then
+ there are 6 unused bits. Hence we fill 2**6 = 64 slots with the
+ value.
+
+ RETURN
+ void
+*/
+
+static void fill_quick_table(uint16 *table, uint bits, uint max_bits,
+ uint value)
+{
+ uint16 *end;
+ DBUG_ENTER("fill_quick_table");
+
+ /*
+ Bits 1..8 of value represent the decoded uchar value.
+ Bits 9..14 become the length of the Huffman code for this uchar value.
+ Bit 16 flags a valid code (IS_CHAR).
+ */
+ value|= (max_bits - bits) << 8 | IS_CHAR;
+
+ for (end= table + ((my_ptrdiff_t) 1 << bits); table < end; table++)
+ {
+ *table= (uint16) value;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Reconstruct a decode subtree at the target position.
+
+ SYNOPSIS
+ copy_decode_table()
+ to_pos Target quick_table and remaining decode table.
+ offset Next free offset from to_pos.
+ decode_table Source Huffman subtree within tmp_buff.
+
+ NOTE
+ Pointers in the decode tree are relative to the pointers position.
+
+ RETURN
+ next free offset from to_pos.
+*/
+
+static uint copy_decode_table(uint16 *to_pos, uint offset,
+ uint16 *decode_table)
+{
+ uint prev_offset= offset;
+ DBUG_ENTER("copy_decode_table");
+
+ /* Descent on the left side. */
+ if (!(*decode_table & IS_CHAR))
+ {
+ /* Set a pointer to the next target node. */
+ to_pos[offset]=2;
+ /* Copy the left hand subtree there. */
+ offset=copy_decode_table(to_pos,offset+2,decode_table+ *decode_table);
+ }
+ else
+ {
+ /* Copy the uchar value. */
+ to_pos[offset]= *decode_table;
+ /* Step behind this node. */
+ offset+=2;
+ }
+
+ /* Descent on the right side. */
+ decode_table++;
+ if (!(*decode_table & IS_CHAR))
+ {
+ /* Set a pointer to the next free target node. */
+ to_pos[prev_offset+1]=(uint16) (offset-prev_offset-1);
+ /* Copy the right hand subtree to the entry of that node. */
+ offset=copy_decode_table(to_pos,offset,decode_table+ *decode_table);
+ }
+ else
+ {
+ /* Copy the uchar value. */
+ to_pos[prev_offset+1]= *decode_table;
+ }
+ DBUG_RETURN(offset);
+}
+
+
+/*
+ Find the length of the longest Huffman code in this table in bits.
+
+ SYNOPSIS
+ find_longest_bitstream()
+ table Code (sub-)table start.
+ end End of code table.
+
+ IMPLEMENTATION
+
+ Recursively follow the branch(es) of the code pair on every level of
+ the tree until two uchar values (and no branch) are found. Add one to
+ each level when returning back from each recursion stage.
+
+ 'end' is used for error checking only. A clean tree terminates
+ before reaching 'end'. Hence the exact value of 'end' is not too
+ important. However having it higher than necessary could lead to
+ misbehaviour should 'next' jump into the dirty area.
+
+ RETURN
+ length Length of longest Huffman code in bits.
+ >= OFFSET_TABLE_SIZE Error, broken tree. It does not end before 'end'.
+*/
+
+static uint find_longest_bitstream(uint16 *table, uint16 *end)
+{
+ uint length=1;
+ uint length2;
+ if (!(*table & IS_CHAR))
+ {
+ uint16 *next= table + *table;
+ if (next > end || next == table)
+ {
+ DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree"));
+ return OFFSET_TABLE_SIZE;
+ }
+ length=find_longest_bitstream(next, end)+1;
+ }
+ table++;
+ if (!(*table & IS_CHAR))
+ {
+ uint16 *next= table + *table;
+ if (next > end || next == table)
+ {
+ DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree"));
+ return OFFSET_TABLE_SIZE;
+ }
+ length2= find_longest_bitstream(next, end) + 1;
+ length=max(length,length2);
+ }
+ return length;
+}
+
+
+/*
+ Read record from datafile.
+
+ SYNOPSIS
+ _ma_read_pack_record()
+ info A pointer to MARIA_HA.
+ filepos File offset of the record.
+ buf RETURN The buffer to receive the record.
+
+ RETURN
+ 0 On success
+ # Error number
+*/
+
+int _ma_read_pack_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
+{
+ MARIA_BLOCK_INFO block_info;
+ File file;
+ DBUG_ENTER("maria_read_pack_record");
+
+ if (filepos == HA_OFFSET_ERROR)
+ DBUG_RETURN(my_errno); /* _search() didn't find record */
+
+ file= info->dfile.file;
+ if (_ma_pack_get_block_info(info, &info->bit_buff, &block_info,
+ &info->rec_buff, &info->rec_buff_size, file,
+ filepos))
+ goto err;
+ if (my_read(file,(uchar*) info->rec_buff + block_info.offset ,
+ block_info.rec_len - block_info.offset, MYF(MY_NABP)))
+ goto panic;
+ info->update|= HA_STATE_AKTIV;
+ DBUG_RETURN(_ma_pack_rec_unpack(info,&info->bit_buff, buf,
+ info->rec_buff, block_info.rec_len));
+panic:
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+err:
+ DBUG_RETURN(my_errno);
+}
+
+
+
+int _ma_pack_rec_unpack(register MARIA_HA *info, MARIA_BIT_BUFF *bit_buff,
+ register uchar *to, uchar *from, ulong reclength)
+{
+ uchar *end_field;
+ reg3 MARIA_COLUMNDEF *end;
+ MARIA_COLUMNDEF *current_field;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_pack_rec_unpack");
+
+ if (info->s->base.null_bytes)
+ {
+ memcpy(to, from, info->s->base.null_bytes);
+ to+= info->s->base.null_bytes;
+ from+= info->s->base.null_bytes;
+ reclength-= info->s->base.null_bytes;
+ }
+ init_bit_buffer(bit_buff, (uchar*) from, reclength);
+ for (current_field=share->columndef, end=current_field+share->base.fields ;
+ current_field < end ;
+ current_field++,to=end_field)
+ {
+ end_field=to+current_field->length;
+ (*current_field->unpack)(current_field, bit_buff, to, end_field);
+ }
+ if (!bit_buff->error &&
+ bit_buff->pos - bit_buff->bits / 8 == bit_buff->end)
+ DBUG_RETURN(0);
+ info->update&= ~HA_STATE_AKTIV;
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_IN_RECORD);
+} /* _ma_pack_rec_unpack */
+
+
+ /* Return function to unpack field */
+
+static void (*get_unpack_function(MARIA_COLUMNDEF *rec))
+ (MARIA_COLUMNDEF *, MARIA_BIT_BUFF *, uchar *, uchar *)
+{
+ switch (rec->base_type) {
+ case FIELD_SKIP_ZERO:
+ if (rec->pack_type & PACK_TYPE_ZERO_FILL)
+ return &uf_zerofill_skip_zero;
+ return &uf_skip_zero;
+ case FIELD_NORMAL:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ return &uf_space_normal;
+ if (rec->pack_type & PACK_TYPE_ZERO_FILL)
+ return &uf_zerofill_normal;
+ return &decode_bytes;
+ case FIELD_SKIP_ENDSPACE:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_space_endspace_selected;
+ return &uf_space_endspace;
+ }
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_endspace_selected;
+ return &uf_endspace;
+ case FIELD_SKIP_PRESPACE:
+ if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_space_prespace_selected;
+ return &uf_space_prespace;
+ }
+ if (rec->pack_type & PACK_TYPE_SELECTED)
+ return &uf_prespace_selected;
+ return &uf_prespace;
+ case FIELD_CONSTANT:
+ return &uf_constant;
+ case FIELD_INTERVALL:
+ return &uf_intervall;
+ case FIELD_ZERO:
+ case FIELD_CHECK:
+ return &uf_zero;
+ case FIELD_BLOB:
+ return &uf_blob;
+ case FIELD_VARCHAR:
+ if (rec->length <= 256) /* 255 + 1 uchar length */
+ return &uf_varchar1;
+ return &uf_varchar2;
+ case FIELD_LAST:
+ default:
+ return 0; /* This should never happend */
+ }
+}
+
+ /* The different functions to unpack a field */
+
+static void uf_zerofill_skip_zero(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero((char*) to,(uint) (end-to));
+ else
+ {
+ end-=rec->space_length_bits;
+ decode_bytes(rec,bit_buff,to,end);
+ bzero((char*) end,rec->space_length_bits);
+ }
+}
+
+static void uf_skip_zero(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero((char*) to,(uint) (end-to));
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_normal(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bfill((uchar*) to,(end-to),' ');
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_endspace_selected(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((uchar*) to,(end-to),' ');
+ else
+ {
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((uchar*) end-spaces,spaces,' ');
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+ }
+}
+
+static void uf_endspace_selected(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((uchar*) end-spaces,spaces,' ');
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+static void uf_space_endspace(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((uchar*) to,(end-to),' ');
+ else
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((uchar*) end-spaces,spaces,' ');
+ }
+}
+
+static void uf_endspace(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to,end-spaces);
+ bfill((uchar*) end-spaces,spaces,' ');
+}
+
+static void uf_space_prespace_selected(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((uchar*) to,(end-to),' ');
+ else
+ {
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((uchar*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+ }
+}
+
+
+static void uf_prespace_selected(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((uchar*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+ else
+ decode_bytes(rec,bit_buff,to,end);
+}
+
+
+static void uf_space_prespace(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if (get_bit(bit_buff))
+ bfill((uchar*) to,(end-to),' ');
+ else
+ {
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((uchar*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+ }
+}
+
+static void uf_prespace(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ uint spaces;
+ if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
+ {
+ bit_buff->error=1;
+ return;
+ }
+ bfill((uchar*) to,spaces,' ');
+ if (to+spaces != end)
+ decode_bytes(rec,bit_buff,to+spaces,end);
+}
+
+static void uf_zerofill_normal(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ end-=rec->space_length_bits;
+ decode_bytes(rec,bit_buff, to, end);
+ bzero((char*) end,rec->space_length_bits);
+}
+
+static void uf_constant(MARIA_COLUMNDEF *rec,
+ MARIA_BIT_BUFF *bit_buff __attribute__((unused)),
+ uchar *to, uchar *end)
+{
+ memcpy(to,rec->huff_tree->intervalls,(size_t) (end-to));
+}
+
+static void uf_intervall(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to,
+ uchar *end)
+{
+ reg1 uint field_length=(uint) (end-to);
+ memcpy(to,rec->huff_tree->intervalls+field_length*decode_pos(bit_buff,
+ rec->huff_tree),
+ (size_t) field_length);
+}
+
+
+/*ARGSUSED*/
+static void uf_zero(MARIA_COLUMNDEF *rec __attribute__((unused)),
+ MARIA_BIT_BUFF *bit_buff __attribute__((unused)),
+ uchar *to, uchar *end)
+{
+ bzero(to, (uint) (end-to));
+}
+
+static void uf_blob(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ if (get_bit(bit_buff))
+ bzero(to, (uint) (end-to));
+ else
+ {
+ ulong length=get_bits(bit_buff,rec->space_length_bits);
+ uint pack_length=(uint) (end-to)-portable_sizeof_char_ptr;
+ if (bit_buff->blob_pos+length > bit_buff->blob_end)
+ {
+ bit_buff->error=1;
+ bzero((uchar*) to,(end-to));
+ return;
+ }
+ decode_bytes(rec,bit_buff,(uchar*) bit_buff->blob_pos,
+ (uchar*) bit_buff->blob_pos+length);
+ _ma_store_blob_length((uchar*) to,pack_length,length);
+ memcpy_fixed((char*) to+pack_length,(char*) &bit_buff->blob_pos,
+ sizeof(char*));
+ bit_buff->blob_pos+=length;
+ }
+}
+
+
+static void uf_varchar1(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end __attribute__((unused)))
+{
+ if (get_bit(bit_buff))
+ to[0]= 0; /* Zero lengths */
+ else
+ {
+ ulong length=get_bits(bit_buff,rec->space_length_bits);
+ *to= (char) length;
+ decode_bytes(rec,bit_buff,to+1,to+1+length);
+ }
+}
+
+
+static void uf_varchar2(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end __attribute__((unused)))
+{
+ if (get_bit(bit_buff))
+ to[0]=to[1]=0; /* Zero lengths */
+ else
+ {
+ ulong length=get_bits(bit_buff,rec->space_length_bits);
+ int2store(to,length);
+ decode_bytes(rec,bit_buff,to+2,to+2+length);
+ }
+}
+
+ /* Functions to decode of buffer of bits */
+
+#if BITS_SAVED == 64
+
+static void decode_bytes(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ reg1 uint bits,low_byte;
+ reg3 uint16 *pos;
+ reg4 uint table_bits,table_and;
+ MARIA_DECODE_TREE *decode_tree;
+
+ decode_tree=rec->decode_tree;
+ bits=bit_buff->bits; /* Save in reg for quicker access */
+ table_bits=decode_tree->quick_table_bits;
+ table_and= (1 << table_bits)-1;
+
+ do
+ {
+ if (bits <= 32)
+ {
+ if (bit_buff->pos > bit_buff->end+4)
+ {
+ bit_buff->error=1;
+ return; /* Can't be right */
+ }
+ bit_buff->current_byte= (bit_buff->current_byte << 32) +
+ ((((uint) bit_buff->pos[3])) +
+ (((uint) bit_buff->pos[2]) << 8) +
+ (((uint) bit_buff->pos[1]) << 16) +
+ (((uint) bit_buff->pos[0]) << 24));
+ bit_buff->pos+=4;
+ bits+=32;
+ }
+ /*
+ First use info in quick_table.
+
+ The quick table is an array of 16-bit values. There exists one
+ value for each possible code representable by table_bits bits.
+ In most cases table_bits is 9. So there are 512 16-bit values.
+
+ If the high-order bit (16) is set (IS_CHAR) then the array slot
+ for this value is a valid Huffman code for a resulting uchar value.
+
+ The low-order 8 bits (1..8) are the resulting uchar value.
+
+ Bits 9..14 are the length of the Huffman code for this uchar value.
+ This means so many bits from the input stream were needed to
+ represent this uchar value. The remaining bits belong to later
+ Huffman codes. This also means that for every Huffman code shorter
+ than table_bits there are multiple entires in the array, which
+ differ just in the unused bits.
+
+ If the high-order bit (16) is clear (0) then the remaining bits are
+ the position of the remaining Huffman decode tree segment behind the
+ quick table.
+ */
+ low_byte=(uint) (bit_buff->current_byte >> (bits - table_bits)) & table_and;
+ low_byte=decode_tree->table[low_byte];
+ if (low_byte & IS_CHAR)
+ {
+ /*
+ All Huffman codes of less or equal table_bits length are in the
+ quick table. This is one of them.
+ */
+ *to++ = (char) (low_byte & 255); /* Found char in quick table */
+ bits-= ((low_byte >> 8) & 31); /* Remove bits used */
+ }
+ else
+ { /* Map through rest of decode-table */
+ /* This means that the Huffman code must be longer than table_bits. */
+ pos=decode_tree->table+low_byte;
+ bits-=table_bits;
+ /* NOTE: decode_bytes_test_bit() is a macro wich contains a break !!! */
+ for (;;)
+ {
+ low_byte=(uint) (bit_buff->current_byte >> (bits-8));
+ decode_bytes_test_bit(0);
+ decode_bytes_test_bit(1);
+ decode_bytes_test_bit(2);
+ decode_bytes_test_bit(3);
+ decode_bytes_test_bit(4);
+ decode_bytes_test_bit(5);
+ decode_bytes_test_bit(6);
+ decode_bytes_test_bit(7);
+ bits-=8;
+ }
+ *to++ = (char) *pos;
+ }
+ } while (to != end);
+
+ bit_buff->bits=bits;
+ return;
+}
+
+#else
+
+static void decode_bytes(MARIA_COLUMNDEF *rec, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *end)
+{
+ reg1 uint bits,low_byte;
+ reg3 uint16 *pos;
+ reg4 uint table_bits,table_and;
+ MARIA_DECODE_TREE *decode_tree;
+
+ decode_tree=rec->huff_tree;
+ bits=bit_buff->bits; /* Save in reg for quicker access */
+ table_bits=decode_tree->quick_table_bits;
+ table_and= (1 << table_bits)-1;
+
+ do
+ {
+ if (bits < table_bits)
+ {
+ if (bit_buff->pos > bit_buff->end+1)
+ {
+ bit_buff->error=1;
+ return; /* Can't be right */
+ }
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (bit_buff->current_byte << 24) +
+ (((uint) ((uchar) bit_buff->pos[2]))) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 16);
+ bit_buff->pos+=3;
+ bits+=24;
+#else
+ if (bits) /* We must have at leasts 9 bits */
+ {
+ bit_buff->current_byte= (bit_buff->current_byte << 8) +
+ (uint) ((uchar) bit_buff->pos[0]);
+ bit_buff->pos++;
+ bits+=8;
+ }
+ else
+ {
+ bit_buff->current_byte= ((uint) ((uchar) bit_buff->pos[0]) << 8) +
+ ((uint) ((uchar) bit_buff->pos[1]));
+ bit_buff->pos+=2;
+ bits+=16;
+ }
+#endif
+ }
+ /* First use info in quick_table */
+ low_byte=(bit_buff->current_byte >> (bits - table_bits)) & table_and;
+ low_byte=decode_tree->table[low_byte];
+ if (low_byte & IS_CHAR)
+ {
+ *to++ = (low_byte & 255); /* Found char in quick table */
+ bits-= ((low_byte >> 8) & 31); /* Remove bits used */
+ }
+ else
+ { /* Map through rest of decode-table */
+ pos=decode_tree->table+low_byte;
+ bits-=table_bits;
+ for (;;)
+ {
+ if (bits < 8)
+ { /* We don't need to check end */
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (bit_buff->current_byte << 24) +
+ (((uint) ((uchar) bit_buff->pos[2]))) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 16);
+ bit_buff->pos+=3;
+ bits+=24;
+#else
+ bit_buff->current_byte= (bit_buff->current_byte << 8) +
+ (uint) ((uchar) bit_buff->pos[0]);
+ bit_buff->pos+=1;
+ bits+=8;
+#endif
+ }
+ low_byte=(uint) (bit_buff->current_byte >> (bits-8));
+ decode_bytes_test_bit(0);
+ decode_bytes_test_bit(1);
+ decode_bytes_test_bit(2);
+ decode_bytes_test_bit(3);
+ decode_bytes_test_bit(4);
+ decode_bytes_test_bit(5);
+ decode_bytes_test_bit(6);
+ decode_bytes_test_bit(7);
+ bits-=8;
+ }
+ *to++ = (char) *pos;
+ }
+ } while (to != end);
+
+ bit_buff->bits=bits;
+ return;
+}
+#endif /* BIT_SAVED == 64 */
+
+
+static uint decode_pos(MARIA_BIT_BUFF *bit_buff,
+ MARIA_DECODE_TREE *decode_tree)
+{
+ uint16 *pos=decode_tree->table;
+ for (;;)
+ {
+ if (get_bit(bit_buff))
+ pos++;
+ if (*pos & IS_CHAR)
+ return (uint) (*pos & ~IS_CHAR);
+ pos+= *pos;
+ }
+}
+
+
+int _ma_read_rnd_pack_record(MARIA_HA *info,
+ uchar *buf,
+ register MARIA_RECORD_POS filepos,
+ my_bool skip_deleted_blocks)
+{
+ File file;
+ MARIA_BLOCK_INFO block_info;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_read_rnd_pack_record");
+
+ if (filepos >= info->state->data_file_length)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ goto err;
+ }
+
+ file= info->dfile.file;
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_ma_read_cache(&info->rec_cache, (uchar*) block_info.header,
+ filepos, share->pack.ref_length,
+ skip_deleted_blocks ? READING_NEXT : 0))
+ goto err;
+ file= -1;
+ }
+ if (_ma_pack_get_block_info(info, &info->bit_buff, &block_info,
+ &info->rec_buff, &info->rec_buff_size,
+ file, filepos))
+ goto err; /* Error code is already set */
+#ifndef DBUG_OFF
+ if (block_info.rec_len > share->max_pack_length)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+#endif
+
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (_ma_read_cache(&info->rec_cache, (uchar*) info->rec_buff,
+ block_info.filepos, block_info.rec_len,
+ skip_deleted_blocks ? READING_NEXT : 0))
+ goto err;
+ }
+ else
+ {
+ if (my_read(info->dfile.file, (uchar*)info->rec_buff + block_info.offset,
+ block_info.rec_len-block_info.offset,
+ MYF(MY_NABP)))
+ goto err;
+ }
+ info->packed_length= block_info.rec_len;
+ info->cur_row.lastpos= filepos;
+ info->cur_row.nextpos= block_info.filepos+block_info.rec_len;
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+
+ DBUG_RETURN (_ma_pack_rec_unpack(info, &info->bit_buff, buf,
+ info->rec_buff, block_info.rec_len));
+ err:
+ DBUG_RETURN(my_errno);
+}
+
+
+ /* Read and process header from a huff-record-file */
+
+uint _ma_pack_get_block_info(MARIA_HA *maria, MARIA_BIT_BUFF *bit_buff,
+ MARIA_BLOCK_INFO *info,
+ uchar **rec_buff_p, size_t *rec_buff_size_p,
+ File file, my_off_t filepos)
+{
+ uchar *header= info->header;
+ uint head_length,ref_length;
+ LINT_INIT(ref_length);
+
+ if (file >= 0)
+ {
+ ref_length=maria->s->pack.ref_length;
+ /*
+ We can't use my_pread() here because _ma_read_rnd_pack_record assumes
+ position is ok
+ */
+ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
+ if (my_read(file, header,ref_length,MYF(MY_NABP)))
+ return BLOCK_FATAL_ERROR;
+ DBUG_DUMP("header",(uchar*) header,ref_length);
+ }
+ head_length= read_pack_length((uint) maria->s->pack.version, header,
+ &info->rec_len);
+ if (maria->s->base.blobs)
+ {
+ head_length+= read_pack_length((uint) maria->s->pack.version,
+ header + head_length, &info->blob_len);
+ /*
+ Ensure that the record buffer is big enough for the compressed
+ record plus all expanded blobs. [We do not have an extra buffer
+ for the resulting blobs. Sigh.]
+ */
+ if (_ma_alloc_buffer(rec_buff_p, rec_buff_size_p,
+ info->rec_len + info->blob_len +
+ maria->s->base.extra_rec_buff_size))
+ return BLOCK_FATAL_ERROR; /* not enough memory */
+ bit_buff->blob_pos= (uchar*) *rec_buff_p + info->rec_len;
+ bit_buff->blob_end= bit_buff->blob_pos + info->blob_len;
+ maria->blob_length=info->blob_len;
+ }
+ info->filepos=filepos+head_length;
+ if (file > 0)
+ {
+ info->offset=min(info->rec_len, ref_length - head_length);
+ memcpy(*rec_buff_p, header + head_length, info->offset);
+ }
+ return 0;
+}
+
+
+ /* rutines for bit buffer */
+ /* Note buffer must be 6 uchar bigger than longest row */
+
+static void init_bit_buffer(MARIA_BIT_BUFF *bit_buff, uchar *buffer,
+ uint length)
+{
+ bit_buff->pos=buffer;
+ bit_buff->end=buffer+length;
+ bit_buff->bits=bit_buff->error=0;
+ bit_buff->current_byte=0; /* Avoid purify errors */
+}
+
+static uint fill_and_get_bits(MARIA_BIT_BUFF *bit_buff, uint count)
+{
+ uint tmp;
+ count-=bit_buff->bits;
+ tmp=(bit_buff->current_byte & mask[bit_buff->bits]) << count;
+ fill_buffer(bit_buff);
+ bit_buff->bits=BITS_SAVED - count;
+ return tmp+(bit_buff->current_byte >> (BITS_SAVED - count));
+}
+
+ /* Fill in empty bit_buff->current_byte from buffer */
+ /* Sets bit_buff->error if buffer is exhausted */
+
+static void fill_buffer(MARIA_BIT_BUFF *bit_buff)
+{
+ if (bit_buff->pos >= bit_buff->end)
+ {
+ bit_buff->error= 1;
+ bit_buff->current_byte=0;
+ return;
+ }
+#if BITS_SAVED == 64
+ bit_buff->current_byte= ((((uint) ((uchar) bit_buff->pos[7]))) +
+ (((uint) ((uchar) bit_buff->pos[6])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[5])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[4])) << 24) +
+ ((ulonglong)
+ ((((uint) ((uchar) bit_buff->pos[3]))) +
+ (((uint) ((uchar) bit_buff->pos[2])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 24)) << 32));
+ bit_buff->pos+=8;
+#else
+#if BITS_SAVED == 32
+ bit_buff->current_byte= (((uint) ((uchar) bit_buff->pos[3])) +
+ (((uint) ((uchar) bit_buff->pos[2])) << 8) +
+ (((uint) ((uchar) bit_buff->pos[1])) << 16) +
+ (((uint) ((uchar) bit_buff->pos[0])) << 24));
+ bit_buff->pos+=4;
+#else
+ bit_buff->current_byte= (uint) (((uint) ((uchar) bit_buff->pos[1]))+
+ (((uint) ((uchar) bit_buff->pos[0])) << 8));
+ bit_buff->pos+=2;
+#endif
+#endif
+}
+
+ /* Get number of bits neaded to represent value */
+
+static uint max_bit(register uint value)
+{
+ reg2 uint power=1;
+
+ while ((value>>=1))
+ power++;
+ return (power);
+}
+
+
+/*****************************************************************************
+ Some redefined functions to handle files when we are using memmap
+*****************************************************************************/
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#ifdef HAVE_MMAP
+
+static int _ma_read_mempack_record(MARIA_HA *info, uchar *buf,
+ MARIA_RECORD_POS filepos);
+static int _ma_read_rnd_mempack_record(MARIA_HA*, uchar *, MARIA_RECORD_POS,
+ my_bool);
+
+my_bool _ma_memmap_file(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("maria_memmap_file");
+
+ if (!info->s->file_map)
+ {
+ if (my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0)) <
+ share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN)
+ {
+ DBUG_PRINT("warning",("File isn't extended for memmap"));
+ DBUG_RETURN(0);
+ }
+ if (_ma_dynmap_file(info, share->state.state.data_file_length))
+ DBUG_RETURN(0);
+ }
+ info->opt_flag|= MEMMAP_USED;
+ info->read_record= share->read_record= _ma_read_mempack_record;
+ share->scan= _ma_read_rnd_mempack_record;
+ DBUG_RETURN(1);
+}
+
+
+void _ma_unmap_file(MARIA_HA *info)
+{
+ VOID(my_munmap((char*) info->s->file_map,
+ (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN));
+}
+
+
+static uchar *
+_ma_mempack_get_block_info(MARIA_HA *maria,
+ MARIA_BIT_BUFF *bit_buff,
+ MARIA_BLOCK_INFO *info,
+ uchar **rec_buff_p,
+ size_t *rec_buff_size_p,
+ uchar *header)
+{
+ header+= read_pack_length((uint) maria->s->pack.version, header,
+ &info->rec_len);
+ if (maria->s->base.blobs)
+ {
+ header+= read_pack_length((uint) maria->s->pack.version, header,
+ &info->blob_len);
+ /* _ma_alloc_rec_buff sets my_errno on error */
+ if (_ma_alloc_buffer(rec_buff_p, rec_buff_size_p,
+ info->blob_len + maria->s->base.extra_rec_buff_size))
+ return 0; /* not enough memory */
+ bit_buff->blob_pos= (uchar*) *rec_buff_p;
+ bit_buff->blob_end= (uchar*) *rec_buff_p + info->blob_len;
+ }
+ return header;
+}
+
+
+static int _ma_read_mempack_record(MARIA_HA *info, uchar *buf,
+ MARIA_RECORD_POS filepos)
+{
+ MARIA_BLOCK_INFO block_info;
+ MARIA_SHARE *share= info->s;
+ uchar *pos;
+ DBUG_ENTER("maria_read_mempack_record");
+
+ if (filepos == HA_OFFSET_ERROR)
+ DBUG_RETURN(my_errno); /* _search() didn't find record */
+
+ if (!(pos= (uchar*) _ma_mempack_get_block_info(info, &info->bit_buff,
+ &block_info, &info->rec_buff,
+ &info->rec_buff_size,
+ (uchar*) share->file_map+
+ filepos)))
+ DBUG_RETURN(my_errno);
+ DBUG_RETURN(_ma_pack_rec_unpack(info, &info->bit_buff, buf,
+ pos, block_info.rec_len));
+}
+
+
+/*ARGSUSED*/
+static int _ma_read_rnd_mempack_record(MARIA_HA *info,
+ uchar *buf,
+ register MARIA_RECORD_POS filepos,
+ my_bool skip_deleted_blocks
+ __attribute__((unused)))
+{
+ MARIA_BLOCK_INFO block_info;
+ MARIA_SHARE *share= info->s;
+ uchar *pos,*start;
+ DBUG_ENTER("_ma_read_rnd_mempack_record");
+
+ if (filepos >= share->state.state.data_file_length)
+ {
+ my_errno=HA_ERR_END_OF_FILE;
+ goto err;
+ }
+ if (!(pos= (uchar*) _ma_mempack_get_block_info(info, &info->bit_buff,
+ &block_info,
+ &info->rec_buff,
+ &info->rec_buff_size,
+ (uchar*)
+ (start= share->file_map +
+ filepos))))
+ goto err;
+#ifndef DBUG_OFF
+ if (block_info.rec_len > info->s->max_pack_length)
+ {
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+#endif
+ info->packed_length=block_info.rec_len;
+ info->cur_row.lastpos= filepos;
+ info->cur_row.nextpos= filepos+(uint) (pos-start)+block_info.rec_len;
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+
+ DBUG_RETURN (_ma_pack_rec_unpack(info, &info->bit_buff, buf,
+ pos, block_info.rec_len));
+ err:
+ DBUG_RETURN(my_errno);
+}
+
+#endif /* HAVE_MMAP */
+
+ /* Save length of row */
+
+uint _ma_save_pack_length(uint version, uchar *block_buff, ulong length)
+{
+ if (length < 254)
+ {
+ *(uchar*) block_buff= (uchar) length;
+ return 1;
+ }
+ if (length <= 65535)
+ {
+ *(uchar*) block_buff=254;
+ int2store(block_buff+1,(uint) length);
+ return 3;
+ }
+ *(uchar*) block_buff=255;
+ if (version == 1) /* old format */
+ {
+ DBUG_ASSERT(length <= 0xFFFFFF);
+ int3store(block_buff + 1, (ulong) length);
+ return 4;
+ }
+ else
+ {
+ int4store(block_buff + 1, (ulong) length);
+ return 5;
+ }
+}
+
+
+static uint read_pack_length(uint version, const uchar *buf, ulong *length)
+{
+ if (buf[0] < 254)
+ {
+ *length= buf[0];
+ return 1;
+ }
+ else if (buf[0] == 254)
+ {
+ *length= uint2korr(buf + 1);
+ return 3;
+ }
+ if (version == 1) /* old format */
+ {
+ *length= uint3korr(buf + 1);
+ return 4;
+ }
+ else
+ {
+ *length= uint4korr(buf + 1);
+ return 5;
+ }
+}
+
+
+uint _ma_calc_pack_length(uint version, ulong length)
+{
+ return (length < 254) ? 1 : (length < 65536) ? 3 : (version == 1) ? 4 : 5;
+}
diff --git a/storage/maria/ma_page.c b/storage/maria/ma_page.c
new file mode 100644
index 00000000000..afe40aad399
--- /dev/null
+++ b/storage/maria/ma_page.c
@@ -0,0 +1,540 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Read and write key blocks
+
+ The basic structure of a key block is as follows:
+
+ LSN 7 (LSN_STORE_SIZE); Log number for last change;
+ Only for transactional pages
+ PACK_TRANSID 6 (TRANSID_SIZE); Relative transid to pack page transid's
+ Only for transactional pages
+ KEYNR 1 (KEYPAGE_KEYID_SIZE) Which index this page belongs to
+ FLAG 1 (KEYPAGE_FLAG_SIZE) Flags for page
+ PAGE_SIZE 2 (KEYPAGE_USED_SIZE) How much of the page is used.
+ high-byte-first
+
+ The flag is a combination of the following values:
+
+ KEYPAGE_FLAG_ISNOD Page is a node
+ KEYPAGE_FLAG_HAS_TRANSID There may be a transid on the page.
+
+ After this we store key data, either packed or not packed, directly
+ after each other. If the page is a node flag, there is a pointer to
+ the next key page at page start and after each key.
+
+ At end of page the last KEYPAGE_CHECKSUM_SIZE bytes are reserved for a
+ page checksum.
+*/
+
+#include "maria_def.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+
+/* Fetch a key-page in memory */
+
+uchar *_ma_fetch_keypage(register MARIA_HA *info,
+ const MARIA_KEYDEF *keyinfo __attribute__ ((unused)),
+ my_off_t pos, enum pagecache_page_lock lock,
+ int level, uchar *buff,
+ int return_buffer __attribute__ ((unused)),
+ MARIA_PINNED_PAGE **page_link_res)
+{
+ uchar *tmp;
+ MARIA_PINNED_PAGE page_link;
+ MARIA_SHARE *share= info->s;
+ uint block_size= share->block_size;
+ DBUG_ENTER("_ma_fetch_keypage");
+ DBUG_PRINT("enter",("pos: %ld", (long) pos));
+
+ tmp= pagecache_read(share->pagecache, &share->kfile,
+ (pgcache_page_no_t) (pos / block_size), level, buff,
+ share->page_type, lock, &page_link.link);
+
+ if (lock != PAGECACHE_LOCK_LEFT_UNLOCKED)
+ {
+ DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE);
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 0;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ *page_link_res= dynamic_element(&info->pinned_pages,
+ info->pinned_pages.elements-1,
+ MARIA_PINNED_PAGE *);
+ }
+
+ if (tmp == info->buff)
+ info->keyread_buff_used=1;
+ else if (!tmp)
+ {
+ DBUG_PRINT("error",("Got errno: %d from pagecache_read",my_errno));
+ info->last_keypage=HA_OFFSET_ERROR;
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
+ }
+ info->last_keypage= pos;
+#ifdef EXTRA_DEBUG
+ {
+ uint page_size= _ma_get_page_used(share, tmp);
+ if (page_size < 4 || page_size > block_size ||
+ _ma_get_keynr(share, tmp) != keyinfo->key_nr)
+ {
+ DBUG_PRINT("error",("page %lu had wrong page length: %u keynr: %u",
+ (ulong) (pos / block_size), page_size,
+ _ma_get_keynr(share, tmp)));
+ DBUG_DUMP("page", tmp, page_size);
+ info->last_keypage = HA_OFFSET_ERROR;
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno= HA_ERR_CRASHED;
+ tmp= 0;
+ }
+ }
+#endif
+ DBUG_RETURN(tmp);
+} /* _ma_fetch_keypage */
+
+
+/* Write a key-page on disk */
+
+int _ma_write_keypage(register MARIA_HA *info,
+ register const MARIA_KEYDEF *keyinfo
+ __attribute__((unused)),
+ my_off_t pos, enum pagecache_page_lock lock,
+ int level, uchar *buff)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_PINNED_PAGE page_link;
+ uint block_size= share->block_size;
+ int res;
+ DBUG_ENTER("_ma_write_keypage");
+
+#ifdef EXTRA_DEBUG /* Safety check */
+ {
+ uint page_length, nod;
+ _ma_get_used_and_nod(share, buff, page_length, nod);
+ if (pos < share->base.keystart ||
+ pos+block_size > share->state.state.key_file_length ||
+ (pos & (maria_block_size-1)))
+ {
+ DBUG_PRINT("error",("Trying to write inside key status region: "
+ "key_start: %lu length: %lu page: %lu",
+ (long) share->base.keystart,
+ (long) share->state.state.key_file_length,
+ (long) pos));
+ my_errno=EINVAL;
+ DBUG_ASSERT(0);
+ DBUG_RETURN((-1));
+ }
+ DBUG_PRINT("page",("write page at: %lu",(long) pos));
+ DBUG_DUMP("buff", buff, page_length);
+ DBUG_ASSERT(page_length >= share->keypage_header + nod +
+ keyinfo->minlength || maria_in_recovery);
+ }
+#endif
+
+ /* Verify that keynr is correct */
+ DBUG_ASSERT(_ma_get_keynr(share, buff) == keyinfo->key_nr);
+
+#if defined(EXTRA_DEBUG) && defined(HAVE_purify) && defined(NOT_ANYMORE)
+ {
+ /* This is here to catch uninitialized bytes */
+ uint length= _ma_get_page_used(share, buff);
+ ulong crc= my_checksum(0, buff, length);
+ int4store(buff + block_size - KEYPAGE_CHECKSUM_SIZE, crc);
+ }
+#endif
+
+#ifdef IDENTICAL_PAGES_AFTER_RECOVERY
+ {
+ uint length= _ma_get_page_used(share, buff);
+ DBUG_ASSERT(length <= block_size - KEYPAGE_CHECKSUM_SIZE);
+ bzero(buff + length, block_size - length);
+ }
+#endif
+ DBUG_ASSERT(share->pagecache->block_size == block_size);
+
+ res= pagecache_write(share->pagecache,
+ &share->kfile, (pgcache_page_no_t) (pos / block_size),
+ level, buff, share->page_type,
+ lock,
+ lock == PAGECACHE_LOCK_LEFT_WRITELOCKED ?
+ PAGECACHE_PIN_LEFT_PINNED :
+ (lock == PAGECACHE_LOCK_WRITE_UNLOCK ?
+ PAGECACHE_UNPIN : PAGECACHE_PIN),
+ PAGECACHE_WRITE_DELAY, &page_link.link,
+ LSN_IMPOSSIBLE);
+
+ if (lock == PAGECACHE_LOCK_WRITE)
+ {
+ /* It was not locked before, we have to unlock it when we unpin pages */
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ }
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Put page in free list
+
+ @fn _ma_dispose()
+ @param info Maria handle
+ @param pos Address to page
+ @param page_not_read 1 if page has not yet been read
+
+ @note
+ The page at 'pos' must have been read with a write lock.
+ This function does logging (unlike _ma_new()).
+
+ @return
+ @retval 0 ok
+ @retval 1 error
+
+*/
+
+int _ma_dispose(register MARIA_HA *info, my_off_t pos, my_bool page_not_read)
+{
+ my_off_t old_link;
+ uchar buff[MAX_KEYPAGE_HEADER_SIZE+ 8 + 2];
+ ulonglong page_no;
+ MARIA_SHARE *share= info->s;
+ MARIA_PINNED_PAGE page_link;
+ uint block_size= share->block_size;
+ int result= 0;
+ enum pagecache_page_lock lock_method;
+ enum pagecache_page_pin pin_method;
+ DBUG_ENTER("_ma_dispose");
+ DBUG_PRINT("enter",("pos: %ld", (long) pos));
+ DBUG_ASSERT(pos % block_size == 0);
+
+ (void) _ma_lock_key_del(info, 0);
+
+ old_link= share->key_del_current;
+ share->key_del_current= pos;
+ page_no= pos / block_size;
+ bzero(buff, share->keypage_header);
+ _ma_store_keynr(share, buff, (uchar) MARIA_DELETE_KEY_NR);
+ _ma_store_page_used(share, buff, share->keypage_header + 8);
+ mi_sizestore(buff + share->keypage_header, old_link);
+ share->state.changed|= STATE_NOT_SORTED_PAGES;
+
+ if (share->now_transactional)
+ {
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ my_off_t page;
+
+ /* Store address of deleted page */
+ page_store(log_data + FILEID_STORE_SIZE, page_no);
+
+ /* Store link to next unused page (the link that is written to page) */
+ page= (old_link == HA_OFFSET_ERROR ? IMPOSSIBLE_PAGE_NO :
+ old_link / block_size);
+ page_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, page);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+
+ if (translog_write_record(&lsn, LOGREC_REDO_INDEX_FREE_PAGE,
+ info->trn, info,
+ (translog_size_t) sizeof(log_data),
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data, NULL))
+ result= 1;
+ }
+
+ if (page_not_read)
+ {
+ lock_method= PAGECACHE_LOCK_WRITE;
+ pin_method= PAGECACHE_PIN;
+ }
+ else
+ {
+ lock_method= PAGECACHE_LOCK_LEFT_WRITELOCKED;
+ pin_method= PAGECACHE_PIN_LEFT_PINNED;
+ }
+
+ if (pagecache_write_part(share->pagecache,
+ &share->kfile, (pgcache_page_no_t) page_no,
+ PAGECACHE_PRIORITY_LOW, buff,
+ share->page_type,
+ lock_method, pin_method,
+ PAGECACHE_WRITE_DELAY, &page_link.link,
+ LSN_IMPOSSIBLE,
+ 0, share->keypage_header + 8))
+ result= 1;
+
+#ifdef IDENTICAL_PAGES_AFTER_RECOVERY
+ {
+ uchar *page_buff= pagecache_block_link_to_buffer(page_link.link);
+ bzero(page_buff + share->keypage_header + 8,
+ block_size - share->keypage_header - 8 - KEYPAGE_CHECKSUM_SIZE);
+ }
+#endif
+
+ if (page_not_read)
+ {
+ /* It was not locked before, we have to unlock it when we unpin pages */
+ page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ page_link.changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) &page_link);
+ }
+
+ DBUG_RETURN(result);
+} /* _ma_dispose */
+
+
+/**
+ @brief Get address for free page to use
+
+ @fn _ma_new()
+ @param info Maria handle
+ @param level Type of key block (caching priority for pagecache)
+ @param page_link Pointer to page in page cache if read. One can
+ check if this is used by checking if
+ page_link->changed != 0
+
+ @note Logging of this is left to the caller (so that the "new"ing and the
+ first changes done to this new page can be logged as one single entry - one
+ single _ma_log_new()) call).
+
+ @return
+ HA_OFFSET_ERROR File is full or page read error
+ # Page address to use
+*/
+
+my_off_t _ma_new(register MARIA_HA *info, int level,
+ MARIA_PINNED_PAGE **page_link)
+
+{
+ my_off_t pos;
+ MARIA_SHARE *share= info->s;
+ uint block_size= share->block_size;
+ DBUG_ENTER("_ma_new");
+
+ if (_ma_lock_key_del(info, 1))
+ {
+ pthread_mutex_lock(&share->intern_lock);
+ pos= share->state.state.key_file_length;
+ if (pos >= share->base.max_key_file_length - block_size)
+ {
+ my_errno=HA_ERR_INDEX_FILE_FULL;
+ pthread_mutex_unlock(&share->intern_lock);
+ DBUG_RETURN(HA_OFFSET_ERROR);
+ }
+ share->state.state.key_file_length+= block_size;
+ /* Following is for not transactional tables */
+ info->state->key_file_length= share->state.state.key_file_length;
+ pthread_mutex_unlock(&share->intern_lock);
+ (*page_link)->changed= 0;
+ (*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
+ }
+ else
+ {
+ uchar *buff;
+ pos= share->key_del_current; /* Protected */
+ DBUG_ASSERT(share->pagecache->block_size == block_size);
+ if (!(buff= pagecache_read(share->pagecache,
+ &share->kfile,
+ (pgcache_page_no_t) (pos / block_size), level,
+ 0, share->page_type,
+ PAGECACHE_LOCK_WRITE, &(*page_link)->link)))
+ pos= HA_OFFSET_ERROR;
+ else
+ {
+ /*
+ Next deleted page's number is in the header of the present page
+ (single linked list):
+ */
+#ifndef DBUG_OFF
+ my_off_t key_del_current;
+#endif
+ share->key_del_current= mi_sizekorr(buff+share->keypage_header);
+#ifndef DBUG_OFF
+ key_del_current= share->key_del_current;
+ DBUG_ASSERT(key_del_current != share->state.key_del &&
+ (key_del_current != 0) &&
+ ((key_del_current == HA_OFFSET_ERROR) ||
+ (key_del_current <=
+ (share->state.state.key_file_length - block_size))));
+#endif
+ }
+
+ (*page_link)->unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
+ (*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
+ /*
+ We have to mark it changed as _ma_flush_pending_blocks() uses
+ 'changed' to know if we used the page cache or not
+ */
+ (*page_link)->changed= 1;
+ push_dynamic(&info->pinned_pages, (void*) *page_link);
+ *page_link= dynamic_element(&info->pinned_pages,
+ info->pinned_pages.elements-1,
+ MARIA_PINNED_PAGE *);
+ }
+ share->state.changed|= STATE_NOT_SORTED_PAGES;
+ DBUG_PRINT("exit",("Pos: %ld",(long) pos));
+ DBUG_RETURN(pos);
+} /* _ma_new */
+
+
+/**
+ Log compactation of a index page
+*/
+
+static my_bool _ma_log_compact_keypage(MARIA_HA *info, my_off_t page,
+ TrID min_read_from)
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 1 + TRANSID_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_log_compact_keypage");
+ DBUG_PRINT("enter", ("page: %lu", (ulong) page));
+
+ /* Store address of new root page */
+ page/= share->block_size;
+ page_store(log_data + FILEID_STORE_SIZE, page);
+
+ log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE]= KEY_OP_COMPACT_PAGE;
+ transid_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE +1,
+ min_read_from);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+
+ if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t) sizeof(log_data),
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data, NULL))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Remove all transaction id's less than given one from a key page
+
+ @fn _ma_compact_keypage()
+ @param keyinfo Key handler
+ @param page_pos Page position on disk
+ @param page Buffer for page
+ @param min_read_from Remove all trids from page less than this
+
+ @retval 0 Ok
+ ®retval 1 Error; my_errno contains the error
+*/
+
+my_bool _ma_compact_keypage(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ my_off_t page_pos, uchar *page, TrID min_read_from)
+{
+ MARIA_SHARE *share= keyinfo->share;
+ MARIA_KEY key;
+ uchar *start_of_page, *endpos, *start_of_empty_space;
+ uint page_flag, nod_flag, saved_space;
+ my_bool page_has_transid;
+ DBUG_ENTER("_ma_compact_keypage");
+
+ page_flag= _ma_get_keypage_flag(share, page);
+ if (!(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ DBUG_RETURN(0); /* No transaction id on page */
+
+ nod_flag= _ma_test_if_nod(share, page);
+ endpos= page + _ma_get_page_used(share, page);
+ key.data= info->lastkey_buff;
+ key.keyinfo= keyinfo;
+
+ start_of_page= page;
+ page_has_transid= 0;
+ page+= share->keypage_header + nod_flag;
+ key.data[0]= 0; /* safety */
+ start_of_empty_space= 0;
+ saved_space= 0;
+ do
+ {
+ if (!(page= (*keyinfo->skip_key)(&key, 0, 0, page)))
+ {
+ DBUG_PRINT("error",("Couldn't find last key: page: 0x%lx",
+ (long) page));
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(1);
+ }
+ if (key_has_transid(page-1))
+ {
+ uint transid_length;
+ transid_length= transid_packed_length(page);
+
+ if (min_read_from == ~(TrID) 0 ||
+ min_read_from < transid_get_packed(share, page))
+ {
+ page[-1]&= 254; /* Remove transid marker */
+ transid_length= transid_packed_length(page);
+ if (start_of_empty_space)
+ {
+ /* Move block before the transid up in page */
+ uint copy_length= (uint) (page - start_of_empty_space) - saved_space;
+ memmove(start_of_empty_space, start_of_empty_space + saved_space,
+ copy_length);
+ start_of_empty_space+= copy_length;
+ }
+ else
+ start_of_empty_space= page;
+ saved_space+= transid_length;
+ }
+ else
+ page_has_transid= 1; /* At least one id left */
+ page+= transid_length;
+ }
+ page+= nod_flag;
+ } while (page < endpos);
+
+ DBUG_ASSERT(page == endpos);
+
+ if (start_of_empty_space)
+ {
+ /*
+ Move last block down
+ This is always true if any transid was removed
+ */
+ uint copy_length= (uint) (endpos - start_of_empty_space) - saved_space;
+ uint page_length;
+
+ if (copy_length)
+ memmove(start_of_empty_space, start_of_empty_space + saved_space,
+ copy_length);
+ page_length= (uint) (start_of_empty_space + copy_length - start_of_page);
+ _ma_store_page_used(share, start_of_page, page_length);
+ }
+
+ if (!page_has_transid)
+ {
+ page_flag&= ~KEYPAGE_FLAG_HAS_TRANSID;
+ _ma_store_keypage_flag(share, start_of_page, page_flag);
+ /* Clear packed transid (in case of zerofill) */
+ bzero(start_of_page + LSN_STORE_SIZE, TRANSID_SIZE);
+ }
+
+ if (share->now_transactional)
+ {
+ if (_ma_log_compact_keypage(info, page_pos, min_read_from))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c
new file mode 100644
index 00000000000..3887d6af7bc
--- /dev/null
+++ b/storage/maria/ma_pagecache.c
@@ -0,0 +1,5100 @@
+/* Copyright (C) 2000-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ These functions handle page caching for Maria tables.
+
+ One cache can handle many files.
+ It must contain buffers of the same blocksize.
+ init_pagecache() should be used to init cache handler.
+
+ The free list (free_block_list) is a stack like structure.
+ When a block is freed by free_block(), it is pushed onto the stack.
+ When a new block is required it is first tried to pop one from the stack.
+ If the stack is empty, it is tried to get a never-used block from the pool.
+ If this is empty too, then a block is taken from the LRU ring, flushing it
+ to disk, if necessary. This is handled in find_block().
+ With the new free list, the blocks can have three temperatures:
+ hot, warm and cold (which is free). This is remembered in the block header
+ by the enum PCBLOCK_TEMPERATURE temperature variable. Remembering the
+ temperature is necessary to correctly count the number of warm blocks,
+ which is required to decide when blocks are allowed to become hot. Whenever
+ a block is inserted to another (sub-)chain, we take the old and new
+ temperature into account to decide if we got one more or less warm block.
+ blocks_unused is the sum of never used blocks in the pool and of currently
+ free blocks. blocks_used is the number of blocks fetched from the pool and
+ as such gives the maximum number of in-use blocks at any time.
+
+ TODO: Write operation locks whole cache till the end of the operation.
+ Should be fixed.
+*/
+
+#include "maria_def.h"
+#include <m_string.h>
+#include "ma_pagecache.h"
+#include "ma_blockrec.h"
+#include <my_bit.h>
+#include <errno.h>
+
+/*
+ Some compilation flags have been added specifically for this module
+ to control the following:
+ - not to let a thread to yield the control when reading directly
+ from page cache, which might improve performance in many cases;
+ to enable this add:
+ #define SERIALIZED_READ_FROM_CACHE
+ - to set an upper bound for number of threads simultaneously
+ using the page cache; this setting helps to determine an optimal
+ size for hash table and improve performance when the number of
+ blocks in the page cache much less than the number of threads
+ accessing it;
+ to set this number equal to <N> add
+ #define MAX_THREADS <N>
+ - to substitute calls of pthread_cond_wait for calls of
+ pthread_cond_timedwait (wait with timeout set up);
+ this setting should be used only when you want to trap a deadlock
+ situation, which theoretically should not happen;
+ to set timeout equal to <T> seconds add
+ #define PAGECACHE_TIMEOUT <T>
+ - to enable the module traps and to send debug information from
+ page cache module to a special debug log add:
+ #define PAGECACHE_DEBUG
+ the name of this debug log file <LOG NAME> can be set through:
+ #define PAGECACHE_DEBUG_LOG <LOG NAME>
+ if the name is not defined, it's set by default;
+ if the PAGECACHE_DEBUG flag is not set up and we are in a debug
+ mode, i.e. when ! defined(DBUG_OFF), the debug information from the
+ module is sent to the regular debug log.
+
+ Example of the settings:
+ #define SERIALIZED_READ_FROM_CACHE
+ #define MAX_THREADS 100
+ #define PAGECACHE_TIMEOUT 1
+ #define PAGECACHE_DEBUG
+ #define PAGECACHE_DEBUG_LOG "my_pagecache_debug.log"
+*/
+
+/*
+ In key cache we have external raw locking here we use
+ SERIALIZED_READ_FROM_CACHE to avoid problem of reading
+ not consistent data from the page.
+ (keycache functions (key_cache_read(), key_cache_insert() and
+ key_cache_write()) rely on external MyISAM lock, we don't)
+*/
+#define SERIALIZED_READ_FROM_CACHE yes
+
+#define PCBLOCK_INFO(B) \
+ DBUG_PRINT("info", \
+ ("block: 0x%lx fd: %lu page: %lu s: %0x hshL: " \
+ " 0x%lx req: %u/%u wrlocks: %u rdlocks %u " \
+ "rdlocks_q: %u pins: %u status: %u type: %s", \
+ (ulong)(B), \
+ (ulong)((B)->hash_link ? \
+ (B)->hash_link->file.file : \
+ 0), \
+ (ulong)((B)->hash_link ? \
+ (B)->hash_link->pageno : \
+ 0), \
+ (B)->status, \
+ (ulong)(B)->hash_link, \
+ (uint) (B)->requests, \
+ (uint)((B)->hash_link ? \
+ (B)->hash_link->requests : \
+ 0), \
+ block->wlocks, block->rlocks, block->rlocks_queue, \
+ (uint)(B)->pins, (uint)(B)->status, \
+ page_cache_page_type_str[(B)->type]))
+
+/* TODO: put it to my_static.c */
+my_bool my_disable_flush_pagecache_blocks= 0;
+
+#define STRUCT_PTR(TYPE, MEMBER, a) \
+ (TYPE *) ((char *) (a) - offsetof(TYPE, MEMBER))
+
+/* types of condition variables */
+#define COND_FOR_REQUESTED 0 /* queue of thread waiting for read operation */
+#define COND_FOR_SAVED 1 /* queue of thread waiting for flush */
+#define COND_FOR_WRLOCK 2 /* queue of write lock */
+#define COND_SIZE 3 /* number of COND_* queues */
+
+typedef pthread_cond_t KEYCACHE_CONDVAR;
+
+/* descriptor of the page in the page cache block buffer */
+struct st_pagecache_page
+{
+ PAGECACHE_FILE file; /* file to which the page belongs to */
+ pgcache_page_no_t pageno; /* number of the page in the file */
+};
+
+/* element in the chain of a hash table bucket */
+struct st_pagecache_hash_link
+{
+ struct st_pagecache_hash_link
+ *next, **prev; /* to connect links in the same bucket */
+ struct st_pagecache_block_link
+ *block; /* reference to the block for the page: */
+ PAGECACHE_FILE file; /* from such a file */
+ pgcache_page_no_t pageno; /* this page */
+ uint requests; /* number of requests for the page */
+};
+
+/* simple states of a block */
+#define PCBLOCK_ERROR 1 /* an error occurred when performing disk i/o */
+#define PCBLOCK_READ 2 /* the is page in the block buffer */
+#define PCBLOCK_IN_SWITCH 4 /* block is preparing to read new page */
+#define PCBLOCK_REASSIGNED 8 /* block does not accept requests for old page */
+#define PCBLOCK_IN_FLUSH 16 /* block is in flush operation */
+#define PCBLOCK_CHANGED 32 /* block buffer contains a dirty page */
+#define PCBLOCK_DIRECT_W 64 /* possible direct write to the block */
+
+/* page status, returned by find_block */
+#define PAGE_READ 0
+#define PAGE_TO_BE_READ 1
+#define PAGE_WAIT_TO_BE_READ 2
+
+/* block temperature determines in which (sub-)chain the block currently is */
+enum PCBLOCK_TEMPERATURE { PCBLOCK_COLD /*free*/ , PCBLOCK_WARM , PCBLOCK_HOT };
+
+/* debug info */
+#ifndef DBUG_OFF
+static const char *page_cache_page_type_str[]=
+{
+ /* used only for control page type changing during debugging */
+ "EMPTY",
+ "PLAIN",
+ "LSN",
+ "READ_UNKNOWN"
+};
+
+static const char *page_cache_page_write_mode_str[]=
+{
+ "DELAY",
+ "DONE"
+};
+
+static const char *page_cache_page_lock_str[]=
+{
+ "free -> free",
+ "read -> read",
+ "write -> write",
+ "free -> read",
+ "free -> write",
+ "read -> free",
+ "write -> free",
+ "write -> read"
+};
+
+static const char *page_cache_page_pin_str[]=
+{
+ "pinned -> pinned",
+ "unpinned -> unpinned",
+ "unpinned -> pinned",
+ "pinned -> unpinned"
+};
+
+
+typedef struct st_pagecache_pin_info
+{
+ struct st_pagecache_pin_info *next, **prev;
+ struct st_my_thread_var *thread;
+} PAGECACHE_PIN_INFO;
+
+/*
+ st_pagecache_lock_info structure should be kept in next, prev, thread part
+ compatible with st_pagecache_pin_info to be compatible in functions.
+*/
+
+typedef struct st_pagecache_lock_info
+{
+ struct st_pagecache_lock_info *next, **prev;
+ struct st_my_thread_var *thread;
+ my_bool write_lock;
+} PAGECACHE_LOCK_INFO;
+
+
+/* service functions maintain debugging info about pin & lock */
+
+
+/*
+ Links information about thread pinned/locked the block to the list
+
+ SYNOPSIS
+ info_link()
+ list the list to link in
+ node the node which should be linked
+*/
+
+static void info_link(PAGECACHE_PIN_INFO **list, PAGECACHE_PIN_INFO *node)
+{
+ if ((node->next= *list))
+ node->next->prev= &(node->next);
+ *list= node;
+ node->prev= list;
+}
+
+
+/*
+ Unlinks information about thread pinned/locked the block from the list
+
+ SYNOPSIS
+ info_unlink()
+ node the node which should be unlinked
+*/
+
+static void info_unlink(PAGECACHE_PIN_INFO *node)
+{
+ if ((*node->prev= node->next))
+ node->next->prev= node->prev;
+}
+
+
+/*
+ Finds information about given thread in the list of threads which
+ pinned/locked this block.
+
+ SYNOPSIS
+ info_find()
+ list the list where to find the thread
+ thread thread ID (reference to the st_my_thread_var
+ of the thread)
+ any return any thread of the list
+
+ RETURN
+ 0 - the thread was not found
+ pointer to the information node of the thread in the list, or, if 'any',
+ to any thread of the list.
+*/
+
+static PAGECACHE_PIN_INFO *info_find(PAGECACHE_PIN_INFO *list,
+ struct st_my_thread_var *thread,
+ my_bool any)
+{
+ register PAGECACHE_PIN_INFO *i= list;
+ if (any)
+ return i;
+ for(; i != 0; i= i->next)
+ if (i->thread == thread)
+ return i;
+ return 0;
+}
+
+#endif /* !DBUG_OFF */
+
+/* page cache block */
+struct st_pagecache_block_link
+{
+ struct st_pagecache_block_link
+ *next_used, **prev_used; /* to connect links in the LRU chain (ring) */
+ struct st_pagecache_block_link
+ *next_changed, **prev_changed; /* for lists of file dirty/clean blocks */
+ struct st_pagecache_hash_link
+ *hash_link; /* backward ptr to referring hash_link */
+#ifndef DBUG_OFF
+ PAGECACHE_PIN_INFO *pin_list;
+ PAGECACHE_LOCK_INFO *lock_list;
+#endif
+ KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */
+ uchar *buffer; /* buffer for the block page */
+ pthread_t write_locker;
+
+ ulonglong last_hit_time; /* timestamp of the last hit */
+ WQUEUE
+ wqueue[COND_SIZE]; /* queues on waiting requests for new/old pages */
+ uint32 requests; /* number of requests for the block */
+ uint32 pins; /* pin counter */
+ uint32 wlocks; /* write locks counter */
+ uint32 rlocks; /* read locks counter */
+ uint32 rlocks_queue; /* rd. locks waiting wr. lock of this thread */
+ uint16 status; /* state of the block */
+ int16 error; /* error code for block in case of error */
+ enum PCBLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot*/
+ enum pagecache_page_type type; /* type of the block */
+ uint hits_left; /* number of hits left until promotion */
+ /** @brief LSN when first became dirty; LSN_MAX means "not yet set" */
+ LSN rec_lsn;
+};
+
+/** @brief information describing a run of flush_pagecache_blocks_int() */
+struct st_file_in_flush
+{
+ File file;
+ /**
+ @brief threads waiting for the thread currently flushing this file to be
+ done
+ */
+ WQUEUE flush_queue;
+ /**
+ @brief if the thread currently flushing the file has a non-empty
+ first_in_switch list.
+ */
+ my_bool first_in_switch;
+};
+
+#ifndef DBUG_OFF
+/* debug checks */
+
+#ifdef NOT_USED
+static my_bool info_check_pin(PAGECACHE_BLOCK_LINK *block,
+ enum pagecache_page_pin mode
+ __attribute__((unused)))
+{
+ struct st_my_thread_var *thread= my_thread_var;
+ PAGECACHE_PIN_INFO *info= info_find(block->pin_list, thread);
+ DBUG_ENTER("info_check_pin");
+ DBUG_PRINT("enter", ("thread: 0x%lx pin: %s",
+ (ulong) thread, page_cache_page_pin_str[mode]));
+ if (info)
+ {
+ if (mode == PAGECACHE_PIN_LEFT_UNPINNED)
+ {
+ DBUG_PRINT("info",
+ ("info_check_pin: thread: 0x%lx block: 0x%lx ; LEFT_UNPINNED!!!",
+ (ulong)thread, (ulong)block));
+ DBUG_RETURN(1);
+ }
+ else if (mode == PAGECACHE_PIN)
+ {
+ DBUG_PRINT("info",
+ ("info_check_pin: thread: 0x%lx block: 0x%lx ; PIN!!!",
+ (ulong)thread, (ulong)block));
+ DBUG_RETURN(1);
+ }
+ }
+ else
+ {
+ if (mode == PAGECACHE_PIN_LEFT_PINNED)
+ {
+ DBUG_PRINT("info",
+ ("info_check_pin: thread: 0x%lx block: 0x%lx ; LEFT_PINNED!!!",
+ (ulong)thread, (ulong)block));
+ DBUG_RETURN(1);
+ }
+ else if (mode == PAGECACHE_UNPIN)
+ {
+ DBUG_PRINT("info",
+ ("info_check_pin: thread: 0x%lx block: 0x%lx ; UNPIN!!!",
+ (ulong)thread, (ulong)block));
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Debug function which checks current lock/pin state and requested changes
+
+ SYNOPSIS
+ info_check_lock()
+ lock requested lock changes
+ pin requested pin changes
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+static my_bool info_check_lock(PAGECACHE_BLOCK_LINK *block,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin)
+{
+ struct st_my_thread_var *thread= my_thread_var;
+ PAGECACHE_LOCK_INFO *info=
+ (PAGECACHE_LOCK_INFO *) info_find((PAGECACHE_PIN_INFO *) block->lock_list,
+ thread);
+ DBUG_ENTER("info_check_lock");
+ switch(lock) {
+ case PAGECACHE_LOCK_LEFT_UNLOCKED:
+ if (pin != PAGECACHE_PIN_LEFT_UNPINNED ||
+ info)
+ goto error;
+ break;
+ case PAGECACHE_LOCK_LEFT_READLOCKED:
+ if ((pin != PAGECACHE_PIN_LEFT_UNPINNED &&
+ pin != PAGECACHE_PIN_LEFT_PINNED) ||
+ info == 0 || info->write_lock)
+ goto error;
+ break;
+ case PAGECACHE_LOCK_LEFT_WRITELOCKED:
+ if (pin != PAGECACHE_PIN_LEFT_PINNED ||
+ info == 0 || !info->write_lock)
+ goto error;
+ break;
+ case PAGECACHE_LOCK_READ:
+ if ((pin != PAGECACHE_PIN_LEFT_UNPINNED &&
+ pin != PAGECACHE_PIN) ||
+ info != 0)
+ goto error;
+ break;
+ case PAGECACHE_LOCK_WRITE:
+ if (pin != PAGECACHE_PIN ||
+ info != 0)
+ goto error;
+ break;
+ case PAGECACHE_LOCK_READ_UNLOCK:
+ if ((pin != PAGECACHE_PIN_LEFT_UNPINNED &&
+ pin != PAGECACHE_UNPIN) ||
+ info == 0 || info->write_lock)
+ goto error;
+ break;
+ case PAGECACHE_LOCK_WRITE_UNLOCK:
+ if (pin != PAGECACHE_UNPIN ||
+ info == 0 || !info->write_lock)
+ goto error;
+ break;
+ case PAGECACHE_LOCK_WRITE_TO_READ:
+ if ((pin != PAGECACHE_PIN_LEFT_PINNED &&
+ pin != PAGECACHE_UNPIN) ||
+ info == 0 || !info->write_lock)
+ goto error;
+ break;
+ }
+ DBUG_RETURN(0);
+error:
+ DBUG_PRINT("info",
+ ("info_check_lock: thread: 0x%lx block 0x%lx: info: %d wrt: %d,"
+ "to lock: %s, to pin: %s",
+ (ulong)thread, (ulong)block, test(info),
+ (info ? info->write_lock : 0),
+ page_cache_page_lock_str[lock],
+ page_cache_page_pin_str[pin]));
+ DBUG_RETURN(1);
+}
+#endif /* NOT_USED */
+#endif /* !DBUG_OFF */
+
+#define FLUSH_CACHE 2000 /* sort this many blocks at once */
+
+static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block);
+#ifndef DBUG_OFF
+static void test_key_cache(PAGECACHE *pagecache,
+ const char *where, my_bool lock);
+#endif
+
+#define PAGECACHE_HASH(p, f, pos) (((ulong) (pos) + \
+ (ulong) (f).file) & (p->hash_entries-1))
+#define FILE_HASH(f) ((uint) (f).file & (PAGECACHE_CHANGED_BLOCKS_HASH - 1))
+
+#define DEFAULT_PAGECACHE_DEBUG_LOG "pagecache_debug.log"
+
+#if defined(PAGECACHE_DEBUG) && ! defined(PAGECACHE_DEBUG_LOG)
+#define PAGECACHE_DEBUG_LOG DEFAULT_PAGECACHE_DEBUG_LOG
+#endif
+
+#if defined(PAGECACHE_DEBUG_LOG)
+static FILE *pagecache_debug_log= NULL;
+static void pagecache_debug_print _VARARGS((const char *fmt, ...));
+#define PAGECACHE_DEBUG_OPEN \
+ if (!pagecache_debug_log) \
+ { \
+ pagecache_debug_log= fopen(PAGECACHE_DEBUG_LOG, "w"); \
+ (void) setvbuf(pagecache_debug_log, NULL, _IOLBF, BUFSIZ); \
+ }
+
+#define PAGECACHE_DEBUG_CLOSE \
+ if (pagecache_debug_log) \
+ { \
+ fclose(pagecache_debug_log); \
+ pagecache_debug_log= 0; \
+ }
+#else
+#define PAGECACHE_DEBUG_OPEN
+#define PAGECACHE_DEBUG_CLOSE
+#endif /* defined(PAGECACHE_DEBUG_LOG) */
+
+#if defined(PAGECACHE_DEBUG_LOG) && defined(PAGECACHE_DEBUG)
+#define KEYCACHE_DBUG_PRINT(l, m) \
+ { if (pagecache_debug_log) \
+ fprintf(pagecache_debug_log, "%s: ", l); \
+ pagecache_debug_print m; }
+
+#define KEYCACHE_DBUG_ASSERT(a) \
+ { if (! (a) && pagecache_debug_log) \
+ fclose(pagecache_debug_log); \
+ assert(a); }
+#else
+#define KEYCACHE_DBUG_PRINT(l, m) DBUG_PRINT(l, m)
+#define KEYCACHE_DBUG_ASSERT(a) DBUG_ASSERT(a)
+#endif /* defined(PAGECACHE_DEBUG_LOG) && defined(PAGECACHE_DEBUG) */
+
+#if defined(PAGECACHE_DEBUG) || !defined(DBUG_OFF)
+#ifdef THREAD
+static long pagecache_thread_id;
+#define KEYCACHE_THREAD_TRACE(l) \
+ KEYCACHE_DBUG_PRINT(l,("|thread %ld",pagecache_thread_id))
+
+#define KEYCACHE_THREAD_TRACE_BEGIN(l) \
+ { struct st_my_thread_var *thread_var= my_thread_var; \
+ pagecache_thread_id= thread_var->id; \
+ KEYCACHE_DBUG_PRINT(l,("[thread %ld",pagecache_thread_id)) }
+
+#define KEYCACHE_THREAD_TRACE_END(l) \
+ KEYCACHE_DBUG_PRINT(l,("]thread %ld",pagecache_thread_id))
+#else /* THREAD */
+#define KEYCACHE_THREAD_TRACE(l) KEYCACHE_DBUG_PRINT(l,(""))
+#define KEYCACHE_THREAD_TRACE_BEGIN(l) KEYCACHE_DBUG_PRINT(l,(""))
+#define KEYCACHE_THREAD_TRACE_END(l) KEYCACHE_DBUG_PRINT(l,(""))
+#endif /* THREAD */
+#else
+#define KEYCACHE_THREAD_TRACE_BEGIN(l)
+#define KEYCACHE_THREAD_TRACE_END(l)
+#define KEYCACHE_THREAD_TRACE(l)
+#endif /* defined(PAGECACHE_DEBUG) || !defined(DBUG_OFF) */
+
+#define PCBLOCK_NUMBER(p, b) \
+ ((uint) (((char*)(b)-(char *) p->block_root)/sizeof(PAGECACHE_BLOCK_LINK)))
+#define PAGECACHE_HASH_LINK_NUMBER(p, h) \
+ ((uint) (((char*)(h)-(char *) p->hash_link_root)/ \
+ sizeof(PAGECACHE_HASH_LINK)))
+
+#if (defined(PAGECACHE_TIMEOUT) && !defined(__WIN__)) || defined(PAGECACHE_DEBUG)
+static int pagecache_pthread_cond_wait(pthread_cond_t *cond,
+ pthread_mutex_t *mutex);
+#else
+#define pagecache_pthread_cond_wait pthread_cond_wait
+#endif
+
+#if defined(PAGECACHE_DEBUG)
+static int ___pagecache_pthread_mutex_lock(pthread_mutex_t *mutex);
+static void ___pagecache_pthread_mutex_unlock(pthread_mutex_t *mutex);
+static int ___pagecache_pthread_cond_signal(pthread_cond_t *cond);
+#define pagecache_pthread_mutex_lock(M) \
+{ DBUG_PRINT("lock", ("mutex lock 0x%lx %u", (ulong)(M), __LINE__)); \
+ ___pagecache_pthread_mutex_lock(M);}
+#define pagecache_pthread_mutex_unlock(M) \
+{ DBUG_PRINT("lock", ("mutex unlock 0x%lx %u", (ulong)(M), __LINE__)); \
+ ___pagecache_pthread_mutex_unlock(M);}
+#define pagecache_pthread_cond_signal(M) \
+{ DBUG_PRINT("lock", ("signal 0x%lx %u", (ulong)(M), __LINE__)); \
+ ___pagecache_pthread_cond_signal(M);}
+#else
+#define pagecache_pthread_mutex_lock pthread_mutex_lock
+#define pagecache_pthread_mutex_unlock pthread_mutex_unlock
+#define pagecache_pthread_cond_signal pthread_cond_signal
+#endif /* defined(PAGECACHE_DEBUG) */
+
+extern my_bool translog_flush(TRANSLOG_ADDRESS lsn);
+
+/*
+ Write page to the disk
+
+ SYNOPSIS
+ pagecache_fwrite()
+ pagecache - page cache pointer
+ filedesc - pagecache file descriptor structure
+ buffer - buffer which we will write
+ type - page type (plain or with LSN)
+ flags - MYF() flags
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+static my_bool pagecache_fwrite(PAGECACHE *pagecache,
+ PAGECACHE_FILE *filedesc,
+ uchar *buffer,
+ pgcache_page_no_t pageno,
+ enum pagecache_page_type type
+ __attribute__((unused)),
+ myf flags)
+{
+ DBUG_ENTER("pagecache_fwrite");
+ DBUG_ASSERT(type != PAGECACHE_READ_UNKNOWN_PAGE);
+
+ /* Todo: Integrate this with write_callback so we have only one callback */
+ if ((*filedesc->flush_log_callback)(buffer, pageno, filedesc->callback_data))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("write_callback: 0x%lx data: 0x%lx",
+ (ulong) filedesc->write_callback,
+ (ulong) filedesc->callback_data));
+ if ((*filedesc->write_callback)(buffer, pageno, filedesc->callback_data))
+ {
+ DBUG_PRINT("error", ("write callback problem"));
+ DBUG_RETURN(1);
+ }
+ if (my_pwrite(filedesc->file, buffer, pagecache->block_size,
+ ((my_off_t) pageno << pagecache->shift), flags))
+ {
+ (*filedesc->write_fail)(filedesc->callback_data);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Read page from the disk
+
+ SYNOPSIS
+ pagecache_fread()
+ pagecache - page cache pointer
+ filedesc - pagecache file descriptor structure
+ buffer - buffer in which we will read
+ pageno - page number
+ flags - MYF() flags
+*/
+#define pagecache_fread(pagecache, filedesc, buffer, pageno, flags) \
+ my_pread((filedesc)->file, buffer, pagecache->block_size, \
+ ((my_off_t) pageno << pagecache->shift), flags)
+
+
+/**
+ @brief set rec_lsn of pagecache block (if it is needed)
+
+ @param block block where to set rec_lsn
+ @param first_REDO_LSN_for_page the LSN to set
+*/
+
+static inline void pagecache_set_block_rec_lsn(PAGECACHE_BLOCK_LINK *block,
+ LSN first_REDO_LSN_for_page)
+{
+ if (block->rec_lsn == LSN_MAX)
+ block->rec_lsn= first_REDO_LSN_for_page;
+ else
+ DBUG_ASSERT(cmp_translog_addr(block->rec_lsn,
+ first_REDO_LSN_for_page) <= 0);
+}
+
+
+/*
+ next_power(value) is 2 at the power of (1+floor(log2(value)));
+ e.g. next_power(2)=4, next_power(3)=4.
+*/
+static inline uint next_power(uint value)
+{
+ return (uint) my_round_up_to_next_power((uint32) value) << 1;
+}
+
+
+/*
+ Initialize a page cache
+
+ SYNOPSIS
+ init_pagecache()
+ pagecache pointer to a page cache data structure
+ key_cache_block_size size of blocks to keep cached data
+ use_mem total memory to use for the key cache
+ division_limit division limit (may be zero)
+ age_threshold age threshold (may be zero)
+ block_size size of block (should be power of 2)
+ my_read_flags Flags used for all pread/pwrite calls
+ Usually MY_WME in case of recovery
+
+ RETURN VALUE
+ number of blocks in the key cache, if successful,
+ 0 - otherwise.
+
+ NOTES.
+ if pagecache->inited != 0 we assume that the key cache
+ is already initialized. This is for now used by myisamchk, but shouldn't
+ be something that a program should rely on!
+
+ It's assumed that no two threads call this function simultaneously
+ referring to the same key cache handle.
+
+*/
+
+ulong init_pagecache(PAGECACHE *pagecache, size_t use_mem,
+ uint division_limit, uint age_threshold,
+ uint block_size, myf my_readwrite_flags)
+{
+ ulong blocks, hash_links, length;
+ int error;
+ DBUG_ENTER("init_pagecache");
+ DBUG_ASSERT(block_size >= 512);
+
+ PAGECACHE_DEBUG_OPEN;
+ if (pagecache->inited && pagecache->disk_blocks > 0)
+ {
+ DBUG_PRINT("warning",("key cache already in use"));
+ DBUG_RETURN(0);
+ }
+
+ pagecache->global_cache_w_requests= pagecache->global_cache_r_requests= 0;
+ pagecache->global_cache_read= pagecache->global_cache_write= 0;
+ pagecache->disk_blocks= -1;
+ if (! pagecache->inited)
+ {
+ if (pthread_mutex_init(&pagecache->cache_lock, MY_MUTEX_INIT_FAST) ||
+ hash_init(&pagecache->files_in_flush, &my_charset_bin, 32,
+ offsetof(struct st_file_in_flush, file),
+ sizeof(((struct st_file_in_flush *)NULL)->file),
+ NULL, NULL, 0))
+ goto err;
+ pagecache->inited= 1;
+ pagecache->in_init= 0;
+ pagecache->resize_queue.last_thread= NULL;
+ }
+
+ pagecache->mem_size= use_mem;
+ pagecache->block_size= block_size;
+ pagecache->shift= my_bit_log2(block_size);
+ pagecache->readwrite_flags= my_readwrite_flags | MY_NABP | MY_WAIT_IF_FULL;
+ pagecache->org_readwrite_flags= pagecache->readwrite_flags;
+ DBUG_PRINT("info", ("block_size: %u", block_size));
+ DBUG_ASSERT(((uint)(1 << pagecache->shift)) == block_size);
+
+ blocks= (ulong) (use_mem / (sizeof(PAGECACHE_BLOCK_LINK) +
+ 2 * sizeof(PAGECACHE_HASH_LINK) +
+ sizeof(PAGECACHE_HASH_LINK*) *
+ 5/4 + block_size));
+ /*
+ We need to support page cache with just one block to be able to do
+ scanning of rows-in-block files
+ */
+ for ( ; ; )
+ {
+ if (blocks < 8)
+ {
+ my_errno= ENOMEM;
+ goto err;
+ }
+ /* Set my_hash_entries to the next bigger 2 power */
+ if ((pagecache->hash_entries= next_power(blocks)) <
+ (blocks) * 5/4)
+ pagecache->hash_entries<<= 1;
+ hash_links= 2 * blocks;
+#if defined(MAX_THREADS)
+ if (hash_links < MAX_THREADS + blocks - 1)
+ hash_links= MAX_THREADS + blocks - 1;
+#endif
+ while ((length= (ALIGN_SIZE(blocks * sizeof(PAGECACHE_BLOCK_LINK)) +
+ ALIGN_SIZE(hash_links * sizeof(PAGECACHE_HASH_LINK)) +
+ ALIGN_SIZE(sizeof(PAGECACHE_HASH_LINK*) *
+ pagecache->hash_entries))) +
+ (blocks << pagecache->shift) > use_mem)
+ blocks--;
+ /* Allocate memory for cache page buffers */
+ if ((pagecache->block_mem=
+ my_large_malloc((ulong) blocks * pagecache->block_size,
+ MYF(MY_WME))))
+ {
+ /*
+ Allocate memory for blocks, hash_links and hash entries;
+ For each block 2 hash links are allocated
+ */
+ if ((pagecache->block_root=
+ (PAGECACHE_BLOCK_LINK*) my_malloc((size_t) length, MYF(0))))
+ break;
+ my_large_free(pagecache->block_mem, MYF(0));
+ pagecache->block_mem= 0;
+ }
+ blocks= blocks / 4*3;
+ }
+ pagecache->blocks_unused= blocks;
+ pagecache->disk_blocks= (long) blocks;
+ pagecache->hash_links= hash_links;
+ pagecache->hash_root=
+ (PAGECACHE_HASH_LINK**) ((char*) pagecache->block_root +
+ ALIGN_SIZE(blocks*sizeof(PAGECACHE_BLOCK_LINK)));
+ pagecache->hash_link_root=
+ (PAGECACHE_HASH_LINK*) ((char*) pagecache->hash_root +
+ ALIGN_SIZE((sizeof(PAGECACHE_HASH_LINK*) *
+ pagecache->hash_entries)));
+ bzero((uchar*) pagecache->block_root,
+ pagecache->disk_blocks * sizeof(PAGECACHE_BLOCK_LINK));
+ bzero((uchar*) pagecache->hash_root,
+ pagecache->hash_entries * sizeof(PAGECACHE_HASH_LINK*));
+ bzero((uchar*) pagecache->hash_link_root,
+ pagecache->hash_links * sizeof(PAGECACHE_HASH_LINK));
+ pagecache->hash_links_used= 0;
+ pagecache->free_hash_list= NULL;
+ pagecache->blocks_used= pagecache->blocks_changed= 0;
+
+ pagecache->global_blocks_changed= 0;
+ pagecache->blocks_available=0; /* For debugging */
+
+ /* The LRU chain is empty after initialization */
+ pagecache->used_last= NULL;
+ pagecache->used_ins= NULL;
+ pagecache->free_block_list= NULL;
+ pagecache->time= 0;
+ pagecache->warm_blocks= 0;
+ pagecache->min_warm_blocks= (division_limit ?
+ blocks * division_limit / 100 + 1 :
+ blocks);
+ pagecache->age_threshold= (age_threshold ?
+ blocks * age_threshold / 100 :
+ blocks);
+
+ pagecache->cnt_for_resize_op= 0;
+ pagecache->resize_in_flush= 0;
+ pagecache->can_be_used= 1;
+
+ pagecache->waiting_for_hash_link.last_thread= NULL;
+ pagecache->waiting_for_block.last_thread= NULL;
+ DBUG_PRINT("exit",
+ ("disk_blocks: %ld block_root: 0x%lx hash_entries: %ld\
+ hash_root: 0x%lx hash_links: %ld hash_link_root: 0x%lx",
+ pagecache->disk_blocks, (long) pagecache->block_root,
+ pagecache->hash_entries, (long) pagecache->hash_root,
+ pagecache->hash_links, (long) pagecache->hash_link_root));
+ bzero((uchar*) pagecache->changed_blocks,
+ sizeof(pagecache->changed_blocks[0]) *
+ PAGECACHE_CHANGED_BLOCKS_HASH);
+ bzero((uchar*) pagecache->file_blocks,
+ sizeof(pagecache->file_blocks[0]) *
+ PAGECACHE_CHANGED_BLOCKS_HASH);
+
+ pagecache->blocks= pagecache->disk_blocks > 0 ? pagecache->disk_blocks : 0;
+ DBUG_RETURN((ulong) pagecache->disk_blocks);
+
+err:
+ error= my_errno;
+ pagecache->disk_blocks= 0;
+ pagecache->blocks= 0;
+ if (pagecache->block_mem)
+ {
+ my_large_free((uchar*) pagecache->block_mem, MYF(0));
+ pagecache->block_mem= NULL;
+ }
+ if (pagecache->block_root)
+ {
+ my_free((uchar*) pagecache->block_root, MYF(0));
+ pagecache->block_root= NULL;
+ }
+ my_errno= error;
+ pagecache->can_be_used= 0;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Flush all blocks in the key cache to disk
+*/
+
+#ifdef NOT_USED
+static int flush_all_key_blocks(PAGECACHE *pagecache)
+{
+#if defined(PAGECACHE_DEBUG)
+ uint cnt=0;
+#endif
+ while (pagecache->blocks_changed > 0)
+ {
+ PAGECACHE_BLOCK_LINK *block;
+ for (block= pagecache->used_last->next_used ; ; block=block->next_used)
+ {
+ if (block->hash_link)
+ {
+#if defined(PAGECACHE_DEBUG)
+ cnt++;
+ KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used);
+#endif
+ if (flush_pagecache_blocks_int(pagecache, &block->hash_link->file,
+ FLUSH_RELEASE, NULL, NULL))
+ return 1;
+ break;
+ }
+ if (block == pagecache->used_last)
+ break;
+ }
+ }
+ return 0;
+}
+#endif /* NOT_USED */
+
+/*
+ Resize a key cache
+
+ SYNOPSIS
+ resize_pagecache()
+ pagecache pointer to a page cache data structure
+ use_mem total memory to use for the new key cache
+ division_limit new division limit (if not zero)
+ age_threshold new age threshold (if not zero)
+
+ RETURN VALUE
+ number of blocks in the key cache, if successful,
+ 0 - otherwise.
+
+ NOTES.
+ The function first compares the memory size parameter
+ with the key cache value.
+
+ If they differ the function free the the memory allocated for the
+ old key cache blocks by calling the end_pagecache function and
+ then rebuilds the key cache with new blocks by calling
+ init_key_cache.
+
+ The function starts the operation only when all other threads
+ performing operations with the key cache let her to proceed
+ (when cnt_for_resize=0).
+
+ Before being usable, this function needs:
+ - to receive fixes for BUG#17332 "changing key_buffer_size on a running
+ server can crash under load" similar to those done to the key cache
+ - to have us (Sanja) look at the additional constraints placed on
+ resizing, due to the page locking specific to this page cache.
+ So we disable it for now.
+*/
+#if NOT_USED /* keep disabled until code is fixed see above !! */
+ulong resize_pagecache(PAGECACHE *pagecache,
+ size_t use_mem, uint division_limit,
+ uint age_threshold)
+{
+ ulong blocks;
+#ifdef THREAD
+ struct st_my_thread_var *thread;
+ WQUEUE *wqueue;
+
+#endif
+ DBUG_ENTER("resize_pagecache");
+
+ if (!pagecache->inited)
+ DBUG_RETURN(pagecache->disk_blocks);
+
+ if(use_mem == pagecache->mem_size)
+ {
+ change_pagecache_param(pagecache, division_limit, age_threshold);
+ DBUG_RETURN(pagecache->disk_blocks);
+ }
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+
+#ifdef THREAD
+ wqueue= &pagecache->resize_queue;
+ thread= my_thread_var;
+ wqueue_link_into_queue(wqueue, thread);
+
+ while (wqueue->last_thread->next != thread)
+ {
+ pagecache_pthread_cond_wait(&thread->suspend, &pagecache->cache_lock);
+ }
+#endif
+
+ pagecache->resize_in_flush= 1;
+ if (flush_all_key_blocks(pagecache))
+ {
+ /* TODO: if this happens, we should write a warning in the log file ! */
+ pagecache->resize_in_flush= 0;
+ blocks= 0;
+ pagecache->can_be_used= 0;
+ goto finish;
+ }
+ pagecache->resize_in_flush= 0;
+ pagecache->can_be_used= 0;
+#ifdef THREAD
+ while (pagecache->cnt_for_resize_op)
+ {
+ KEYCACHE_DBUG_PRINT("resize_pagecache: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend, &pagecache->cache_lock);
+ }
+#else
+ KEYCACHE_DBUG_ASSERT(pagecache->cnt_for_resize_op == 0);
+#endif
+
+ end_pagecache(pagecache, 0); /* Don't free mutex */
+ /* The following will work even if use_mem is 0 */
+ blocks= init_pagecache(pagecache, pagecache->block_size, use_mem,
+ division_limit, age_threshold,
+ pagecache->readwrite_flags);
+
+finish:
+#ifdef THREAD
+ wqueue_unlink_from_queue(wqueue, thread);
+ /* Signal for the next resize request to proceeed if any */
+ if (wqueue->last_thread)
+ {
+ KEYCACHE_DBUG_PRINT("resize_pagecache: signal",
+ ("thread %ld", wqueue->last_thread->next->id));
+ pagecache_pthread_cond_signal(&wqueue->last_thread->next->suspend);
+ }
+#endif
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_RETURN(blocks);
+}
+#endif /* 0 */
+
+
+/*
+ Increment counter blocking resize key cache operation
+*/
+static inline void inc_counter_for_resize_op(PAGECACHE *pagecache)
+{
+ pagecache->cnt_for_resize_op++;
+}
+
+
+/*
+ Decrement counter blocking resize key cache operation;
+ Signal the operation to proceed when counter becomes equal zero
+*/
+static inline void dec_counter_for_resize_op(PAGECACHE *pagecache)
+{
+#ifdef THREAD
+ struct st_my_thread_var *last_thread;
+ if (!--pagecache->cnt_for_resize_op &&
+ (last_thread= pagecache->resize_queue.last_thread))
+ {
+ KEYCACHE_DBUG_PRINT("dec_counter_for_resize_op: signal",
+ ("thread %ld", last_thread->next->id));
+ pagecache_pthread_cond_signal(&last_thread->next->suspend);
+ }
+#else
+ pagecache->cnt_for_resize_op--;
+#endif
+}
+
+/*
+ Change the page cache parameters
+
+ SYNOPSIS
+ change_pagecache_param()
+ pagecache pointer to a page cache data structure
+ division_limit new division limit (if not zero)
+ age_threshold new age threshold (if not zero)
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ Presently the function resets the key cache parameters
+ concerning midpoint insertion strategy - division_limit and
+ age_threshold.
+*/
+
+void change_pagecache_param(PAGECACHE *pagecache, uint division_limit,
+ uint age_threshold)
+{
+ DBUG_ENTER("change_pagecache_param");
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ if (division_limit)
+ pagecache->min_warm_blocks= (pagecache->disk_blocks *
+ division_limit / 100 + 1);
+ if (age_threshold)
+ pagecache->age_threshold= (pagecache->disk_blocks *
+ age_threshold / 100);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Removes page cache from memory. Does NOT flush pages to disk.
+
+ SYNOPSIS
+ end_pagecache()
+ pagecache page cache handle
+ cleanup Complete free (Free also mutex for key cache)
+
+ RETURN VALUE
+ none
+*/
+
+void end_pagecache(PAGECACHE *pagecache, my_bool cleanup)
+{
+ DBUG_ENTER("end_pagecache");
+ DBUG_PRINT("enter", ("key_cache: 0x%lx", (long) pagecache));
+
+ if (!pagecache->inited)
+ DBUG_VOID_RETURN;
+
+ if (pagecache->disk_blocks > 0)
+ {
+ if (pagecache->block_mem)
+ {
+ my_large_free((uchar*) pagecache->block_mem, MYF(0));
+ pagecache->block_mem= NULL;
+ my_free((uchar*) pagecache->block_root, MYF(0));
+ pagecache->block_root= NULL;
+ }
+ pagecache->disk_blocks= -1;
+ /* Reset blocks_changed to be safe if flush_all_key_blocks is called */
+ pagecache->blocks_changed= 0;
+ }
+
+ DBUG_PRINT("status", ("used: %lu changed: %lu w_requests: %lu "
+ "writes: %lu r_requests: %lu reads: %lu",
+ pagecache->blocks_used,
+ pagecache->global_blocks_changed,
+ (ulong) pagecache->global_cache_w_requests,
+ (ulong) pagecache->global_cache_write,
+ (ulong) pagecache->global_cache_r_requests,
+ (ulong) pagecache->global_cache_read));
+
+ if (cleanup)
+ {
+ hash_free(&pagecache->files_in_flush);
+ pthread_mutex_destroy(&pagecache->cache_lock);
+ pagecache->inited= pagecache->can_be_used= 0;
+ PAGECACHE_DEBUG_CLOSE;
+ }
+ DBUG_VOID_RETURN;
+} /* end_pagecache */
+
+
+/*
+ Unlink a block from the chain of dirty/clean blocks
+*/
+
+static inline void unlink_changed(PAGECACHE_BLOCK_LINK *block)
+{
+ if (block->next_changed)
+ block->next_changed->prev_changed= block->prev_changed;
+ *block->prev_changed= block->next_changed;
+}
+
+
+/*
+ Link a block into the chain of dirty/clean blocks
+*/
+
+static inline void link_changed(PAGECACHE_BLOCK_LINK *block,
+ PAGECACHE_BLOCK_LINK **phead)
+{
+ block->prev_changed= phead;
+ if ((block->next_changed= *phead))
+ (*phead)->prev_changed= &block->next_changed;
+ *phead= block;
+}
+
+
+/*
+ Unlink a block from the chain of dirty/clean blocks, if it's asked for,
+ and link it to the chain of clean blocks for the specified file
+*/
+
+static void link_to_file_list(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ PAGECACHE_FILE *file, my_bool unlink_flag)
+{
+ if (unlink_flag)
+ unlink_changed(block);
+ link_changed(block, &pagecache->file_blocks[FILE_HASH(*file)]);
+ if (block->status & PCBLOCK_CHANGED)
+ {
+ block->status&= ~PCBLOCK_CHANGED;
+ block->rec_lsn= LSN_MAX;
+ pagecache->blocks_changed--;
+ pagecache->global_blocks_changed--;
+ }
+}
+
+
+/*
+ Unlink a block from the chain of clean blocks for the specified
+ file and link it to the chain of dirty blocks for this file
+*/
+
+static inline void link_to_changed_list(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block)
+{
+ unlink_changed(block);
+ link_changed(block,
+ &pagecache->changed_blocks[FILE_HASH(block->hash_link->file)]);
+ block->status|=PCBLOCK_CHANGED;
+ pagecache->blocks_changed++;
+ pagecache->global_blocks_changed++;
+}
+
+
+/*
+ Link a block to the LRU chain at the beginning or at the end of
+ one of two parts.
+
+ SYNOPSIS
+ link_block()
+ pagecache pointer to a page cache data structure
+ block pointer to the block to link to the LRU chain
+ hot <-> to link the block into the hot subchain
+ at_end <-> to link the block at the end of the subchain
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ The LRU chain is represented by a circular list of block structures.
+ The list is double-linked of the type (**prev,*next) type.
+ The LRU chain is divided into two parts - hot and warm.
+ There are two pointers to access the last blocks of these two
+ parts. The beginning of the warm part follows right after the
+ end of the hot part.
+ Only blocks of the warm part can be used for replacement.
+ The first block from the beginning of this subchain is always
+ taken for eviction (pagecache->last_used->next)
+
+ LRU chain: +------+ H O T +------+
+ +----| end |----...<----| beg |----+
+ | +------+last +------+ |
+ v<-link in latest hot (new end) |
+ | link in latest warm (new end)->^
+ | +------+ W A R M +------+ |
+ +----| beg |---->...----| end |----+
+ +------+ +------+ins
+ first for eviction
+*/
+
+static void link_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
+ my_bool hot, my_bool at_end)
+{
+ PAGECACHE_BLOCK_LINK *ins;
+ PAGECACHE_BLOCK_LINK **ptr_ins;
+
+ PCBLOCK_INFO(block);
+ KEYCACHE_DBUG_ASSERT(! (block->hash_link && block->hash_link->requests));
+#ifdef THREAD
+ if (!hot && pagecache->waiting_for_block.last_thread)
+ {
+ /* Signal that in the LRU warm sub-chain an available block has appeared */
+ struct st_my_thread_var *last_thread=
+ pagecache->waiting_for_block.last_thread;
+ struct st_my_thread_var *first_thread= last_thread->next;
+ struct st_my_thread_var *next_thread= first_thread;
+ PAGECACHE_HASH_LINK *hash_link=
+ (PAGECACHE_HASH_LINK *) first_thread->opt_info;
+ struct st_my_thread_var *thread;
+ do
+ {
+ thread= next_thread;
+ next_thread= thread->next;
+ /*
+ We notify about the event all threads that ask
+ for the same page as the first thread in the queue
+ */
+ if ((PAGECACHE_HASH_LINK *) thread->opt_info == hash_link)
+ {
+ KEYCACHE_DBUG_PRINT("link_block: signal", ("thread: %ld", thread->id));
+ pagecache_pthread_cond_signal(&thread->suspend);
+ wqueue_unlink_from_queue(&pagecache->waiting_for_block, thread);
+ block->requests++;
+ }
+ }
+ while (thread != last_thread);
+ hash_link->block= block;
+ KEYCACHE_THREAD_TRACE("link_block: after signaling");
+#if defined(PAGECACHE_DEBUG)
+ KEYCACHE_DBUG_PRINT("link_block",
+ ("linked,unlinked block: %u status: %x #requests: %u #available: %u",
+ PCBLOCK_NUMBER(pagecache, block), block->status,
+ block->requests, pagecache->blocks_available));
+#endif
+ return;
+ }
+#else /* THREAD */
+ KEYCACHE_DBUG_ASSERT(! (!hot && pagecache->waiting_for_block.last_thread));
+ /* Condition not transformed using DeMorgan, to keep the text identical */
+#endif /* THREAD */
+ ptr_ins= hot ? &pagecache->used_ins : &pagecache->used_last;
+ ins= *ptr_ins;
+ if (ins)
+ {
+ ins->next_used->prev_used= &block->next_used;
+ block->next_used= ins->next_used;
+ block->prev_used= &ins->next_used;
+ ins->next_used= block;
+ if (at_end)
+ *ptr_ins= block;
+ }
+ else
+ {
+ /* The LRU chain is empty */
+ pagecache->used_last= pagecache->used_ins= block->next_used= block;
+ block->prev_used= &block->next_used;
+ }
+ KEYCACHE_THREAD_TRACE("link_block");
+#if defined(PAGECACHE_DEBUG)
+ pagecache->blocks_available++;
+ KEYCACHE_DBUG_PRINT("link_block",
+ ("linked block: %u:%1u status: %x #requests: %u #available: %u",
+ PCBLOCK_NUMBER(pagecache, block), at_end, block->status,
+ block->requests, pagecache->blocks_available));
+ KEYCACHE_DBUG_ASSERT((ulong) pagecache->blocks_available <=
+ pagecache->blocks_used);
+#endif
+}
+
+
+/*
+ Unlink a block from the LRU chain
+
+ SYNOPSIS
+ unlink_block()
+ pagecache pointer to a page cache data structure
+ block pointer to the block to unlink from the LRU chain
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ See NOTES for link_block
+*/
+
+static void unlink_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
+{
+ DBUG_ENTER("unlink_block");
+ DBUG_PRINT("unlink_block", ("unlink 0x%lx", (ulong)block));
+ DBUG_ASSERT(block->next_used != NULL);
+ if (block->next_used == block)
+ {
+ /* The list contains only one member */
+ pagecache->used_last= pagecache->used_ins= NULL;
+ }
+ else
+ {
+ block->next_used->prev_used= block->prev_used;
+ *block->prev_used= block->next_used;
+ if (pagecache->used_last == block)
+ pagecache->used_last= STRUCT_PTR(PAGECACHE_BLOCK_LINK,
+ next_used, block->prev_used);
+ if (pagecache->used_ins == block)
+ pagecache->used_ins= STRUCT_PTR(PAGECACHE_BLOCK_LINK,
+ next_used, block->prev_used);
+ }
+ block->next_used= NULL;
+
+ KEYCACHE_THREAD_TRACE("unlink_block");
+#if defined(PAGECACHE_DEBUG)
+ KEYCACHE_DBUG_ASSERT(pagecache->blocks_available != 0);
+ pagecache->blocks_available--;
+ KEYCACHE_DBUG_PRINT("unlink_block",
+ ("unlinked block: 0x%lx (%u) status: %x #requests: %u #available: %u",
+ (ulong)block, PCBLOCK_NUMBER(pagecache, block),
+ block->status,
+ block->requests, pagecache->blocks_available));
+ PCBLOCK_INFO(block);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Register requests for a block
+
+ SYNOPSIS
+ reg_requests()
+ pagecache this page cache reference
+ block the block we request reference
+ count how many requests we register (it is 1 everywhere)
+
+ NOTE
+ Registration of request means we are going to use this block so we exclude
+ it from the LRU if it is first request
+*/
+static void reg_requests(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block,
+ int count)
+{
+ DBUG_ENTER("reg_requests");
+ DBUG_PRINT("enter", ("block: 0x%lx (%u) status: %x reqs: %u",
+ (ulong)block, PCBLOCK_NUMBER(pagecache, block),
+ block->status, block->requests));
+ PCBLOCK_INFO(block);
+ if (! block->requests)
+ /* First request for the block unlinks it */
+ unlink_block(pagecache, block);
+ block->requests+= count;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Unregister request for a block
+ linking it to the LRU chain if it's the last request
+
+ SYNOPSIS
+ unreg_request()
+ pagecache pointer to a page cache data structure
+ block pointer to the block to link to the LRU chain
+ at_end <-> to link the block at the end of the LRU chain
+
+ RETURN VALUE
+ none
+
+ NOTES.
+ Every linking to the LRU chain decrements by one a special block
+ counter (if it's positive). If the at_end parameter is TRUE the block is
+ added either at the end of warm sub-chain or at the end of hot sub-chain.
+ It is added to the hot subchain if its counter is zero and number of
+ blocks in warm sub-chain is not less than some low limit (determined by
+ the division_limit parameter). Otherwise the block is added to the warm
+ sub-chain. If the at_end parameter is FALSE the block is always added
+ at beginning of the warm sub-chain.
+ Thus a warm block can be promoted to the hot sub-chain when its counter
+ becomes zero for the first time.
+ At the same time the block at the very beginning of the hot subchain
+ might be moved to the beginning of the warm subchain if it stays untouched
+ for a too long time (this time is determined by parameter age_threshold).
+*/
+
+static void unreg_request(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block, int at_end)
+{
+ DBUG_ENTER("unreg_request");
+ DBUG_PRINT("enter", ("block 0x%lx (%u) status: %x reqs: %u",
+ (ulong)block, PCBLOCK_NUMBER(pagecache, block),
+ block->status, block->requests));
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(block->requests > 0);
+ if (! --block->requests)
+ {
+ my_bool hot;
+ if (block->hits_left)
+ block->hits_left--;
+ hot= !block->hits_left && at_end &&
+ pagecache->warm_blocks > pagecache->min_warm_blocks;
+ if (hot)
+ {
+ if (block->temperature == PCBLOCK_WARM)
+ pagecache->warm_blocks--;
+ block->temperature= PCBLOCK_HOT;
+ KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
+ pagecache->warm_blocks));
+ }
+ link_block(pagecache, block, hot, (my_bool)at_end);
+ block->last_hit_time= pagecache->time;
+ pagecache->time++;
+
+ block= pagecache->used_ins;
+ /* Check if we should link a hot block to the warm block */
+ if (block && pagecache->time - block->last_hit_time >
+ pagecache->age_threshold)
+ {
+ unlink_block(pagecache, block);
+ link_block(pagecache, block, 0, 0);
+ if (block->temperature != PCBLOCK_WARM)
+ {
+ pagecache->warm_blocks++;
+ block->temperature= PCBLOCK_WARM;
+ }
+ KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
+ pagecache->warm_blocks));
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Remove a reader of the page in block
+*/
+
+static inline void remove_reader(PAGECACHE_BLOCK_LINK *block)
+{
+ DBUG_ENTER("remove_reader");
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(block->hash_link->requests > 0);
+#ifdef THREAD
+ if (! --block->hash_link->requests && block->condvar)
+ pagecache_pthread_cond_signal(block->condvar);
+#else
+ --block->hash_link->requests;
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Wait until the last reader of the page in block
+ signals on its termination
+*/
+
+static inline void wait_for_readers(PAGECACHE *pagecache
+ __attribute__((unused)),
+ PAGECACHE_BLOCK_LINK *block)
+{
+#ifdef THREAD
+ struct st_my_thread_var *thread= my_thread_var;
+ while (block->hash_link->requests)
+ {
+ KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
+ ("suspend thread: %ld block: %u",
+ thread->id, PCBLOCK_NUMBER(pagecache, block)));
+ block->condvar= &thread->suspend;
+ pagecache_pthread_cond_wait(&thread->suspend, &pagecache->cache_lock);
+ block->condvar= NULL;
+ }
+#else
+ KEYCACHE_DBUG_ASSERT(block->hash_link->requests == 0);
+#endif
+}
+
+
+/*
+ Add a hash link to a bucket in the hash_table
+*/
+
+static inline void link_hash(PAGECACHE_HASH_LINK **start,
+ PAGECACHE_HASH_LINK *hash_link)
+{
+ if (*start)
+ (*start)->prev= &hash_link->next;
+ hash_link->next= *start;
+ hash_link->prev= start;
+ *start= hash_link;
+}
+
+
+/*
+ Remove a hash link from the hash table
+*/
+
+static void unlink_hash(PAGECACHE *pagecache, PAGECACHE_HASH_LINK *hash_link)
+{
+ KEYCACHE_DBUG_PRINT("unlink_hash", ("fd: %u pos_ %lu #requests=%u",
+ (uint) hash_link->file.file, (ulong) hash_link->pageno,
+ hash_link->requests));
+ KEYCACHE_DBUG_ASSERT(hash_link->requests == 0);
+ if ((*hash_link->prev= hash_link->next))
+ hash_link->next->prev= hash_link->prev;
+ hash_link->block= NULL;
+#ifdef THREAD
+ if (pagecache->waiting_for_hash_link.last_thread)
+ {
+ /* Signal that a free hash link has appeared */
+ struct st_my_thread_var *last_thread=
+ pagecache->waiting_for_hash_link.last_thread;
+ struct st_my_thread_var *first_thread= last_thread->next;
+ struct st_my_thread_var *next_thread= first_thread;
+ PAGECACHE_PAGE *first_page= (PAGECACHE_PAGE *) (first_thread->opt_info);
+ struct st_my_thread_var *thread;
+
+ hash_link->file= first_page->file;
+ DBUG_ASSERT(first_page->pageno < ((ULL(1)) << 40));
+ hash_link->pageno= first_page->pageno;
+ do
+ {
+ PAGECACHE_PAGE *page;
+ thread= next_thread;
+ page= (PAGECACHE_PAGE *) thread->opt_info;
+ next_thread= thread->next;
+ /*
+ We notify about the event all threads that ask
+ for the same page as the first thread in the queue
+ */
+ if (page->file.file == hash_link->file.file &&
+ page->pageno == hash_link->pageno)
+ {
+ KEYCACHE_DBUG_PRINT("unlink_hash: signal", ("thread %ld", thread->id));
+ pagecache_pthread_cond_signal(&thread->suspend);
+ wqueue_unlink_from_queue(&pagecache->waiting_for_hash_link, thread);
+ }
+ }
+ while (thread != last_thread);
+ link_hash(&pagecache->hash_root[PAGECACHE_HASH(pagecache,
+ hash_link->file,
+ hash_link->pageno)],
+ hash_link);
+ return;
+ }
+#else /* THREAD */
+ KEYCACHE_DBUG_ASSERT(! (pagecache->waiting_for_hash_link.last_thread));
+#endif /* THREAD */
+ hash_link->next= pagecache->free_hash_list;
+ pagecache->free_hash_list= hash_link;
+}
+
+
+/*
+ Get the hash link for the page if it is in the cache (do not put the
+ page in the cache if it is absent there)
+
+ SYNOPSIS
+ get_present_hash_link()
+ pagecache Pagecache reference
+ file file ID
+ pageno page number in the file
+ start where to put pointer to found hash bucket (for
+ direct referring it)
+
+ RETURN
+ found hashlink pointer
+*/
+
+static PAGECACHE_HASH_LINK *get_present_hash_link(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ PAGECACHE_HASH_LINK ***start)
+{
+ reg1 PAGECACHE_HASH_LINK *hash_link;
+#if defined(PAGECACHE_DEBUG)
+ int cnt;
+#endif
+ DBUG_ENTER("get_present_hash_link");
+
+ KEYCACHE_DBUG_PRINT("get_present_hash_link", ("fd: %u pos: %lu",
+ (uint) file->file, (ulong) pageno));
+
+ /*
+ Find the bucket in the hash table for the pair (file, pageno);
+ start contains the head of the bucket list,
+ hash_link points to the first member of the list
+ */
+ hash_link= *(*start= &pagecache->hash_root[PAGECACHE_HASH(pagecache,
+ *file, pageno)]);
+#if defined(PAGECACHE_DEBUG)
+ cnt= 0;
+#endif
+ /* Look for an element for the pair (file, pageno) in the bucket chain */
+ while (hash_link &&
+ (hash_link->pageno != pageno ||
+ hash_link->file.file != file->file))
+ {
+ hash_link= hash_link->next;
+#if defined(PAGECACHE_DEBUG)
+ cnt++;
+ if (! (cnt <= pagecache->hash_links_used))
+ {
+ int i;
+ for (i=0, hash_link= **start ;
+ i < cnt ; i++, hash_link= hash_link->next)
+ {
+ KEYCACHE_DBUG_PRINT("get_present_hash_link", ("fd: %u pos: %lu",
+ (uint) hash_link->file.file, (ulong) hash_link->pageno));
+ }
+ }
+ KEYCACHE_DBUG_ASSERT(cnt <= pagecache->hash_links_used);
+#endif
+ }
+ if (hash_link)
+ {
+ /* Register the request for the page */
+ hash_link->requests++;
+ }
+ /*
+ As soon as the caller will release the page cache's lock, "hash_link"
+ will be potentially obsolete (unusable) information.
+ */
+ DBUG_RETURN(hash_link);
+}
+
+
+/*
+ Get the hash link for a page
+*/
+
+static PAGECACHE_HASH_LINK *get_hash_link(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno)
+{
+ reg1 PAGECACHE_HASH_LINK *hash_link;
+ PAGECACHE_HASH_LINK **start;
+
+ KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u pos: %lu",
+ (uint) file->file, (ulong) pageno));
+
+restart:
+ /* try to find the page in the cache */
+ hash_link= get_present_hash_link(pagecache, file, pageno,
+ &start);
+ if (!hash_link)
+ {
+ /* There is no hash link in the hash table for the pair (file, pageno) */
+ if (pagecache->free_hash_list)
+ {
+ hash_link= pagecache->free_hash_list;
+ pagecache->free_hash_list= hash_link->next;
+ }
+ else if (pagecache->hash_links_used < pagecache->hash_links)
+ {
+ hash_link= &pagecache->hash_link_root[pagecache->hash_links_used++];
+ }
+ else
+ {
+#ifdef THREAD
+ /* Wait for a free hash link */
+ struct st_my_thread_var *thread= my_thread_var;
+ PAGECACHE_PAGE page;
+ KEYCACHE_DBUG_PRINT("get_hash_link", ("waiting"));
+ page.file= *file;
+ page.pageno= pageno;
+ thread->opt_info= (void *) &page;
+ wqueue_link_into_queue(&pagecache->waiting_for_hash_link, thread);
+ KEYCACHE_DBUG_PRINT("get_hash_link: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ thread->opt_info= NULL;
+#else
+ KEYCACHE_DBUG_ASSERT(0);
+#endif
+ DBUG_PRINT("info", ("restarting..."));
+ goto restart;
+ }
+ hash_link->file= *file;
+ DBUG_ASSERT(pageno < ((ULL(1)) << 40));
+ hash_link->pageno= pageno;
+ link_hash(start, hash_link);
+ /* Register the request for the page */
+ hash_link->requests++;
+ }
+
+ return hash_link;
+}
+
+
+/*
+ Get a block for the file page requested by a pagecache read/write operation;
+ If the page is not in the cache return a free block, if there is none
+ return the lru block after saving its buffer if the page is dirty.
+
+ SYNOPSIS
+
+ find_block()
+ pagecache pointer to a page cache data structure
+ file handler for the file to read page from
+ pageno number of the page in the file
+ init_hits_left how initialize the block counter for the page
+ wrmode <-> get for writing
+ reg_req Register request to thye page
+ page_st out {PAGE_READ,PAGE_TO_BE_READ,PAGE_WAIT_TO_BE_READ}
+
+ RETURN VALUE
+ Pointer to the found block if successful, 0 - otherwise
+
+ NOTES.
+ For the page from file positioned at pageno the function checks whether
+ the page is in the key cache specified by the first parameter.
+ If this is the case it immediately returns the block.
+ If not, the function first chooses a block for this page. If there is
+ no not used blocks in the key cache yet, the function takes the block
+ at the very beginning of the warm sub-chain. It saves the page in that
+ block if it's dirty before returning the pointer to it.
+ The function returns in the page_st parameter the following values:
+ PAGE_READ - if page already in the block,
+ PAGE_TO_BE_READ - if it is to be read yet by the current thread
+ WAIT_TO_BE_READ - if it is to be read by another thread
+ If an error occurs THE PCBLOCK_ERROR bit is set in the block status.
+ It might happen that there are no blocks in LRU chain (in warm part) -
+ all blocks are unlinked for some read/write operations. Then the function
+ waits until first of this operations links any block back.
+*/
+
+static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ int init_hits_left,
+ my_bool wrmode,
+ my_bool reg_req,
+ int *page_st)
+{
+ PAGECACHE_HASH_LINK *hash_link;
+ PAGECACHE_BLOCK_LINK *block;
+ int error= 0;
+ int page_status;
+
+ DBUG_ENTER("find_block");
+ KEYCACHE_THREAD_TRACE("find_block:begin");
+ DBUG_PRINT("enter", ("fd: %d pos: %lu wrmode: %d",
+ file->file, (ulong) pageno, wrmode));
+ KEYCACHE_DBUG_PRINT("find_block", ("fd: %d pos: %lu wrmode: %d",
+ file->file, (ulong) pageno,
+ wrmode));
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("check_pagecache",
+ test_key_cache(pagecache, "start of find_block", 0););
+#endif
+
+restart:
+ /* Find the hash link for the requested page (file, pageno) */
+ hash_link= get_hash_link(pagecache, file, pageno);
+
+ page_status= -1;
+ if ((block= hash_link->block) &&
+ block->hash_link == hash_link && (block->status & PCBLOCK_READ))
+ page_status= PAGE_READ;
+
+ if (wrmode && pagecache->resize_in_flush)
+ {
+ /* This is a write request during the flush phase of a resize operation */
+
+ if (page_status != PAGE_READ)
+ {
+ /* We don't need the page in the cache: we are going to write on disk */
+ DBUG_ASSERT(hash_link->requests > 0);
+ hash_link->requests--;
+ unlink_hash(pagecache, hash_link);
+ return 0;
+ }
+ if (!(block->status & PCBLOCK_IN_FLUSH))
+ {
+ DBUG_ASSERT(hash_link->requests > 0);
+ hash_link->requests--;
+ /*
+ Remove block to invalidate the page in the block buffer
+ as we are going to write directly on disk.
+ Although we have an exclusive lock for the updated key part
+ the control can be yielded by the current thread as we might
+ have unfinished readers of other key parts in the block
+ buffer. Still we are guaranteed not to have any readers
+ of the key part we are writing into until the block is
+ removed from the cache as we set the PCBLOCK_REASSIGNED
+ flag (see the code below that handles reading requests).
+ */
+ free_block(pagecache, block);
+ return 0;
+ }
+ /* Wait until the page is flushed on disk */
+ DBUG_ASSERT(hash_link->requests > 0);
+ hash_link->requests--;
+ {
+#ifdef THREAD
+ struct st_my_thread_var *thread= my_thread_var;
+ wqueue_add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
+ do
+ {
+ KEYCACHE_DBUG_PRINT("find_block: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while(thread->next);
+#else
+ KEYCACHE_DBUG_ASSERT(0);
+ /*
+ Given the use of "resize_in_flush", it seems impossible
+ that this whole branch is ever entered in single-threaded case
+ because "(wrmode && pagecache->resize_in_flush)" cannot be true.
+ TODO: Check this, and then put the whole branch into the
+ "#ifdef THREAD" guard.
+ */
+#endif
+ }
+ /* Invalidate page in the block if it has not been done yet */
+ if (block->status)
+ free_block(pagecache, block);
+ return 0;
+ }
+
+ if (page_status == PAGE_READ &&
+ (block->status & (PCBLOCK_IN_SWITCH | PCBLOCK_REASSIGNED)))
+ {
+ /* This is a request for a page to be removed from cache */
+
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("request for old page in block: %u "
+ "wrmode: %d block->status: %d",
+ PCBLOCK_NUMBER(pagecache, block), wrmode,
+ block->status));
+ /*
+ Only reading requests can proceed until the old dirty page is flushed,
+ all others are to be suspended, then resubmitted
+ */
+ if (!wrmode && !(block->status & PCBLOCK_REASSIGNED))
+ {
+ if (reg_req)
+ reg_requests(pagecache, block, 1);
+ }
+ else
+ {
+ DBUG_ASSERT(hash_link->requests > 0);
+ hash_link->requests--;
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("request waiting for old page to be saved"));
+ {
+#ifdef THREAD
+ struct st_my_thread_var *thread= my_thread_var;
+ /* Put the request into the queue of those waiting for the old page */
+ wqueue_add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
+ /* Wait until the request can be resubmitted */
+ do
+ {
+ KEYCACHE_DBUG_PRINT("find_block: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while(thread->next);
+#else
+ KEYCACHE_DBUG_ASSERT(0);
+ /* No parallel requests in single-threaded case */
+#endif
+ }
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("request for old page resubmitted"));
+ DBUG_PRINT("info", ("restarting..."));
+ /* Resubmit the request */
+ goto restart;
+ }
+ }
+ else
+ {
+ /* This is a request for a new page or for a page not to be removed */
+ if (! block)
+ {
+ /* No block is assigned for the page yet */
+ if (pagecache->blocks_unused)
+ {
+ if (pagecache->free_block_list)
+ {
+ /* There is a block in the free list. */
+ block= pagecache->free_block_list;
+ pagecache->free_block_list= block->next_used;
+ block->next_used= NULL;
+ }
+ else
+ {
+ /* There are some never used blocks, take first of them */
+ block= &pagecache->block_root[pagecache->blocks_used];
+ block->buffer= ADD_TO_PTR(pagecache->block_mem,
+ ((ulong) pagecache->blocks_used*
+ pagecache->block_size),
+ uchar*);
+ pagecache->blocks_used++;
+ }
+ pagecache->blocks_unused--;
+ DBUG_ASSERT(block->wlocks == 0);
+ DBUG_ASSERT(block->rlocks == 0);
+ DBUG_ASSERT(block->rlocks_queue == 0);
+ DBUG_ASSERT(block->pins == 0);
+ block->status= 0;
+#ifndef DBUG_OFF
+ block->type= PAGECACHE_EMPTY_PAGE;
+#endif
+ block->requests= 1;
+ block->temperature= PCBLOCK_COLD;
+ block->hits_left= init_hits_left;
+ block->last_hit_time= 0;
+ block->rec_lsn= LSN_MAX;
+ link_to_file_list(pagecache, block, file, 0);
+ block->hash_link= hash_link;
+ hash_link->block= block;
+ page_status= PAGE_TO_BE_READ;
+ DBUG_PRINT("info", ("page to be read set for page 0x%lx",
+ (ulong)block));
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("got free or never used block %u",
+ PCBLOCK_NUMBER(pagecache, block)));
+ }
+ else
+ {
+ /* There are no never used blocks, use a block from the LRU chain */
+
+ /*
+ Wait until a new block is added to the LRU chain;
+ several threads might wait here for the same page,
+ all of them must get the same block
+ */
+
+#ifdef THREAD
+ if (! pagecache->used_last)
+ {
+ struct st_my_thread_var *thread= my_thread_var;
+ thread->opt_info= (void *) hash_link;
+ wqueue_link_into_queue(&pagecache->waiting_for_block, thread);
+ do
+ {
+ KEYCACHE_DBUG_PRINT("find_block: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while (thread->next);
+ thread->opt_info= NULL;
+ }
+#else
+ KEYCACHE_DBUG_ASSERT(pagecache->used_last);
+#endif
+ block= hash_link->block;
+ if (! block)
+ {
+ /*
+ Take the first block from the LRU chain
+ unlinking it from the chain
+ */
+ block= pagecache->used_last->next_used;
+ block->hits_left= init_hits_left;
+ block->last_hit_time= 0;
+ if (reg_req)
+ reg_requests(pagecache, block, 1);
+ hash_link->block= block;
+ }
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(block->wlocks == 0);
+ DBUG_ASSERT(block->rlocks == 0);
+ DBUG_ASSERT(block->rlocks_queue == 0);
+ DBUG_ASSERT(block->pins == 0);
+
+ if (block->hash_link != hash_link &&
+ ! (block->status & PCBLOCK_IN_SWITCH) )
+ {
+ /* this is a primary request for a new page */
+ DBUG_ASSERT(block->wlocks == 0);
+ DBUG_ASSERT(block->rlocks == 0);
+ DBUG_ASSERT(block->rlocks_queue == 0);
+ DBUG_ASSERT(block->pins == 0);
+ block->status|= PCBLOCK_IN_SWITCH;
+
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("got block %u for new page",
+ PCBLOCK_NUMBER(pagecache, block)));
+
+ if (block->status & PCBLOCK_CHANGED)
+ {
+ /* The block contains a dirty page - push it out of the cache */
+
+ KEYCACHE_DBUG_PRINT("find_block", ("block is dirty"));
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ /*
+ The call is thread safe because only the current
+ thread might change the block->hash_link value
+ */
+ DBUG_ASSERT(block->pins == 0);
+ error= pagecache_fwrite(pagecache,
+ &block->hash_link->file,
+ block->buffer,
+ block->hash_link->pageno,
+ block->type,
+ pagecache->readwrite_flags);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ pagecache->global_cache_write++;
+ }
+
+ block->status|= PCBLOCK_REASSIGNED;
+ if (block->hash_link)
+ {
+ /*
+ Wait until all pending read requests
+ for this page are executed
+ (we could have avoided this waiting, if we had read
+ a page in the cache in a sweep, without yielding control)
+ */
+ wait_for_readers(pagecache, block);
+
+ /* Remove the hash link for this page from the hash table */
+ unlink_hash(pagecache, block->hash_link);
+ /* All pending requests for this page must be resubmitted */
+#ifdef THREAD
+ if (block->wqueue[COND_FOR_SAVED].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
+#endif
+ }
+ link_to_file_list(pagecache, block, file,
+ (my_bool)(block->hash_link ? 1 : 0));
+ PCBLOCK_INFO(block);
+ block->status= error ? PCBLOCK_ERROR : 0;
+ block->error= (int16) my_errno;
+#ifndef DBUG_OFF
+ block->type= PAGECACHE_EMPTY_PAGE;
+ if (error)
+ my_debug_put_break_here();
+#endif
+ block->hash_link= hash_link;
+ page_status= PAGE_TO_BE_READ;
+ DBUG_PRINT("info", ("page to be read set for page 0x%lx",
+ (ulong)block));
+
+ KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
+ KEYCACHE_DBUG_ASSERT(hash_link->block->hash_link == hash_link);
+ }
+ else
+ {
+ /* This is for secondary requests for a new page only */
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("block->hash_link: %p hash_link: %p "
+ "block->status: %u", block->hash_link,
+ hash_link, block->status ));
+ page_status= (((block->hash_link == hash_link) &&
+ (block->status & PCBLOCK_READ)) ?
+ PAGE_READ : PAGE_WAIT_TO_BE_READ);
+ }
+ }
+ }
+ else
+ {
+ if (reg_req)
+ reg_requests(pagecache, block, 1);
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("block->hash_link: %p hash_link: %p "
+ "block->status: %u", block->hash_link,
+ hash_link, block->status ));
+ page_status= (((block->hash_link == hash_link) &&
+ (block->status & PCBLOCK_READ)) ?
+ PAGE_READ : PAGE_WAIT_TO_BE_READ);
+ }
+ }
+
+ KEYCACHE_DBUG_ASSERT(page_status != -1);
+ *page_st= page_status;
+ DBUG_PRINT("info",
+ ("block: 0x%lx fd: %u pos: %lu block->status: %u page_status: %u",
+ (ulong) block, (uint) file->file,
+ (ulong) pageno, block->status, (uint) page_status));
+ KEYCACHE_DBUG_PRINT("find_block",
+ ("block: 0x%lx fd: %d pos: %lu block->status: %u page_status: %d",
+ (ulong) block,
+ file->file, (ulong) pageno, block->status,
+ page_status));
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("check_pagecache",
+ test_key_cache(pagecache, "end of find_block",0););
+#endif
+ KEYCACHE_THREAD_TRACE("find_block:end");
+ DBUG_RETURN(block);
+}
+
+
+static void add_pin(PAGECACHE_BLOCK_LINK *block)
+{
+ DBUG_ENTER("add_pin");
+ DBUG_PRINT("enter", ("block: 0x%lx pins: %u",
+ (ulong) block,
+ block->pins));
+ PCBLOCK_INFO(block);
+ block->pins++;
+#ifndef DBUG_OFF
+ {
+ PAGECACHE_PIN_INFO *info=
+ (PAGECACHE_PIN_INFO *)my_malloc(sizeof(PAGECACHE_PIN_INFO), MYF(0));
+ info->thread= my_thread_var;
+ info_link(&block->pin_list, info);
+ }
+#endif
+ DBUG_VOID_RETURN;
+}
+
+static void remove_pin(PAGECACHE_BLOCK_LINK *block, my_bool any
+#ifdef DBUG_OFF
+ __attribute__((unused))
+#endif
+ )
+{
+ DBUG_ENTER("remove_pin");
+ DBUG_PRINT("enter", ("block: 0x%lx pins: %u any: %d",
+ (ulong) block,
+ block->pins, (int)any));
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(block->pins > 0);
+ block->pins--;
+#ifndef DBUG_OFF
+ {
+ PAGECACHE_PIN_INFO *info= info_find(block->pin_list, my_thread_var, any);
+ DBUG_ASSERT(info != 0);
+ info_unlink(info);
+ my_free((uchar*) info, MYF(0));
+ }
+#endif
+ DBUG_VOID_RETURN;
+}
+#ifndef DBUG_OFF
+static void info_add_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
+{
+ PAGECACHE_LOCK_INFO *info=
+ (PAGECACHE_LOCK_INFO *)my_malloc(sizeof(PAGECACHE_LOCK_INFO), MYF(0));
+ info->thread= my_thread_var;
+ info->write_lock= wl;
+ info_link((PAGECACHE_PIN_INFO **)&block->lock_list,
+ (PAGECACHE_PIN_INFO *)info);
+}
+static void info_remove_lock(PAGECACHE_BLOCK_LINK *block)
+{
+ PAGECACHE_LOCK_INFO *info=
+ (PAGECACHE_LOCK_INFO *)info_find((PAGECACHE_PIN_INFO *)block->lock_list,
+ my_thread_var, FALSE);
+ DBUG_ASSERT(info != 0);
+ info_unlink((PAGECACHE_PIN_INFO *)info);
+ my_free((uchar*)info, MYF(0));
+}
+static void info_change_lock(PAGECACHE_BLOCK_LINK *block, my_bool wl)
+{
+ PAGECACHE_LOCK_INFO *info=
+ (PAGECACHE_LOCK_INFO *)info_find((PAGECACHE_PIN_INFO *)block->lock_list,
+ my_thread_var, FALSE);
+ DBUG_ASSERT(info != 0);
+ DBUG_ASSERT(info->write_lock != wl);
+ info->write_lock= wl;
+}
+#else
+#define info_add_lock(B,W)
+#define info_remove_lock(B)
+#define info_change_lock(B,W)
+#endif
+
+
+/**
+ @brief waiting for lock for read and write lock
+
+ @parem pagecache pointer to a page cache data structure
+ @parem block the block to work with
+ @param file file of the block when it was locked
+ @param pageno page number of the block when it was locked
+ @param lock_type MY_PTHREAD_LOCK_READ or MY_PTHREAD_LOCK_WRITE
+
+ @retval 0 OK
+ @retval 1 Can't lock this block, need retry
+*/
+
+static my_bool pagecache_wait_lock(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ PAGECACHE_FILE file,
+ pgcache_page_no_t pageno,
+ uint lock_type)
+{
+ /* Lock failed we will wait */
+#ifdef THREAD
+ struct st_my_thread_var *thread= my_thread_var;
+ DBUG_ENTER("pagecache_wait_lock");
+ DBUG_PRINT("info", ("fail to lock, waiting... 0x%lx", (ulong)block));
+ thread->lock_type= lock_type;
+ wqueue_add_to_queue(&block->wqueue[COND_FOR_WRLOCK], thread);
+ dec_counter_for_resize_op(pagecache);
+ do
+ {
+ KEYCACHE_DBUG_PRINT("get_wrlock: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while(thread->next);
+#else
+ DBUG_ASSERT(0);
+#endif
+ PCBLOCK_INFO(block);
+ if ((block->status & (PCBLOCK_REASSIGNED | PCBLOCK_IN_SWITCH)) ||
+ file.file != block->hash_link->file.file ||
+ pageno != block->hash_link->pageno)
+ {
+ DBUG_PRINT("info", ("the block 0x%lx changed => need retry "
+ "status: %x files %d != %d or pages %lu != %lu",
+ (ulong)block, block->status,
+ file.file, block->hash_link->file.file,
+ (ulong) pageno, (ulong) block->hash_link->pageno));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+/**
+ @brief Put on the block write lock
+
+ @parem pagecache pointer to a page cache data structure
+ @parem block the block to work with
+
+ @note We have loose scheme for locking by the same thread:
+ * Downgrade to read lock if no other locks are taken
+ * Our scheme of locking allow for the same thread
+ - the same kind of lock
+ - taking read lock if write lock present
+ - downgrading to read lock if still other place the same
+ thread keep write lock
+ * But unlock operation number should be the same to lock operation.
+ * If we try to get read lock having active write locks we put read
+ locks to queue, and as soon as write lock(s) gone the read locks
+ from queue came in force.
+ * If read lock is unlocked earlier then it came to force it
+ just removed from the queue
+
+ @retval 0 OK
+ @retval 1 Can't lock this block, need retry
+*/
+
+static my_bool get_wrlock(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block)
+{
+ PAGECACHE_FILE file= block->hash_link->file;
+ pgcache_page_no_t pageno= block->hash_link->pageno;
+ pthread_t locker= pthread_self();
+ DBUG_ENTER("get_wrlock");
+ DBUG_PRINT("info", ("the block 0x%lx "
+ "files %d(%d) pages %lu(%lu)",
+ (ulong) block,
+ file.file, block->hash_link->file.file,
+ (ulong) pageno, (ulong) block->hash_link->pageno));
+ PCBLOCK_INFO(block);
+ /*
+ We assume that the same thread will try write lock on block on which it
+ has already read lock.
+ */
+ while ((block->wlocks && !pthread_equal(block->write_locker, locker)) ||
+ block->rlocks)
+ {
+ /* Lock failed we will wait */
+ if (pagecache_wait_lock(pagecache, block, file, pageno,
+ MY_PTHREAD_LOCK_WRITE))
+ DBUG_RETURN(1);
+ }
+ /* we are doing it by global cache mutex protection, so it is OK */
+ block->wlocks++;
+ block->write_locker= locker;
+ DBUG_PRINT("info", ("WR lock set, block 0x%lx", (ulong)block));
+ DBUG_RETURN(0);
+}
+
+
+/*
+ @brief Put on the block read lock
+
+ @param pagecache pointer to a page cache data structure
+ @param block the block to work with
+ @param user_file Unique handler per handler file. Used to check if
+ we request many write locks withing the same
+ statement
+
+ @note see note for get_wrlock().
+
+ @retvalue 0 OK
+ @retvalue 1 Can't lock this block, need retry
+*/
+
+static my_bool get_rdlock(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block)
+{
+ PAGECACHE_FILE file= block->hash_link->file;
+ pgcache_page_no_t pageno= block->hash_link->pageno;
+ pthread_t locker= pthread_self();
+ DBUG_ENTER("get_rdlock");
+ DBUG_PRINT("info", ("the block 0x%lx "
+ "files %d(%d) pages %lu(%lu)",
+ (ulong) block,
+ file.file, block->hash_link->file.file,
+ (ulong) pageno, (ulong) block->hash_link->pageno));
+ PCBLOCK_INFO(block);
+ while (block->wlocks && !pthread_equal(block->write_locker, locker))
+ {
+ /* Lock failed we will wait */
+ if (pagecache_wait_lock(pagecache, block, file, pageno,
+ MY_PTHREAD_LOCK_READ))
+ DBUG_RETURN(1);
+ }
+ /* we are doing it by global cache mutex protection, so it is OK */
+ if (block->wlocks)
+ {
+ DBUG_ASSERT(pthread_equal(block->write_locker, locker));
+ block->rlocks_queue++;
+ DBUG_PRINT("info", ("RD lock put into queue, block 0x%lx", (ulong)block));
+ }
+ else
+ {
+ block->rlocks++;
+ DBUG_PRINT("info", ("RD lock set, block 0x%lx", (ulong)block));
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ @brief Remove write lock from the block
+
+ @param pagecache pointer to a page cache data structure
+ @param block the block to work with
+ @param read_lock downgrade to read lock
+
+ @note see note for get_wrlock().
+*/
+
+static void release_wrlock(PAGECACHE_BLOCK_LINK *block, my_bool read_lock)
+{
+ DBUG_ENTER("release_wrlock");
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(block->wlocks > 0);
+ DBUG_ASSERT(block->rlocks == 0);
+ DBUG_ASSERT(block->pins > 0);
+ if (read_lock)
+ block->rlocks_queue++;
+ if (block->wlocks == 1)
+ {
+ block->rlocks= block->rlocks_queue;
+ block->rlocks_queue= 0;
+ }
+ block->wlocks--;
+ if (block->wlocks > 0)
+ DBUG_VOID_RETURN; /* Multiple write locked */
+ DBUG_PRINT("info", ("WR lock reset, block 0x%lx", (ulong)block));
+#ifdef THREAD
+ /* release all threads waiting for read lock or one waiting for write */
+ if (block->wqueue[COND_FOR_WRLOCK].last_thread)
+ wqueue_release_one_locktype_from_queue(&block->wqueue[COND_FOR_WRLOCK]);
+#endif
+ PCBLOCK_INFO(block);
+ DBUG_VOID_RETURN;
+}
+
+/*
+ @brief Remove read lock from the block
+
+ @param pagecache pointer to a page cache data structure
+ @param block the block to work with
+
+ @note see note for get_wrlock().
+*/
+
+static void release_rdlock(PAGECACHE_BLOCK_LINK *block)
+{
+ DBUG_ENTER("release_wrlock");
+ PCBLOCK_INFO(block);
+ if (block->wlocks)
+ {
+ DBUG_ASSERT(pthread_equal(block->write_locker, pthread_self()));
+ DBUG_ASSERT(block->rlocks == 0);
+ DBUG_ASSERT(block->rlocks_queue > 0);
+ block->rlocks_queue--;
+ DBUG_PRINT("info", ("RD lock queue decreased, block 0x%lx", (ulong)block));
+ DBUG_VOID_RETURN;
+ }
+ DBUG_ASSERT(block->rlocks > 0);
+ DBUG_ASSERT(block->rlocks_queue == 0);
+ block->rlocks--;
+ DBUG_PRINT("info", ("RD lock decreased, block 0x%lx", (ulong)block));
+ if (block->rlocks > 0)
+ DBUG_VOID_RETURN; /* Multiple write locked */
+ DBUG_PRINT("info", ("RD lock reset, block 0x%lx", (ulong)block));
+#ifdef THREAD
+ /* release all threads waiting for read lock or one waiting for write */
+ if (block->wqueue[COND_FOR_WRLOCK].last_thread)
+ wqueue_release_one_locktype_from_queue(&block->wqueue[COND_FOR_WRLOCK]);
+#endif
+ PCBLOCK_INFO(block);
+ DBUG_VOID_RETURN;
+}
+
+/**
+ @brief Try to lock/unlock and pin/unpin the block
+
+ @param pagecache pointer to a page cache data structure
+ @param block the block to work with
+ @param lock lock change mode
+ @param pin pinchange mode
+ @param file File handler requesting pin
+ @param any allow unpinning block pinned by any thread; possible
+ only if not locked, see pagecache_unlock_by_link()
+
+ @retval 0 OK
+ @retval 1 Try to lock the block failed
+*/
+
+static my_bool make_lock_and_pin(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin,
+ my_bool any)
+{
+ DBUG_ENTER("make_lock_and_pin");
+
+ DBUG_PRINT("enter", ("block: 0x%lx", (ulong)block));
+#ifndef DBUG_OFF
+ if (block)
+ {
+ DBUG_PRINT("enter", ("block: 0x%lx (%u) wrlocks: %u rdlocks: %u "
+ "rdlocks_q: %u pins: %u lock: %s pin: %s any %d",
+ (ulong)block, PCBLOCK_NUMBER(pagecache, block),
+ block->wlocks, block->rlocks, block->rlocks_queue,
+ block->pins,
+ page_cache_page_lock_str[lock],
+ page_cache_page_pin_str[pin], (int)any));
+ PCBLOCK_INFO(block);
+ }
+#endif
+
+ DBUG_ASSERT(!any ||
+ ((lock == PAGECACHE_LOCK_LEFT_UNLOCKED) &&
+ (pin == PAGECACHE_UNPIN)));
+
+ switch (lock) {
+ case PAGECACHE_LOCK_WRITE: /* free -> write */
+ /* Writelock and pin the buffer */
+ if (get_wrlock(pagecache, block))
+ {
+ /* Couldn't lock because block changed status => need retry */
+ goto retry;
+ }
+
+ /* The cache is locked so nothing afraid of */
+ add_pin(block);
+ info_add_lock(block, 1);
+ break;
+ case PAGECACHE_LOCK_WRITE_TO_READ: /* write -> read */
+ case PAGECACHE_LOCK_WRITE_UNLOCK: /* write -> free */
+ /* Removes write lock and puts read lock */
+ release_wrlock(block, lock == PAGECACHE_LOCK_WRITE_TO_READ);
+ /* fall through */
+ case PAGECACHE_LOCK_READ_UNLOCK: /* read -> free */
+ if (lock == PAGECACHE_LOCK_READ_UNLOCK)
+ release_rdlock(block);
+ /* fall through */
+ case PAGECACHE_LOCK_LEFT_READLOCKED: /* read -> read */
+ if (pin == PAGECACHE_UNPIN)
+ {
+ remove_pin(block, FALSE);
+ }
+ if (lock == PAGECACHE_LOCK_WRITE_TO_READ)
+ {
+ info_change_lock(block, 0);
+ }
+ else if (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
+ lock == PAGECACHE_LOCK_READ_UNLOCK)
+ {
+ info_remove_lock(block);
+ }
+ break;
+ case PAGECACHE_LOCK_READ: /* free -> read */
+ if (get_rdlock(pagecache, block))
+ {
+ /* Couldn't lock because block changed status => need retry */
+ goto retry;
+ }
+
+ if (pin == PAGECACHE_PIN)
+ {
+ /* The cache is locked so nothing afraid off */
+ add_pin(block);
+ }
+ info_add_lock(block, 0);
+ break;
+ case PAGECACHE_LOCK_LEFT_UNLOCKED: /* free -> free */
+ if (pin == PAGECACHE_UNPIN)
+ {
+ remove_pin(block, any);
+ }
+ /* fall through */
+ case PAGECACHE_LOCK_LEFT_WRITELOCKED: /* write -> write */
+ break; /* do nothing */
+ default:
+ DBUG_ASSERT(0); /* Never should happened */
+ }
+
+#ifndef DBUG_OFF
+ if (block)
+ PCBLOCK_INFO(block);
+#endif
+ DBUG_RETURN(0);
+retry:
+ DBUG_PRINT("INFO", ("Retry block 0x%lx", (ulong)block));
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(block->hash_link->requests > 0);
+ block->hash_link->requests--;
+ PCBLOCK_INFO(block);
+ DBUG_RETURN(1);
+
+}
+
+
+/*
+ Read into a key cache block buffer from disk.
+
+ SYNOPSIS
+
+ read_block()
+ pagecache pointer to a page cache data structure
+ block block to which buffer the data is to be read
+ primary <-> the current thread will read the data
+
+ RETURN VALUE
+ None
+
+ NOTES.
+ The function either reads a page data from file to the block buffer,
+ or waits until another thread reads it. What page to read is determined
+ by a block parameter - reference to a hash link for this page.
+ If an error occurs THE PCBLOCK_ERROR bit is set in the block status.
+
+ On entry cache_lock is locked
+*/
+
+static void read_block(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ my_bool primary)
+{
+
+ DBUG_ENTER("read_block");
+ DBUG_PRINT("enter", ("read block: 0x%lx primary: %d",
+ (ulong)block, primary));
+ if (primary)
+ {
+ size_t error;
+ /*
+ This code is executed only by threads
+ that submitted primary requests
+ */
+
+ pagecache->global_cache_read++;
+ /* Page is not in buffer yet, is to be read from disk */
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ /*
+ Here other threads may step in and register as secondary readers.
+ They will register in block->wqueue[COND_FOR_REQUESTED].
+ */
+ error= pagecache_fread(pagecache, &block->hash_link->file,
+ block->buffer,
+ block->hash_link->pageno,
+ pagecache->readwrite_flags);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ if (error)
+ {
+ block->status|= PCBLOCK_ERROR;
+ block->error= (int16) my_errno;
+ my_debug_put_break_here();
+ }
+ else
+ {
+ block->status|= PCBLOCK_READ;
+ if ((*block->hash_link->file.read_callback)(block->buffer,
+ block->hash_link->pageno,
+ block->hash_link->
+ file.callback_data))
+ {
+ DBUG_PRINT("error", ("read callback problem"));
+ block->status|= PCBLOCK_ERROR;
+ block->error= (int16) my_errno;
+ my_debug_put_break_here();
+ }
+ }
+ DBUG_PRINT("read_block",
+ ("primary request: new page in cache"));
+ /* Signal that all pending requests for this page now can be processed */
+#ifdef THREAD
+ if (block->wqueue[COND_FOR_REQUESTED].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_REQUESTED]);
+#endif
+ }
+ else
+ {
+ /*
+ This code is executed only by threads
+ that submitted secondary requests
+ */
+
+#ifdef THREAD
+ struct st_my_thread_var *thread= my_thread_var;
+ /* Put the request into a queue and wait until it can be processed */
+ wqueue_add_to_queue(&block->wqueue[COND_FOR_REQUESTED], thread);
+ do
+ {
+ DBUG_PRINT("read_block: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while (thread->next);
+#else
+ KEYCACHE_DBUG_ASSERT(0);
+ /* No parallel requests in single-threaded case */
+#endif
+ DBUG_PRINT("read_block",
+ ("secondary request: new page in cache"));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Set LSN on the page to the given one if the given LSN is bigger
+
+ @param pagecache pointer to a page cache data structure
+ @param lsn LSN to set
+ @param block block to check and set
+*/
+
+static void check_and_set_lsn(PAGECACHE *pagecache,
+ LSN lsn, PAGECACHE_BLOCK_LINK *block)
+{
+ LSN old;
+ DBUG_ENTER("check_and_set_lsn");
+ /*
+ In recovery, we can _ma_unpin_all_pages() to put a LSN on page, though
+ page would be PAGECACHE_PLAIN_PAGE (transactionality temporarily disabled
+ to not log REDOs).
+ */
+ DBUG_ASSERT((block->type == PAGECACHE_LSN_PAGE) || maria_in_recovery);
+ old= lsn_korr(block->buffer);
+ DBUG_PRINT("info", ("old lsn: (%lu, 0x%lx) new lsn: (%lu, 0x%lx)",
+ LSN_IN_PARTS(old), LSN_IN_PARTS(lsn)));
+ if (cmp_translog_addr(lsn, old) > 0)
+ {
+
+ DBUG_ASSERT(block->type != PAGECACHE_READ_UNKNOWN_PAGE);
+ lsn_store(block->buffer, lsn);
+ /* we stored LSN in page so we dirtied it */
+ if (!(block->status & PCBLOCK_CHANGED))
+ link_to_changed_list(pagecache, block);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Unlock/unpin page and put LSN stamp if it need
+
+ @param pagecache pointer to a page cache data structure
+ @pagam file handler for the file for the block of data to be read
+ @param pageno number of the block of data in the file
+ @param lock lock change
+ @param pin pin page
+ @param first_REDO_LSN_for_page do not set it if it is zero
+ @param lsn if it is not LSN_IMPOSSIBLE (0) and it
+ is bigger then LSN on the page it will be written on
+ the page
+ @param was_changed should be true if the page was write locked with
+ direct link giving and the page was changed
+
+ @note
+ Pininig uses requests registration mechanism it works following way:
+ | beginnig | ending |
+ | of func. | of func. |
+ ----------------------------+-------------+---------------+
+ PAGECACHE_PIN_LEFT_PINNED | - | - |
+ PAGECACHE_PIN_LEFT_UNPINNED | reg request | unreg request |
+ PAGECACHE_PIN | reg request | - |
+ PAGECACHE_UNPIN | - | unreg request |
+
+
+*/
+
+void pagecache_unlock(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin,
+ LSN first_REDO_LSN_for_page,
+ LSN lsn, my_bool was_changed)
+{
+ PAGECACHE_BLOCK_LINK *block;
+ int page_st;
+ DBUG_ENTER("pagecache_unlock");
+ DBUG_PRINT("enter", ("fd: %u page: %lu %s %s",
+ (uint) file->file, (ulong) pageno,
+ page_cache_page_lock_str[lock],
+ page_cache_page_pin_str[pin]));
+ /* we do not allow any lock/pin increasing here */
+ DBUG_ASSERT(pin != PAGECACHE_PIN);
+ DBUG_ASSERT(lock != PAGECACHE_LOCK_READ);
+ DBUG_ASSERT(lock != PAGECACHE_LOCK_WRITE);
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ /*
+ As soon as we keep lock cache can be used, and we have lock because want
+ to unlock.
+ */
+ DBUG_ASSERT(pagecache->can_be_used);
+
+ inc_counter_for_resize_op(pagecache);
+ /* See NOTE for pagecache_unlock about registering requests */
+ block= find_block(pagecache, file, pageno, 0, 0,
+ pin == PAGECACHE_PIN_LEFT_UNPINNED, &page_st);
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(block != 0 && page_st == PAGE_READ);
+ if (first_REDO_LSN_for_page)
+ {
+ DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE_UNLOCK);
+ DBUG_ASSERT(pin == PAGECACHE_UNPIN);
+ pagecache_set_block_rec_lsn(block, first_REDO_LSN_for_page);
+ }
+ if (lsn != LSN_IMPOSSIBLE)
+ check_and_set_lsn(pagecache, lsn, block);
+
+ /* if we lock for write we must link the block to changed blocks */
+ DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0 ||
+ (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
+ lock == PAGECACHE_LOCK_WRITE_TO_READ ||
+ lock == PAGECACHE_LOCK_LEFT_WRITELOCKED));
+ /*
+ if was_changed then status should be PCBLOCK_DIRECT_W or marked
+ as dirty
+ */
+ DBUG_ASSERT(!was_changed || (block->status & PCBLOCK_DIRECT_W) ||
+ (block->status & PCBLOCK_CHANGED));
+ if ((block->status & PCBLOCK_DIRECT_W) &&
+ (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
+ lock == PAGECACHE_LOCK_WRITE_TO_READ))
+ {
+ if (!(block->status & PCBLOCK_CHANGED) && was_changed)
+ link_to_changed_list(pagecache, block);
+ block->status&= ~PCBLOCK_DIRECT_W;
+ DBUG_PRINT("info", ("Drop PCBLOCK_DIRECT_W for block: 0x%lx",
+ (ulong) block));
+ }
+
+ if (make_lock_and_pin(pagecache, block, lock, pin, FALSE))
+ {
+ DBUG_ASSERT(0); /* should not happend */
+ }
+
+ remove_reader(block);
+ /*
+ Link the block into the LRU chain if it's the last submitted request
+ for the block and block will not be pinned.
+ See NOTE for pagecache_unlock about registering requests.
+ */
+ if (pin != PAGECACHE_PIN_LEFT_PINNED)
+ unreg_request(pagecache, block, 1);
+
+ dec_counter_for_resize_op(pagecache);
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Unpin page
+
+ SYNOPSIS
+ pagecache_unpin()
+ pagecache pointer to a page cache data structure
+ file handler for the file for the block of data to be read
+ pageno number of the block of data in the file
+ lsn if it is not LSN_IMPOSSIBLE (0) and it
+ is bigger then LSN on the page it will be written on
+ the page
+*/
+
+void pagecache_unpin(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ LSN lsn)
+{
+ PAGECACHE_BLOCK_LINK *block;
+ int page_st;
+ DBUG_ENTER("pagecache_unpin");
+ DBUG_PRINT("enter", ("fd: %u page: %lu",
+ (uint) file->file, (ulong) pageno));
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ /*
+ As soon as we keep lock cache can be used, and we have lock bacause want
+ aunlock.
+ */
+ DBUG_ASSERT(pagecache->can_be_used);
+
+ inc_counter_for_resize_op(pagecache);
+ /* See NOTE for pagecache_unlock about registering requests */
+ block= find_block(pagecache, file, pageno, 0, 0, 0, &page_st);
+ DBUG_ASSERT(block != 0);
+ DBUG_ASSERT(page_st == PAGE_READ);
+ /* we can't unpin such page without unlock */
+ DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0);
+
+ if (lsn != LSN_IMPOSSIBLE)
+ check_and_set_lsn(pagecache, lsn, block);
+
+ /*
+ we can just unpin only with keeping read lock because:
+ a) we can't pin without any lock
+ b) we can't unpin keeping write lock
+ */
+ if (make_lock_and_pin(pagecache, block,
+ PAGECACHE_LOCK_LEFT_READLOCKED,
+ PAGECACHE_UNPIN, FALSE))
+ DBUG_ASSERT(0); /* should not happend */
+
+ remove_reader(block);
+ /*
+ Link the block into the LRU chain if it's the last submitted request
+ for the block and block will not be pinned.
+ See NOTE for pagecache_unlock about registering requests
+ */
+ unreg_request(pagecache, block, 1);
+
+ dec_counter_for_resize_op(pagecache);
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief Unlock/unpin page and put LSN stamp if it need
+ (uses direct block/page pointer)
+
+ @param pagecache pointer to a page cache data structure
+ @param link direct link to page (returned by read or write)
+ @param lock lock change
+ @param pin pin page
+ @param first_REDO_LSN_for_page do not set it if it is LSN_IMPOSSIBLE (0)
+ @param lsn if it is not LSN_IMPOSSIBLE and it is bigger then
+ LSN on the page it will be written on the page
+ @param was_changed should be true if the page was write locked with
+ direct link giving and the page was changed
+ @param any allow unpinning block pinned by any thread; possible
+ only if not locked
+
+ @note 'any' is a hack so that _ma_bitmap_unpin_all() is allowed to unpin
+ non-locked bitmap pages pinned by other threads. Because it always uses
+ PAGECACHE_LOCK_LEFT_UNLOCKED and PAGECACHE_UNPIN
+ (see write_changed_bitmap()), the hack is limited to these conditions.
+*/
+
+void pagecache_unlock_by_link(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin,
+ LSN first_REDO_LSN_for_page,
+ LSN lsn, my_bool was_changed,
+ my_bool any)
+{
+ DBUG_ENTER("pagecache_unlock_by_link");
+ DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu changed: %d %s %s",
+ (ulong) block,
+ (uint) block->hash_link->file.file,
+ (ulong) block->hash_link->pageno, was_changed,
+ page_cache_page_lock_str[lock],
+ page_cache_page_pin_str[pin]));
+ /*
+ We do not allow any lock/pin increasing here and page can't be
+ unpinned because we use direct link.
+ */
+ DBUG_ASSERT(pin != PAGECACHE_PIN);
+ DBUG_ASSERT(pin != PAGECACHE_PIN_LEFT_UNPINNED);
+ DBUG_ASSERT(lock != PAGECACHE_LOCK_READ);
+ DBUG_ASSERT(lock != PAGECACHE_LOCK_WRITE);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ if (pin == PAGECACHE_PIN_LEFT_UNPINNED &&
+ lock == PAGECACHE_LOCK_READ_UNLOCK)
+ {
+ if (make_lock_and_pin(pagecache, block, lock, pin, FALSE))
+ DBUG_ASSERT(0); /* should not happend */
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_VOID_RETURN;
+ }
+
+ /*
+ As soon as we keep lock cache can be used, and we have lock because want
+ unlock.
+ */
+ DBUG_ASSERT(pagecache->can_be_used);
+
+ inc_counter_for_resize_op(pagecache);
+ if (was_changed)
+ {
+ if (first_REDO_LSN_for_page != LSN_IMPOSSIBLE)
+ {
+ /*
+ LOCK_READ_UNLOCK is ok here as the page may have first locked
+ with WRITE lock that was temporarly converted to READ lock before
+ it's unpinned
+ */
+ DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
+ lock == PAGECACHE_LOCK_READ_UNLOCK);
+ DBUG_ASSERT(pin == PAGECACHE_UNPIN);
+ pagecache_set_block_rec_lsn(block, first_REDO_LSN_for_page);
+ }
+ if (lsn != LSN_IMPOSSIBLE)
+ check_and_set_lsn(pagecache, lsn, block);
+ /*
+ Reset error flag. Mark also that page is active; This may not have
+ been the case if there was an error reading the page
+ */
+ block->status= (block->status & ~PCBLOCK_ERROR) | PCBLOCK_READ;
+ }
+
+ /* if we lock for write we must link the block to changed blocks */
+ DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0 ||
+ (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
+ lock == PAGECACHE_LOCK_WRITE_TO_READ ||
+ lock == PAGECACHE_LOCK_LEFT_WRITELOCKED));
+ /*
+ If was_changed then status should be PCBLOCK_DIRECT_W or marked
+ as dirty
+ */
+ DBUG_ASSERT(!was_changed || (block->status & PCBLOCK_DIRECT_W) ||
+ (block->status & PCBLOCK_CHANGED));
+ if ((block->status & PCBLOCK_DIRECT_W) &&
+ (lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
+ lock == PAGECACHE_LOCK_WRITE_TO_READ))
+ {
+ if (!(block->status & PCBLOCK_CHANGED) && was_changed)
+ link_to_changed_list(pagecache, block);
+ block->status&= ~PCBLOCK_DIRECT_W;
+ DBUG_PRINT("info", ("Drop PCBLOCK_DIRECT_W for block: 0x%lx",
+ (ulong) block));
+ }
+
+ if (make_lock_and_pin(pagecache, block, lock, pin, any))
+ DBUG_ASSERT(0); /* should not happend */
+
+ /*
+ Link the block into the LRU chain if it's the last submitted request
+ for the block and block will not be pinned.
+ See NOTE for pagecache_unlock about registering requests.
+ */
+ if (pin != PAGECACHE_PIN_LEFT_PINNED)
+ unreg_request(pagecache, block, 1);
+
+ dec_counter_for_resize_op(pagecache);
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Unpin page
+ (uses direct block/page pointer)
+
+ SYNOPSIS
+ pagecache_unpin_by_link()
+ pagecache pointer to a page cache data structure
+ link direct link to page (returned by read or write)
+ lsn if it is not LSN_IMPOSSIBLE (0) and it
+ is bigger then LSN on the page it will be written on
+ the page
+*/
+
+void pagecache_unpin_by_link(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ LSN lsn)
+{
+ DBUG_ENTER("pagecache_unpin_by_link");
+ DBUG_PRINT("enter", ("block: 0x%lx fd: %u page: %lu",
+ (ulong) block,
+ (uint) block->hash_link->file.file,
+ (ulong) block->hash_link->pageno));
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ /*
+ As soon as we keep lock cache can be used, and we have lock because want
+ unlock.
+ */
+ DBUG_ASSERT(pagecache->can_be_used);
+ /* we can't unpin such page without unlock */
+ DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0);
+
+ inc_counter_for_resize_op(pagecache);
+
+ if (lsn != LSN_IMPOSSIBLE)
+ check_and_set_lsn(pagecache, lsn, block);
+
+ /*
+ We can just unpin only with keeping read lock because:
+ a) we can't pin without any lock
+ b) we can't unpin keeping write lock
+ */
+ if (make_lock_and_pin(pagecache, block,
+ PAGECACHE_LOCK_LEFT_READLOCKED,
+ PAGECACHE_UNPIN, FALSE))
+ DBUG_ASSERT(0); /* should not happend */
+
+ /*
+ Link the block into the LRU chain if it's the last submitted request
+ for the block and block will not be pinned.
+ See NOTE for pagecache_unlock about registering requests.
+ */
+ unreg_request(pagecache, block, 1);
+
+ dec_counter_for_resize_op(pagecache);
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+
+ DBUG_VOID_RETURN;
+}
+
+/* description of how to change lock before and after read/write */
+struct rw_lock_change
+{
+ my_bool need_lock_change; /* need changing of lock at the end */
+ enum pagecache_page_lock new_lock; /* lock at the beginning */
+ enum pagecache_page_lock unlock_lock; /* lock at the end */
+};
+
+/* description of how to change pin before and after read/write */
+struct rw_pin_change
+{
+ enum pagecache_page_pin new_pin; /* pin status at the beginning */
+ enum pagecache_page_pin unlock_pin; /* pin status at the end */
+};
+
+/**
+ Depending on the lock which the user wants in pagecache_read(), we
+ need to acquire a first type of lock at start of pagecache_read(), and
+ downgrade it to a second type of lock at end. For example, if user
+ asked for no lock (PAGECACHE_LOCK_LEFT_UNLOCKED) this translates into
+ taking first a read lock PAGECACHE_LOCK_READ (to rightfully block on
+ existing write locks) then read then unlock the lock i.e. change lock
+ to PAGECACHE_LOCK_READ_UNLOCK (the "1" below tells that a change is
+ needed).
+*/
+
+static struct rw_lock_change lock_to_read[8]=
+{
+ { /*PAGECACHE_LOCK_LEFT_UNLOCKED*/
+ 1,
+ PAGECACHE_LOCK_READ, PAGECACHE_LOCK_READ_UNLOCK
+ },
+ { /*PAGECACHE_LOCK_LEFT_READLOCKED*/
+ 0,
+ PAGECACHE_LOCK_LEFT_READLOCKED, PAGECACHE_LOCK_LEFT_READLOCKED
+ },
+ { /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/
+ 0,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, PAGECACHE_LOCK_LEFT_WRITELOCKED
+ },
+ { /*PAGECACHE_LOCK_READ*/
+ 1,
+ PAGECACHE_LOCK_READ, PAGECACHE_LOCK_LEFT_READLOCKED
+ },
+ { /*PAGECACHE_LOCK_WRITE*/
+ 1,
+ PAGECACHE_LOCK_WRITE, PAGECACHE_LOCK_LEFT_WRITELOCKED
+ },
+ { /*PAGECACHE_LOCK_READ_UNLOCK*/
+ 1,
+ PAGECACHE_LOCK_LEFT_READLOCKED, PAGECACHE_LOCK_READ_UNLOCK
+ },
+ { /*PAGECACHE_LOCK_WRITE_UNLOCK*/
+ 1,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, PAGECACHE_LOCK_WRITE_UNLOCK
+ },
+ { /*PAGECACHE_LOCK_WRITE_TO_READ*/
+ 1,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, PAGECACHE_LOCK_WRITE_TO_READ
+ }
+};
+
+/**
+ Two sets of pin modes (every as for lock upper but for pinning). The
+ difference between sets if whether we are going to provide caller with
+ reference on the block or not
+*/
+
+static struct rw_pin_change lock_to_pin[2][8]=
+{
+ {
+ { /*PAGECACHE_LOCK_LEFT_UNLOCKED*/
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_PIN_LEFT_UNPINNED
+ },
+ { /*PAGECACHE_LOCK_LEFT_READLOCKED*/
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ },
+ { /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_PIN_LEFT_PINNED
+ },
+ { /*PAGECACHE_LOCK_READ*/
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_PIN_LEFT_UNPINNED
+ },
+ { /*PAGECACHE_LOCK_WRITE*/
+ PAGECACHE_PIN,
+ PAGECACHE_PIN_LEFT_PINNED
+ },
+ { /*PAGECACHE_LOCK_READ_UNLOCK*/
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_PIN_LEFT_UNPINNED
+ },
+ { /*PAGECACHE_LOCK_WRITE_UNLOCK*/
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_UNPIN
+ },
+ { /*PAGECACHE_LOCK_WRITE_TO_READ*/
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_UNPIN
+ }
+ },
+ {
+ { /*PAGECACHE_LOCK_LEFT_UNLOCKED*/
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_PIN_LEFT_UNPINNED
+ },
+ { /*PAGECACHE_LOCK_LEFT_READLOCKED*/
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ },
+ { /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_PIN_LEFT_PINNED
+ },
+ { /*PAGECACHE_LOCK_READ*/
+ PAGECACHE_PIN,
+ PAGECACHE_PIN_LEFT_PINNED
+ },
+ { /*PAGECACHE_LOCK_WRITE*/
+ PAGECACHE_PIN,
+ PAGECACHE_PIN_LEFT_PINNED
+ },
+ { /*PAGECACHE_LOCK_READ_UNLOCK*/
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_PIN_LEFT_UNPINNED
+ },
+ { /*PAGECACHE_LOCK_WRITE_UNLOCK*/
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_UNPIN
+ },
+ { /*PAGECACHE_LOCK_WRITE_TO_READ*/
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_PIN_LEFT_PINNED,
+ }
+ }
+};
+
+
+/*
+ @brief Read a block of data from a cached file into a buffer;
+
+ @param pagecache pointer to a page cache data structure
+ @param file handler for the file for the block of data to be read
+ @param pageno number of the block of data in the file
+ @param level determines the weight of the data
+ @param buff buffer to where the data must be placed
+ @param type type of the page
+ @param lock lock change
+ @param link link to the page if we pin it
+
+ @return address from where the data is placed if successful, 0 - otherwise.
+
+ @note Pin will be chosen according to lock parameter (see lock_to_pin)
+
+ @note 'buff', if not NULL, must be long-aligned.
+
+ @note If buff==0 then we provide reference on the page so should keep the
+ page pinned.
+*/
+
+uchar *pagecache_read(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ uint level,
+ uchar *buff,
+ enum pagecache_page_type type,
+ enum pagecache_page_lock lock,
+ PAGECACHE_BLOCK_LINK **page_link)
+{
+ my_bool error= 0;
+ enum pagecache_page_pin
+ new_pin= lock_to_pin[buff==0][lock].new_pin,
+ unlock_pin= lock_to_pin[buff==0][lock].unlock_pin;
+ PAGECACHE_BLOCK_LINK *fake_link;
+ my_bool reg_request;
+#ifndef DBUG_OFF
+ char llbuf[22];
+ DBUG_ENTER("pagecache_read");
+ DBUG_PRINT("enter", ("fd: %u page: %s buffer: 0x%lx level: %u "
+ "t:%s (%d)%s->%s %s->%s",
+ (uint) file->file, ullstr(pageno, llbuf),
+ (ulong) buff, level,
+ page_cache_page_type_str[type],
+ lock_to_read[lock].need_lock_change,
+ page_cache_page_lock_str[lock_to_read[lock].new_lock],
+ page_cache_page_lock_str[lock_to_read[lock].unlock_lock],
+ page_cache_page_pin_str[new_pin],
+ page_cache_page_pin_str[unlock_pin]));
+ DBUG_ASSERT(buff != 0 || (buff == 0 && (unlock_pin == PAGECACHE_PIN ||
+ unlock_pin == PAGECACHE_PIN_LEFT_PINNED)));
+ DBUG_ASSERT(pageno < ((ULL(1)) << 40));
+#endif
+
+ if (!page_link)
+ page_link= &fake_link;
+ *page_link= 0; /* Catch errors */
+
+restart:
+
+ if (pagecache->can_be_used)
+ {
+ /* Key cache is used */
+ PAGECACHE_BLOCK_LINK *block;
+ uint status;
+ int page_st;
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ if (!pagecache->can_be_used)
+ {
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ goto no_key_cache;
+ }
+
+ inc_counter_for_resize_op(pagecache);
+ pagecache->global_cache_r_requests++;
+ /* See NOTE for pagecache_unlock about registering requests. */
+ reg_request= ((new_pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
+ (new_pin == PAGECACHE_PIN));
+ block= find_block(pagecache, file, pageno, level,
+ lock == PAGECACHE_LOCK_WRITE,
+ reg_request, &page_st);
+ DBUG_PRINT("info", ("Block type: %s current type %s",
+ page_cache_page_type_str[block->type],
+ page_cache_page_type_str[type]));
+ if (((block->status & PCBLOCK_ERROR) == 0) && (page_st != PAGE_READ))
+ {
+ /* The requested page is to be read into the block buffer */
+ read_block(pagecache, block,
+ (my_bool)(page_st == PAGE_TO_BE_READ));
+ DBUG_PRINT("info", ("read is done"));
+ }
+ /*
+ Assert after block is read. Imagine two concurrent SELECTs on same
+ table (thread1 and 2), which want to pagecache_read() the same
+ pageno/fileno. Thread1 calls find_block(), decides to evict a dirty
+ page from LRU; while it's writing this dirty page to disk, it is
+ pre-empted and thread2 runs its find_block(), gets the block (in
+ PAGE_TO_BE_READ state). This block is still containing the in-eviction
+ dirty page so has an its type, which cannot be tested.
+ So thread2 has to wait for read_block() to finish (when it wakes up in
+ read_block(), it's woken up by read_block() of thread1, which implies
+ that block's type was set to EMPTY by thread1 as part of find_block()).
+ */
+ DBUG_ASSERT(block->type == PAGECACHE_EMPTY_PAGE ||
+ block->type == type ||
+ type == PAGECACHE_LSN_PAGE ||
+ type == PAGECACHE_READ_UNKNOWN_PAGE ||
+ block->type == PAGECACHE_READ_UNKNOWN_PAGE);
+ if (type != PAGECACHE_READ_UNKNOWN_PAGE ||
+ block->type == PAGECACHE_EMPTY_PAGE)
+ block->type= type;
+
+ if (make_lock_and_pin(pagecache, block, lock_to_read[lock].new_lock,
+ new_pin, FALSE))
+ {
+ /*
+ We failed to write lock the block, cache is unlocked,
+ we will try to get the block again.
+ */
+ if (reg_request)
+ unreg_request(pagecache, block, 1);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_PRINT("info", ("restarting..."));
+ goto restart;
+ }
+
+ status= block->status;
+ if (!buff)
+ {
+ buff= block->buffer;
+ /* possibly we will write here (resolved on unlock) */
+ if ((lock == PAGECACHE_LOCK_WRITE ||
+ lock == PAGECACHE_LOCK_LEFT_WRITELOCKED) &&
+ !(block->status & PCBLOCK_CHANGED))
+ {
+ block->status|= PCBLOCK_DIRECT_W;
+ DBUG_PRINT("info", ("Set PCBLOCK_DIRECT_W for block: 0x%lx",
+ (ulong) block));
+ }
+ }
+ else
+ {
+ if (!(status & PCBLOCK_ERROR))
+ {
+#if !defined(SERIALIZED_READ_FROM_CACHE)
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+#endif
+
+ DBUG_ASSERT((pagecache->block_size & 511) == 0);
+ /* Copy data from the cache buffer */
+ bmove512(buff, block->buffer, pagecache->block_size);
+
+#if !defined(SERIALIZED_READ_FROM_CACHE)
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+#endif
+ }
+ else
+ my_errno= block->error;
+ }
+
+ remove_reader(block);
+ if (lock_to_read[lock].need_lock_change)
+ {
+ if (make_lock_and_pin(pagecache, block,
+ lock_to_read[lock].unlock_lock,
+ unlock_pin, FALSE))
+ DBUG_ASSERT(0);
+ }
+ /*
+ Link the block into the LRU chain if it's the last submitted request
+ for the block and block will not be pinned.
+ See NOTE for pagecache_unlock about registering requests.
+ */
+ if (unlock_pin == PAGECACHE_PIN_LEFT_UNPINNED ||
+ unlock_pin == PAGECACHE_UNPIN)
+ unreg_request(pagecache, block, 1);
+ else
+ *page_link= block;
+
+ dec_counter_for_resize_op(pagecache);
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+
+ if (status & PCBLOCK_ERROR)
+ {
+ DBUG_ASSERT(my_errno != 0);
+ DBUG_PRINT("error", ("Got error %d when doing page read", my_errno));
+ DBUG_RETURN((uchar *) 0);
+ }
+
+ DBUG_RETURN(buff);
+ }
+
+no_key_cache: /* Key cache is not used */
+
+ /* We can't use mutex here as the key cache may not be initialized */
+ pagecache->global_cache_r_requests++;
+ pagecache->global_cache_read++;
+ if (pagecache_fread(pagecache, file, (uchar*) buff, pageno,
+ pagecache->readwrite_flags))
+ error= 1;
+ DBUG_RETURN(error ? (uchar*) 0 : buff);
+}
+
+
+/*
+ @brief Delete page from the buffer (common part for link and file/page)
+
+ @param pagecache pointer to a page cache data structure
+ @param block direct link to page (returned by read or write)
+ @param page_link hash link of the block
+ @param flush flush page if it is dirty
+
+ @retval 0 deleted or was not present at all
+ @retval 1 error
+
+*/
+
+static my_bool pagecache_delete_internal(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ PAGECACHE_HASH_LINK *page_link,
+ my_bool flush)
+{
+ my_bool error= 0;
+ if (block->status & PCBLOCK_CHANGED)
+ {
+ if (flush)
+ {
+ /* The block contains a dirty page - push it out of the cache */
+
+ KEYCACHE_DBUG_PRINT("find_block", ("block is dirty"));
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ /*
+ The call is thread safe because only the current
+ thread might change the block->hash_link value
+ */
+ DBUG_ASSERT(block->pins == 1);
+ error= pagecache_fwrite(pagecache,
+ &block->hash_link->file,
+ block->buffer,
+ block->hash_link->pageno,
+ block->type,
+ pagecache->readwrite_flags);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ pagecache->global_cache_write++;
+
+ if (error)
+ {
+ block->status|= PCBLOCK_ERROR;
+ block->error= (int16) my_errno;
+ my_debug_put_break_here();
+ goto err;
+ }
+ }
+ pagecache->blocks_changed--;
+ pagecache->global_blocks_changed--;
+ /*
+ free_block() will change the status and rec_lsn of the block so no
+ need to change them here.
+ */
+ }
+ /* Cache is locked, so we can relese page before freeing it */
+ if (make_lock_and_pin(pagecache, block,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, FALSE))
+ DBUG_ASSERT(0);
+ DBUG_ASSERT(block->hash_link->requests > 0);
+ page_link->requests--;
+ /* See NOTE for pagecache_unlock about registering requests. */
+ free_block(pagecache, block);
+
+err:
+ dec_counter_for_resize_op(pagecache);
+ return error;
+}
+
+
+/*
+ @brief Delete page from the buffer by link
+
+ @param pagecache pointer to a page cache data structure
+ @param link direct link to page (returned by read or write)
+ @param lock lock change
+ @param flush flush page if it is dirty
+
+ @retval 0 deleted or was not present at all
+ @retval 1 error
+
+ @note lock can be only PAGECACHE_LOCK_LEFT_WRITELOCKED (page was
+ write locked before) or PAGECACHE_LOCK_WRITE (delete will write
+ lock page before delete)
+*/
+
+my_bool pagecache_delete_by_link(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ enum pagecache_page_lock lock,
+ my_bool flush)
+{
+ my_bool error= 0;
+ enum pagecache_page_pin pin= PAGECACHE_PIN_LEFT_PINNED;
+ DBUG_ENTER("pagecache_delete_by_link");
+ DBUG_PRINT("enter", ("fd: %d block 0x%lx %s %s",
+ block->hash_link->file.file,
+ (ulong) block,
+ page_cache_page_lock_str[lock],
+ page_cache_page_pin_str[pin]));
+ DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE ||
+ lock == PAGECACHE_LOCK_LEFT_WRITELOCKED);
+ DBUG_ASSERT(block->pins != 0); /* should be pinned */
+
+ if (pagecache->can_be_used)
+ {
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ if (!pagecache->can_be_used)
+ goto end;
+
+ /*
+ This block should be pinned (i.e. has not zero request counter) =>
+ Such block can't be chosen for eviction.
+ */
+ DBUG_ASSERT((block->status &
+ (PCBLOCK_IN_SWITCH | PCBLOCK_REASSIGNED)) == 0);
+ /*
+ make_lock_and_pin() can't fail here, because we are keeping pin on the
+ block and it can't be evicted (which is cause of lock fail and retry)
+ */
+ if (make_lock_and_pin(pagecache, block, lock, pin, FALSE))
+ DBUG_ASSERT(0);
+
+ /*
+ get_present_hash_link() side effect emulation before call
+ pagecache_delete_internal()
+ */
+ block->hash_link->requests++;
+
+ error= pagecache_delete_internal(pagecache, block, block->hash_link,
+ flush);
+end:
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ }
+
+ DBUG_RETURN(error);
+}
+
+
+/**
+ @brief Returns "hits" for promotion
+
+ @return "hits" for promotion
+*/
+
+uint pagecache_pagelevel(PAGECACHE_BLOCK_LINK *block)
+{
+ return block->hits_left;
+}
+
+/*
+ @brief Adds "hits" to the page
+
+ @param link direct link to page (returned by read or write)
+ @param level number of "hits" which we add to the page
+*/
+
+void pagecache_add_level_by_link(PAGECACHE_BLOCK_LINK *block,
+ uint level)
+{
+ DBUG_ASSERT(block->pins != 0); /* should be pinned */
+ /*
+ Operation is just for statistics so it is not really important
+ if it interfere with other hit increasing => we are doing it without
+ locking the pagecache.
+ */
+ block->hits_left+= level;
+}
+
+/*
+ @brief Delete page from the buffer
+
+ @param pagecache pointer to a page cache data structure
+ @param file handler for the file for the block of data to be read
+ @param pageno number of the block of data in the file
+ @param lock lock change
+ @param flush flush page if it is dirty
+
+ @retval 0 deleted or was not present at all
+ @retval 1 error
+
+ @note lock can be only PAGECACHE_LOCK_LEFT_WRITELOCKED (page was
+ write locked before) or PAGECACHE_LOCK_WRITE (delete will write
+ lock page before delete)
+*/
+static enum pagecache_page_pin lock_to_pin_one_phase[8]=
+{
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
+ PAGECACHE_PIN_LEFT_PINNED /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ*/,
+ PAGECACHE_PIN /*PAGECACHE_LOCK_WRITE*/,
+ PAGECACHE_PIN_LEFT_UNPINNED /*PAGECACHE_LOCK_READ_UNLOCK*/,
+ PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
+ PAGECACHE_UNPIN /*PAGECACHE_LOCK_WRITE_TO_READ*/
+};
+
+my_bool pagecache_delete(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ enum pagecache_page_lock lock,
+ my_bool flush)
+{
+ my_bool error= 0;
+ enum pagecache_page_pin pin= lock_to_pin_one_phase[lock];
+ DBUG_ENTER("pagecache_delete");
+ DBUG_PRINT("enter", ("fd: %u page: %lu %s %s",
+ (uint) file->file, (ulong) pageno,
+ page_cache_page_lock_str[lock],
+ page_cache_page_pin_str[pin]));
+ DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE ||
+ lock == PAGECACHE_LOCK_LEFT_WRITELOCKED);
+ DBUG_ASSERT(pin == PAGECACHE_PIN ||
+ pin == PAGECACHE_PIN_LEFT_PINNED);
+restart:
+
+ DBUG_ASSERT(pageno < ((ULL(1)) << 40));
+ if (pagecache->can_be_used)
+ {
+ /* Key cache is used */
+ reg1 PAGECACHE_BLOCK_LINK *block;
+ PAGECACHE_HASH_LINK **unused_start, *page_link;
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ if (!pagecache->can_be_used)
+ goto end;
+
+ inc_counter_for_resize_op(pagecache);
+ page_link= get_present_hash_link(pagecache, file, pageno, &unused_start);
+ if (!page_link)
+ {
+ DBUG_PRINT("info", ("There is no such page in the cache"));
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_RETURN(0);
+ }
+ block= page_link->block;
+ if (block->status & (PCBLOCK_REASSIGNED | PCBLOCK_IN_SWITCH))
+ {
+ DBUG_PRINT("info", ("Block 0x%0lx already is %s",
+ (ulong) block,
+ ((block->status & PCBLOCK_REASSIGNED) ?
+ "reassigned" : "in switch")));
+ PCBLOCK_INFO(block);
+ page_link->requests--;
+ goto end;
+ }
+ /* See NOTE for pagecache_unlock about registering requests. */
+ if (pin == PAGECACHE_PIN)
+ reg_requests(pagecache, block, 1);
+ DBUG_ASSERT(block != 0);
+ if (make_lock_and_pin(pagecache, block, lock, pin, FALSE))
+ {
+ /*
+ We failed to writelock the block, cache is unlocked, and last write
+ lock is released, we will try to get the block again.
+ */
+ if (pin == PAGECACHE_PIN)
+ unreg_request(pagecache, block, 1);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_PRINT("info", ("restarting..."));
+ goto restart;
+ }
+
+ /* we can't delete with opened direct link for write */
+ DBUG_ASSERT((block->status & PCBLOCK_DIRECT_W) == 0);
+
+ error= pagecache_delete_internal(pagecache, block, page_link, flush);
+end:
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ }
+
+ DBUG_RETURN(error);
+}
+
+
+my_bool pagecache_delete_pages(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ uint page_count,
+ enum pagecache_page_lock lock,
+ my_bool flush)
+{
+ pgcache_page_no_t page_end;
+ DBUG_ENTER("pagecache_delete_pages");
+ DBUG_ASSERT(page_count > 0);
+
+ page_end= pageno + page_count;
+ do
+ {
+ if (pagecache_delete(pagecache, file, pageno,
+ lock, flush))
+ DBUG_RETURN(1);
+ } while (++pageno != page_end);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Writes a buffer into a cached file.
+
+ @param pagecache pointer to a page cache data structure
+ @param file handler for the file to write data to
+ @param pageno number of the block of data in the file
+ @param level determines the weight of the data
+ @param buff buffer with the data
+ @param type type of the page
+ @param lock lock change
+ @param pin pin page
+ @param write_mode how to write page
+ @param link link to the page if we pin it
+ @param first_REDO_LSN_for_page the lsn to set rec_lsn
+ @param offset offset in the page
+ @param size size of data
+ @param validator read page validator
+ @param validator_data the validator data
+
+ @retval 0 if a success.
+ @retval 1 Error.
+*/
+
+static struct rw_lock_change write_lock_change_table[]=
+{
+ {1,
+ PAGECACHE_LOCK_WRITE,
+ PAGECACHE_LOCK_WRITE_UNLOCK} /*PAGECACHE_LOCK_LEFT_UNLOCKED*/,
+ {0, /*unsupported (we can't write having the block read locked) */
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_LOCK_LEFT_UNLOCKED} /*PAGECACHE_LOCK_LEFT_READLOCKED*/,
+ {0, PAGECACHE_LOCK_LEFT_WRITELOCKED, 0} /*PAGECACHE_LOCK_LEFT_WRITELOCKED*/,
+ {1,
+ PAGECACHE_LOCK_WRITE,
+ PAGECACHE_LOCK_WRITE_TO_READ} /*PAGECACHE_LOCK_READ*/,
+ {0, PAGECACHE_LOCK_WRITE, 0} /*PAGECACHE_LOCK_WRITE*/,
+ {0, /*unsupported (we can't write having the block read locked) */
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_LOCK_LEFT_UNLOCKED} /*PAGECACHE_LOCK_READ_UNLOCK*/,
+ {1,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ PAGECACHE_LOCK_WRITE_UNLOCK } /*PAGECACHE_LOCK_WRITE_UNLOCK*/,
+ {1,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ PAGECACHE_LOCK_WRITE_TO_READ} /*PAGECACHE_LOCK_WRITE_TO_READ*/
+};
+
+
+static struct rw_pin_change write_pin_change_table[]=
+{
+ {PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_PIN_LEFT_PINNED} /*PAGECACHE_PIN_LEFT_PINNED*/,
+ {PAGECACHE_PIN,
+ PAGECACHE_UNPIN} /*PAGECACHE_PIN_LEFT_UNPINNED*/,
+ {PAGECACHE_PIN,
+ PAGECACHE_PIN_LEFT_PINNED} /*PAGECACHE_PIN*/,
+ {PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_UNPIN} /*PAGECACHE_UNPIN*/
+};
+
+
+/**
+ @note 'buff', if not NULL, must be long-aligned.
+*/
+
+my_bool pagecache_write_part(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ uint level,
+ uchar *buff,
+ enum pagecache_page_type type,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin,
+ enum pagecache_write_mode write_mode,
+ PAGECACHE_BLOCK_LINK **page_link,
+ LSN first_REDO_LSN_for_page,
+ uint offset, uint size)
+{
+ PAGECACHE_BLOCK_LINK *block= NULL;
+ PAGECACHE_BLOCK_LINK *fake_link;
+ my_bool error= 0;
+ int need_lock_change= write_lock_change_table[lock].need_lock_change;
+ my_bool reg_request;
+#ifndef DBUG_OFF
+ char llbuf[22];
+ DBUG_ENTER("pagecache_write_part");
+ DBUG_PRINT("enter", ("fd: %u page: %s level: %u type: %s lock: %s "
+ "pin: %s mode: %s offset: %u size %u",
+ (uint) file->file, ullstr(pageno, llbuf), level,
+ page_cache_page_type_str[type],
+ page_cache_page_lock_str[lock],
+ page_cache_page_pin_str[pin],
+ page_cache_page_write_mode_str[write_mode],
+ offset, size));
+ DBUG_ASSERT(type != PAGECACHE_READ_UNKNOWN_PAGE);
+ DBUG_ASSERT(lock != PAGECACHE_LOCK_LEFT_READLOCKED);
+ DBUG_ASSERT(lock != PAGECACHE_LOCK_READ_UNLOCK);
+ DBUG_ASSERT(offset + size <= pagecache->block_size);
+ DBUG_ASSERT(pageno < ((ULL(1)) << 40));
+#endif
+
+ if (!page_link)
+ page_link= &fake_link;
+ *page_link= 0;
+
+restart:
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("check_pagecache",
+ test_key_cache(pagecache, "start of key_cache_write", 1););
+#endif
+
+ if (pagecache->can_be_used)
+ {
+ /* Key cache is used */
+ int page_st;
+ my_bool need_page_ready_signal= FALSE;
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ if (!pagecache->can_be_used)
+ {
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ goto no_key_cache;
+ }
+
+ inc_counter_for_resize_op(pagecache);
+ pagecache->global_cache_w_requests++;
+ /* See NOTE for pagecache_unlock about registering requests. */
+ reg_request= ((pin == PAGECACHE_PIN_LEFT_UNPINNED) ||
+ (pin == PAGECACHE_PIN));
+ block= find_block(pagecache, file, pageno, level,
+ TRUE,
+ reg_request, &page_st);
+ if (!block)
+ {
+ DBUG_ASSERT(write_mode != PAGECACHE_WRITE_DONE);
+ /* It happens only for requests submitted during resize operation */
+ dec_counter_for_resize_op(pagecache);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ /* Write to the disk key cache is in resize at the moment*/
+ goto no_key_cache;
+ }
+ DBUG_PRINT("info", ("page status: %d", page_st));
+ if (!(block->status & PCBLOCK_ERROR) &&
+ ((page_st == PAGE_TO_BE_READ &&
+ (offset || size < pagecache->block_size)) ||
+ (page_st == PAGE_WAIT_TO_BE_READ)))
+ {
+ /* The requested page is to be read into the block buffer */
+ read_block(pagecache, block,
+ (my_bool)(page_st == PAGE_TO_BE_READ));
+ DBUG_PRINT("info", ("read is done"));
+ }
+ else if (page_st == PAGE_TO_BE_READ)
+ {
+ need_page_ready_signal= TRUE;
+ }
+
+ DBUG_ASSERT(block->type == PAGECACHE_EMPTY_PAGE ||
+ block->type == PAGECACHE_READ_UNKNOWN_PAGE ||
+ block->type == type ||
+ /* this is for when going to non-trans to trans */
+ (block->type == PAGECACHE_PLAIN_PAGE &&
+ type == PAGECACHE_LSN_PAGE));
+ block->type= type;
+ /* we write to the page so it has no sense to keep the flag */
+ block->status&= ~PCBLOCK_DIRECT_W;
+ DBUG_PRINT("info", ("Drop PCBLOCK_DIRECT_W for block: 0x%lx",
+ (ulong) block));
+
+ if (make_lock_and_pin(pagecache, block,
+ write_lock_change_table[lock].new_lock,
+ (need_lock_change ?
+ write_pin_change_table[pin].new_pin :
+ pin), FALSE))
+ {
+ /*
+ We failed to writelock the block, cache is unlocked, and last write
+ lock is released, we will try to get the block again.
+ */
+ if (reg_request)
+ unreg_request(pagecache, block, 1);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_PRINT("info", ("restarting..."));
+ goto restart;
+ }
+
+ if (write_mode == PAGECACHE_WRITE_DONE)
+ {
+ if (block->status & PCBLOCK_ERROR)
+ {
+ my_debug_put_break_here();
+ DBUG_PRINT("warning", ("Writing on page with error"));
+ }
+ else
+ {
+ /* Copy data from buff */
+ if (!(size & 511))
+ bmove512(block->buffer + offset, buff, size);
+ else
+ memcpy(block->buffer + offset, buff, size);
+ block->status= PCBLOCK_READ;
+ /*
+ The read_callback can change the page content (removing page
+ protection) so it have to be called
+ */
+ DBUG_PRINT("info", ("read_callback: 0x%lx data: 0x%lx",
+ (ulong) block->hash_link->file.read_callback,
+ (ulong) block->hash_link->file.callback_data));
+ if ((*block->hash_link->file.read_callback)(block->buffer,
+ block->hash_link->pageno,
+ block->hash_link->
+ file.callback_data))
+ {
+ DBUG_PRINT("error", ("read callback problem"));
+ block->status|= PCBLOCK_ERROR;
+ block->error= (int16) my_errno;
+ my_debug_put_break_here();
+ }
+ KEYCACHE_DBUG_PRINT("key_cache_insert",
+ ("Page injection"));
+#ifdef THREAD
+ /* Signal that all pending requests for this now can be processed. */
+ if (block->wqueue[COND_FOR_REQUESTED].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_REQUESTED]);
+#endif
+ }
+ }
+ else
+ {
+ if (! (block->status & PCBLOCK_CHANGED))
+ link_to_changed_list(pagecache, block);
+
+ if (!(size & 511))
+ bmove512(block->buffer + offset, buff, size);
+ else
+ memcpy(block->buffer + offset, buff, size);
+ block->status|= PCBLOCK_READ;
+ /* Page is correct again if we made a full write in it */
+ if (size == pagecache->block_size)
+ block->status&= ~PCBLOCK_ERROR;
+ }
+
+#ifdef THREAD
+ if (need_page_ready_signal &&
+ block->wqueue[COND_FOR_REQUESTED].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_REQUESTED]);
+#endif
+
+ if (first_REDO_LSN_for_page)
+ {
+ /* single write action of the last write action */
+ DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE_UNLOCK ||
+ lock == PAGECACHE_LOCK_LEFT_UNLOCKED);
+ DBUG_ASSERT(pin == PAGECACHE_UNPIN ||
+ pin == PAGECACHE_PIN_LEFT_UNPINNED);
+ pagecache_set_block_rec_lsn(block, first_REDO_LSN_for_page);
+ }
+
+ if (need_lock_change)
+ {
+ /*
+ We don't set rec_lsn of the block; this is ok as for the
+ Maria-block-record's pages, we always keep pages pinned here.
+ */
+ if (make_lock_and_pin(pagecache, block,
+ write_lock_change_table[lock].unlock_lock,
+ write_pin_change_table[pin].unlock_pin, FALSE))
+ DBUG_ASSERT(0);
+ }
+
+ /* Unregister the request */
+ DBUG_ASSERT(block->hash_link->requests > 0);
+ block->hash_link->requests--;
+ /* See NOTE for pagecache_unlock about registering requests. */
+ if (pin == PAGECACHE_PIN_LEFT_UNPINNED || pin == PAGECACHE_UNPIN)
+ unreg_request(pagecache, block, 1);
+ else
+ *page_link= block;
+
+ if (block->status & PCBLOCK_ERROR)
+ {
+ error= 1;
+ my_debug_put_break_here();
+ }
+
+ dec_counter_for_resize_op(pagecache);
+
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+
+ goto end;
+ }
+
+no_key_cache:
+ /*
+ We can't by pass the normal page cache operations because need
+ whole page for calling callbacks & so on.
+ This branch should not be used for now (but it is fixed as it
+ should be just to avoid confusing)
+ */
+ DBUG_ASSERT(0);
+ /* Key cache is not used */
+ if (write_mode == PAGECACHE_WRITE_DELAY)
+ {
+ /* We can't use mutex here as the key cache may not be initialized */
+ pagecache->global_cache_w_requests++;
+ pagecache->global_cache_write++;
+ if (offset != 0 || size != pagecache->block_size)
+ {
+ uchar *page_buffer= (uchar *) alloca(pagecache->block_size);
+
+ pagecache->global_cache_read++;
+ if ((error= (pagecache_fread(pagecache, file,
+ page_buffer,
+ pageno,
+ pagecache->readwrite_flags) != 0)))
+ goto end;
+ if ((file->read_callback)(page_buffer, pageno, file->callback_data))
+ {
+ DBUG_PRINT("error", ("read callback problem"));
+ error= 1;
+ goto end;
+ }
+ memcpy((char *)page_buffer + offset, buff, size);
+ buff= page_buffer;
+ }
+ if (pagecache_fwrite(pagecache, file, (uchar*) buff, pageno, type,
+ pagecache->readwrite_flags))
+ error= 1;
+ }
+
+end:
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",
+ test_key_cache(pagecache, "end of key_cache_write", 1););
+#endif
+ if (block)
+ PCBLOCK_INFO(block);
+ else
+ DBUG_PRINT("info", ("No block"));
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Free block: remove reference to it from hash table,
+ remove it from the chain file of dirty/clean blocks
+ and add it to the free list.
+*/
+
+static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
+{
+ KEYCACHE_THREAD_TRACE("free block");
+ KEYCACHE_DBUG_PRINT("free_block",
+ ("block: %u hash_link 0x%lx",
+ PCBLOCK_NUMBER(pagecache, block),
+ (long) block->hash_link));
+ if (block->hash_link)
+ {
+ /*
+ While waiting for readers to finish, new readers might request the
+ block. But since we set block->status|= PCBLOCK_REASSIGNED, they
+ will wait on block->wqueue[COND_FOR_SAVED]. They must be signalled
+ later.
+ */
+ block->status|= PCBLOCK_REASSIGNED;
+ wait_for_readers(pagecache, block);
+ unlink_hash(pagecache, block->hash_link);
+ }
+
+ unlink_changed(block);
+ DBUG_ASSERT(block->wlocks == 0);
+ DBUG_ASSERT(block->rlocks == 0);
+ DBUG_ASSERT(block->rlocks_queue == 0);
+ DBUG_ASSERT(block->pins == 0);
+ block->status= 0;
+#ifndef DBUG_OFF
+ block->type= PAGECACHE_EMPTY_PAGE;
+#endif
+ block->rec_lsn= LSN_MAX;
+ KEYCACHE_THREAD_TRACE("free block");
+ KEYCACHE_DBUG_PRINT("free_block",
+ ("block is freed"));
+ unreg_request(pagecache, block, 0);
+ block->hash_link= NULL;
+
+ /* Remove the free block from the LRU ring. */
+ unlink_block(pagecache, block);
+ if (block->temperature == PCBLOCK_WARM)
+ pagecache->warm_blocks--;
+ block->temperature= PCBLOCK_COLD;
+ /* Insert the free block in the free list. */
+ block->next_used= pagecache->free_block_list;
+ pagecache->free_block_list= block;
+ /* Keep track of the number of currently unused blocks. */
+ pagecache->blocks_unused++;
+
+#ifdef THREAD
+ /* All pending requests for this page must be resubmitted. */
+ if (block->wqueue[COND_FOR_SAVED].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
+#endif
+}
+
+
+static int cmp_sec_link(PAGECACHE_BLOCK_LINK **a, PAGECACHE_BLOCK_LINK **b)
+{
+ return (((*a)->hash_link->pageno < (*b)->hash_link->pageno) ? -1 :
+ ((*a)->hash_link->pageno > (*b)->hash_link->pageno) ? 1 : 0);
+}
+
+
+/**
+ @brief Flush a portion of changed blocks to disk, free used blocks
+ if requested
+
+ @param pagecache This page cache reference.
+ @param file File which should be flushed
+ @param cache Beginning of array of the block.
+ @param end Reference to the block after last in the array.
+ @param flush_type Type of the flush.
+ @param first_errno Where to store first errno of the flush.
+
+
+ @return Operation status
+ @retval PCFLUSH_OK OK
+ @retval PCFLUSH_ERROR There was errors during the flush process.
+ @retval PCFLUSH_PINNED Pinned blocks was met and skipped.
+ @retval PCFLUSH_PINNED_AND_ERROR PCFLUSH_ERROR and PCFLUSH_PINNED.
+*/
+
+static int flush_cached_blocks(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ PAGECACHE_BLOCK_LINK **cache,
+ PAGECACHE_BLOCK_LINK **end,
+ enum flush_type type,
+ int *first_errno)
+{
+ int rc= PCFLUSH_OK;
+ my_bool error;
+ uint count= (uint) (end-cache);
+ DBUG_ENTER("flush_cached_blocks");
+ *first_errno= 0;
+
+ /* Don't lock the cache during the flush */
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ /*
+ As all blocks referred in 'cache' are marked by PCBLOCK_IN_FLUSH
+ we are guaranteed that no thread will change them
+ */
+ qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
+
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ for (; cache != end; cache++)
+ {
+ PAGECACHE_BLOCK_LINK *block= *cache;
+
+ if (block->pins)
+ {
+ KEYCACHE_DBUG_PRINT("flush_cached_blocks",
+ ("block: %u (0x%lx) pinned",
+ PCBLOCK_NUMBER(pagecache, block), (ulong)block));
+ DBUG_PRINT("info", ("block: %u (0x%lx) pinned",
+ PCBLOCK_NUMBER(pagecache, block), (ulong)block));
+ PCBLOCK_INFO(block);
+ /* undo the mark put by flush_pagecache_blocks_int(): */
+ block->status&= ~PCBLOCK_IN_FLUSH;
+ rc|= PCFLUSH_PINNED;
+ DBUG_PRINT("warning", ("Page pinned"));
+ unreg_request(pagecache, block, 1);
+ if (!*first_errno)
+ *first_errno= HA_ERR_INTERNAL_ERROR;
+ continue;
+ }
+ /* if the block is not pinned then it is not write locked */
+ DBUG_ASSERT(block->wlocks == 0);
+ DBUG_ASSERT(block->pins == 0);
+ if (make_lock_and_pin(pagecache, block,
+ PAGECACHE_LOCK_WRITE, PAGECACHE_PIN, FALSE))
+ DBUG_ASSERT(0);
+ DBUG_ASSERT(block->pins == 1);
+
+ KEYCACHE_DBUG_PRINT("flush_cached_blocks",
+ ("block: %u (0x%lx) to be flushed",
+ PCBLOCK_NUMBER(pagecache, block), (ulong)block));
+ DBUG_PRINT("info", ("block: %u (0x%lx) to be flushed",
+ PCBLOCK_NUMBER(pagecache, block), (ulong)block));
+ PCBLOCK_INFO(block);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_PRINT("info", ("block: %u (0x%lx) pins: %u",
+ PCBLOCK_NUMBER(pagecache, block), (ulong)block,
+ block->pins));
+ DBUG_ASSERT(block->pins == 1);
+ /**
+ @todo IO If page is contiguous with next page to flush, group flushes
+ in one single my_pwrite().
+ */
+ /**
+ It is important to use block->hash_link->file below and not 'file', as
+ the first one is right and the second may have different out-of-date
+ content (see StaleFilePointersInFlush in ma_checkpoint.c).
+ @todo change argument of functions to be File.
+ */
+ error= pagecache_fwrite(pagecache, &block->hash_link->file,
+ block->buffer,
+ block->hash_link->pageno,
+ block->type,
+ pagecache->readwrite_flags);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+
+ if (make_lock_and_pin(pagecache, block,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, FALSE))
+ DBUG_ASSERT(0);
+
+ pagecache->global_cache_write++;
+ if (error)
+ {
+ block->status|= PCBLOCK_ERROR;
+ block->error= (int16) my_errno;
+ my_debug_put_break_here();
+ if (!*first_errno)
+ *first_errno= my_errno ? my_errno : -1;
+ rc|= PCFLUSH_ERROR;
+ }
+#ifdef THREAD
+ /*
+ Let to proceed for possible waiting requests to write to the block page.
+ It might happen only during an operation to resize the key cache.
+ */
+ if (block->wqueue[COND_FOR_SAVED].last_thread)
+ wqueue_release_queue(&block->wqueue[COND_FOR_SAVED]);
+#endif
+ /* type will never be FLUSH_IGNORE_CHANGED here */
+ if (! (type == FLUSH_KEEP || type == FLUSH_KEEP_LAZY ||
+ type == FLUSH_FORCE_WRITE))
+ {
+ pagecache->blocks_changed--;
+ pagecache->global_blocks_changed--;
+ free_block(pagecache, block);
+ }
+ else
+ {
+ block->status&= ~PCBLOCK_IN_FLUSH;
+ link_to_file_list(pagecache, block, file, 1);
+ unreg_request(pagecache, block, 1);
+ }
+ }
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief flush all blocks for a file to disk but don't do any mutex locks
+
+ @param pagecache pointer to a pagecache data structure
+ @param file handler for the file to flush to
+ @param flush_type type of the flush
+ @param filter optional function which tells what blocks to flush;
+ can be non-NULL only if FLUSH_KEEP, FLUSH_KEEP_LAZY
+ or FLUSH_FORCE_WRITE.
+ @param filter_arg an argument to pass to 'filter'. Information about
+ the block will be passed too.
+
+ @note
+ Flushes all blocks having the same OS file descriptor as 'file->file', so
+ can flush blocks having '*block->hash_link->file' != '*file'.
+
+ @note
+ This function doesn't do any mutex locks because it needs to be called
+ both from flush_pagecache_blocks and flush_all_key_blocks (the later one
+ does the mutex lock in the resize_pagecache() function).
+
+ @note
+ This function can cause problems if two threads call it
+ concurrently on the same file (look for "PageCacheFlushConcurrencyBugs"
+ in ma_checkpoint.c); to avoid them, it has internal logic to serialize in
+ this situation.
+
+ @return Operation status
+ @retval PCFLUSH_OK OK
+ @retval PCFLUSH_ERROR There was errors during the flush process.
+ @retval PCFLUSH_PINNED Pinned blocks was met and skipped.
+ @retval PCFLUSH_PINNED_AND_ERROR PCFLUSH_ERROR and PCFLUSH_PINNED.
+*/
+
+static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ enum flush_type type,
+ PAGECACHE_FLUSH_FILTER filter,
+ void *filter_arg)
+{
+ PAGECACHE_BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
+ int last_errno= 0;
+ int rc= PCFLUSH_OK;
+ DBUG_ENTER("flush_pagecache_blocks_int");
+ DBUG_PRINT("enter",
+ ("fd: %d blocks_used: %lu blocks_changed: %lu type: %d",
+ file->file, pagecache->blocks_used, pagecache->blocks_changed,
+ type));
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("check_pagecache",
+ test_key_cache(pagecache,
+ "start of flush_pagecache_blocks", 0););
+#endif
+
+ cache= cache_buff;
+ if (pagecache->disk_blocks > 0 &&
+ (!my_disable_flush_pagecache_blocks ||
+ (type != FLUSH_KEEP && type != FLUSH_KEEP_LAZY)))
+ {
+ /*
+ Key cache exists. If my_disable_flush_pagecache_blocks is true it
+ disables the operation but only FLUSH_KEEP[_LAZY]: other flushes still
+ need to be allowed: FLUSH_RELEASE has to free blocks, and
+ FLUSH_FORCE_WRITE is to overrule my_disable_flush_pagecache_blocks.
+ */
+ int error= 0;
+ uint count= 0;
+ PAGECACHE_BLOCK_LINK **pos, **end;
+ PAGECACHE_BLOCK_LINK *first_in_switch= NULL;
+ PAGECACHE_BLOCK_LINK *block, *next;
+#if defined(PAGECACHE_DEBUG)
+ uint cnt= 0;
+#endif
+
+#ifdef THREAD
+ struct st_file_in_flush us_flusher, *other_flusher;
+ us_flusher.file= file->file;
+ us_flusher.flush_queue.last_thread= NULL;
+ us_flusher.first_in_switch= FALSE;
+ while ((other_flusher= (struct st_file_in_flush *)
+ hash_search(&pagecache->files_in_flush, (uchar *)&file->file,
+ sizeof(file->file))))
+ {
+ /*
+ File is in flush already: wait, unless FLUSH_KEEP_LAZY. "Flusher"
+ means "who can mark PCBLOCK_IN_FLUSH", i.e. caller of
+ flush_pagecache_blocks_int().
+ */
+ struct st_my_thread_var *thread;
+ if (type == FLUSH_KEEP_LAZY)
+ {
+ DBUG_PRINT("info",("FLUSH_KEEP_LAZY skips"));
+ DBUG_RETURN(0);
+ }
+ thread= my_thread_var;
+ wqueue_add_to_queue(&other_flusher->flush_queue, thread);
+ do
+ {
+ KEYCACHE_DBUG_PRINT("flush_pagecache_blocks_int: wait1",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while (thread->next);
+ }
+ /* we are the only flusher of this file now */
+ while (my_hash_insert(&pagecache->files_in_flush, (uchar *)&us_flusher))
+ {
+ /*
+ Out of memory, wait for flushers to empty the hash and retry; should
+ rarely happen. Other threads are flushing the file; when done, they
+ are going to remove themselves from the hash, and thus memory will
+ appear again. However, this memory may be stolen by yet another thread
+ (for a purpose unrelated to page cache), before we retry
+ hash_insert(). So the loop may run for long. Only if the thread was
+ killed do we abort the loop, returning 1 (error) which can cause the
+ table to be marked as corrupted (cf maria_chk_size(), maria_close())
+ and thus require a table check.
+ */
+ DBUG_ASSERT(0);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ if (my_thread_var->abort)
+ DBUG_RETURN(1); /* End if aborted by user */
+ sleep(10);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ }
+#endif
+
+ if (type != FLUSH_IGNORE_CHANGED)
+ {
+ /*
+ Count how many key blocks we have to cache to be able
+ to flush all dirty pages with minimum seek moves.
+ */
+ for (block= pagecache->changed_blocks[FILE_HASH(*file)] ;
+ block;
+ block= block->next_changed)
+ {
+ if (block->hash_link->file.file == file->file)
+ {
+ count++;
+ KEYCACHE_DBUG_ASSERT(count<= pagecache->blocks_used);
+ }
+ }
+ /* Allocate a new buffer only if its bigger than the one we have */
+ if (count > FLUSH_CACHE &&
+ !(cache=
+ (PAGECACHE_BLOCK_LINK**)
+ my_malloc(sizeof(PAGECACHE_BLOCK_LINK*)*count, MYF(0))))
+ {
+ cache= cache_buff;
+ count= FLUSH_CACHE;
+ }
+ }
+
+ /* Retrieve the blocks and write them to a buffer to be flushed */
+restart:
+ end= (pos= cache)+count;
+ for (block= pagecache->changed_blocks[FILE_HASH(*file)] ;
+ block;
+ block= next)
+ {
+#if defined(PAGECACHE_DEBUG)
+ cnt++;
+ KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used);
+#endif
+ next= block->next_changed;
+ if (block->hash_link->file.file != file->file)
+ continue;
+ if (filter != NULL)
+ {
+ int filter_res= (*filter)(block->type, block->hash_link->pageno,
+ block->rec_lsn, filter_arg);
+ DBUG_PRINT("info",("filter returned %d", filter_res));
+ if (filter_res == FLUSH_FILTER_SKIP_TRY_NEXT)
+ continue;
+ if (filter_res == FLUSH_FILTER_SKIP_ALL)
+ break;
+ DBUG_ASSERT(filter_res == FLUSH_FILTER_OK);
+ }
+ {
+ /*
+ Mark the block with BLOCK_IN_FLUSH in order not to let
+ other threads to use it for new pages and interfere with
+ our sequence of flushing dirty file pages
+ */
+ block->status|= PCBLOCK_IN_FLUSH;
+
+ if (! (block->status & PCBLOCK_IN_SWITCH))
+ {
+ /*
+ We care only for the blocks for which flushing was not
+ initiated by other threads as a result of page swapping
+ */
+ reg_requests(pagecache, block, 1);
+ if (type != FLUSH_IGNORE_CHANGED)
+ {
+ /* It's not a temporary file */
+ if (pos == end)
+ {
+ /*
+ This happens only if there is not enough
+ memory for the big block
+ */
+ if ((rc|= flush_cached_blocks(pagecache, file, cache,
+ end, type, &error)) &
+ (PCFLUSH_ERROR | PCFLUSH_PINNED))
+ last_errno=error;
+ DBUG_PRINT("info", ("restarting..."));
+ /*
+ Restart the scan as some other thread might have changed
+ the changed blocks chain: the blocks that were in switch
+ state before the flush started have to be excluded
+ */
+ goto restart;
+ }
+ *pos++= block;
+ }
+ else
+ {
+ /* It's a temporary file */
+ pagecache->blocks_changed--;
+ pagecache->global_blocks_changed--;
+ free_block(pagecache, block);
+ }
+ }
+ else if (type != FLUSH_KEEP_LAZY)
+ {
+ /*
+ Link the block into a list of blocks 'in switch', and then we will
+ wait for this list to be empty, which means they have been flushed
+ */
+ unlink_changed(block);
+ link_changed(block, &first_in_switch);
+ us_flusher.first_in_switch= TRUE;
+ }
+ }
+ }
+ if (pos != cache)
+ {
+ if ((rc|= flush_cached_blocks(pagecache, file, cache, pos, type,
+ &error)) &
+ (PCFLUSH_ERROR | PCFLUSH_PINNED))
+ last_errno= error;
+ }
+ /* Wait until list of blocks in switch is empty */
+ while (first_in_switch)
+ {
+#if defined(PAGECACHE_DEBUG)
+ cnt= 0;
+#endif
+ block= first_in_switch;
+ {
+#ifdef THREAD
+ struct st_my_thread_var *thread= my_thread_var;
+ wqueue_add_to_queue(&block->wqueue[COND_FOR_SAVED], thread);
+ do
+ {
+ KEYCACHE_DBUG_PRINT("flush_pagecache_blocks_int: wait2",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while (thread->next);
+#else
+ KEYCACHE_DBUG_ASSERT(0);
+ /* No parallel requests in single-threaded case */
+#endif
+ }
+#if defined(PAGECACHE_DEBUG)
+ cnt++;
+ KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used);
+#endif
+ }
+ us_flusher.first_in_switch= FALSE;
+ /* The following happens very seldom */
+ if (! (type == FLUSH_KEEP || type == FLUSH_KEEP_LAZY ||
+ type == FLUSH_FORCE_WRITE))
+ {
+ /*
+ this code would free all blocks while filter maybe handled only a
+ few, that is not possible.
+ */
+ DBUG_ASSERT(filter == NULL);
+#if defined(PAGECACHE_DEBUG)
+ cnt=0;
+#endif
+ for (block= pagecache->file_blocks[FILE_HASH(*file)] ;
+ block;
+ block= next)
+ {
+#if defined(PAGECACHE_DEBUG)
+ cnt++;
+ KEYCACHE_DBUG_ASSERT(cnt <= pagecache->blocks_used);
+#endif
+ next= block->next_changed;
+ if (block->hash_link->file.file == file->file &&
+ (! (block->status & PCBLOCK_CHANGED)
+ || type == FLUSH_IGNORE_CHANGED))
+ {
+ reg_requests(pagecache, block, 1);
+ free_block(pagecache, block);
+ }
+ }
+ }
+#ifdef THREAD
+ /* wake up others waiting to flush this file */
+ hash_delete(&pagecache->files_in_flush, (uchar *)&us_flusher);
+ if (us_flusher.flush_queue.last_thread)
+ wqueue_release_queue(&us_flusher.flush_queue);
+#endif
+ }
+
+#ifndef DBUG_OFF
+ DBUG_EXECUTE("check_pagecache",
+ test_key_cache(pagecache, "end of flush_pagecache_blocks", 0););
+#endif
+ if (cache != cache_buff)
+ my_free((uchar*) cache, MYF(0));
+ if (rc != 0)
+ {
+ if (last_errno)
+ my_errno= last_errno; /* Return first error */
+ DBUG_PRINT("error", ("Got error: %d", my_errno));
+ }
+ DBUG_RETURN(rc);
+}
+
+
+/**
+ @brief flush all blocks for a file to disk
+
+ @param pagecache pointer to a pagecache data structure
+ @param file handler for the file to flush to
+ @param flush_type type of the flush
+ @param filter optional function which tells what blocks to flush;
+ can be non-NULL only if FLUSH_KEEP, FLUSH_KEEP_LAZY
+ or FLUSH_FORCE_WRITE.
+ @param filter_arg an argument to pass to 'filter'. Information about
+ the block will be passed too.
+
+ @return Operation status
+ @retval PCFLUSH_OK OK
+ @retval PCFLUSH_ERROR There was errors during the flush process.
+ @retval PCFLUSH_PINNED Pinned blocks was met and skipped.
+ @retval PCFLUSH_PINNED_AND_ERROR PCFLUSH_ERROR and PCFLUSH_PINNED.
+*/
+
+int flush_pagecache_blocks_with_filter(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ enum flush_type type,
+ PAGECACHE_FLUSH_FILTER filter,
+ void *filter_arg)
+{
+ int res;
+ DBUG_ENTER("flush_pagecache_blocks_with_filter");
+ DBUG_PRINT("enter", ("pagecache: 0x%lx", (long) pagecache));
+
+ if (pagecache->disk_blocks <= 0)
+ DBUG_RETURN(0);
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+ inc_counter_for_resize_op(pagecache);
+ res= flush_pagecache_blocks_int(pagecache, file, type, filter, filter_arg);
+ dec_counter_for_resize_op(pagecache);
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Reset the counters of a key cache.
+
+ SYNOPSIS
+ reset_pagecache_counters()
+ name the name of a key cache
+ pagecache pointer to the pagecache to be reset
+
+ DESCRIPTION
+ This procedure is used to reset the counters of all currently used key
+ caches, both the default one and the named ones.
+
+ RETURN
+ 0 on success (always because it can't fail)
+*/
+
+int reset_pagecache_counters(const char *name __attribute__((unused)),
+ PAGECACHE *pagecache)
+{
+ DBUG_ENTER("reset_pagecache_counters");
+ if (!pagecache->inited)
+ {
+ DBUG_PRINT("info", ("Key cache %s not initialized.", name));
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("info", ("Resetting counters for key cache %s.", name));
+
+ pagecache->global_blocks_changed= 0; /* Key_blocks_not_flushed */
+ pagecache->global_cache_r_requests= 0; /* Key_read_requests */
+ pagecache->global_cache_read= 0; /* Key_reads */
+ pagecache->global_cache_w_requests= 0; /* Key_write_requests */
+ pagecache->global_cache_write= 0; /* Key_writes */
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Allocates a buffer and stores in it some info about all dirty pages
+
+ Does the allocation because the caller cannot know the size itself.
+ Memory freeing is to be done by the caller (if the "str" member of the
+ LEX_STRING is not NULL).
+ Ignores all pages of another type than PAGECACHE_LSN_PAGE, because they
+ are not interesting for a checkpoint record.
+ The caller has the intention of doing checkpoints.
+
+ @param pagecache pointer to the page cache
+ @param[out] str pointer to where the allocated buffer, and
+ its size, will be put
+ @param[out] min_rec_lsn pointer to where the minimum rec_lsn of all
+ relevant dirty pages will be put
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache,
+ LEX_STRING *str,
+ LSN *min_rec_lsn)
+{
+ my_bool error= 0;
+ ulong stored_list_size= 0;
+ uint file_hash;
+ char *ptr;
+ LSN minimum_rec_lsn= LSN_MAX;
+ DBUG_ENTER("pagecache_collect_changed_blocks_with_LSN");
+
+ DBUG_ASSERT(NULL == str->str);
+ /*
+ We lock the entire cache but will be quick, just reading/writing a few MBs
+ of memory at most.
+ */
+ pagecache_pthread_mutex_lock(&pagecache->cache_lock);
+#ifdef THREAD
+ for (;;)
+ {
+ struct st_file_in_flush *other_flusher;
+ for (file_hash= 0;
+ (other_flusher= (struct st_file_in_flush *)
+ hash_element(&pagecache->files_in_flush, file_hash)) != NULL &&
+ !other_flusher->first_in_switch;
+ file_hash++)
+ {}
+ if (other_flusher == NULL)
+ break;
+ /*
+ other_flusher.first_in_switch is true: some thread is flushing a file
+ and has removed dirty blocks from changed_blocks[] while they were still
+ dirty (they were being evicted (=>flushed) by yet another thread, which
+ may not have flushed the block yet so it may still be dirty).
+ If Checkpoint proceeds now, it will not see the page. If there is a
+ crash right after writing the checkpoint record, before the page is
+ flushed, at recovery the page will be wrongly ignored because it won't
+ be in the dirty pages list in the checkpoint record. So wait.
+ */
+ {
+ struct st_my_thread_var *thread= my_thread_var;
+ wqueue_add_to_queue(&other_flusher->flush_queue, thread);
+ do
+ {
+ KEYCACHE_DBUG_PRINT("pagecache_collect_changed_blocks_with_lsn: wait",
+ ("suspend thread %ld", thread->id));
+ pagecache_pthread_cond_wait(&thread->suspend,
+ &pagecache->cache_lock);
+ }
+ while (thread->next);
+ }
+ }
+#endif
+
+ /* Count how many dirty pages are interesting */
+ for (file_hash= 0; file_hash < PAGECACHE_CHANGED_BLOCKS_HASH; file_hash++)
+ {
+ PAGECACHE_BLOCK_LINK *block;
+ for (block= pagecache->changed_blocks[file_hash] ;
+ block;
+ block= block->next_changed)
+ {
+ /*
+ Q: is there something subtle with block->hash_link: can it be NULL?
+ does it have to be == hash_link->block... ?
+ */
+ DBUG_ASSERT(block->hash_link != NULL);
+ DBUG_ASSERT(block->status & PCBLOCK_CHANGED);
+ /*
+ Note that we don't store bitmap pages, or pages from non-transactional
+ (like temporary) tables. Don't checkpoint during Recovery which uses
+ PAGECACHE_PLAIN_PAGE.
+ */
+ if (block->type != PAGECACHE_LSN_PAGE)
+ continue; /* no need to store it */
+ stored_list_size++;
+ }
+ }
+
+ compile_time_assert(sizeof(pagecache->blocks) <= 8);
+ str->length= 8 + /* number of dirty pages */
+ (2 + /* table id */
+ 1 + /* data or index file */
+ 5 + /* pageno */
+ LSN_STORE_SIZE /* rec_lsn */
+ ) * stored_list_size;
+ if (NULL == (str->str= my_malloc(str->length, MYF(MY_WME))))
+ goto err;
+ ptr= str->str;
+ int8store(ptr, (ulonglong)stored_list_size);
+ ptr+= 8;
+ DBUG_PRINT("info", ("found %lu dirty pages", stored_list_size));
+ if (stored_list_size == 0)
+ goto end;
+ for (file_hash= 0; file_hash < PAGECACHE_CHANGED_BLOCKS_HASH; file_hash++)
+ {
+ PAGECACHE_BLOCK_LINK *block;
+ for (block= pagecache->changed_blocks[file_hash] ;
+ block;
+ block= block->next_changed)
+ {
+ uint16 table_id;
+ MARIA_SHARE *share;
+ if (block->type != PAGECACHE_LSN_PAGE)
+ continue; /* no need to store it in the checkpoint record */
+ share= (MARIA_SHARE *)(block->hash_link->file.callback_data);
+ table_id= share->id;
+ int2store(ptr, table_id);
+ ptr+= 2;
+ ptr[0]= (share->kfile.file == block->hash_link->file.file);
+ ptr++;
+ DBUG_ASSERT(block->hash_link->pageno < ((ULL(1)) << 40));
+ page_store(ptr, block->hash_link->pageno);
+ ptr+= PAGE_STORE_SIZE;
+ lsn_store(ptr, block->rec_lsn);
+ ptr+= LSN_STORE_SIZE;
+ if (block->rec_lsn != LSN_MAX)
+ {
+ DBUG_ASSERT(LSN_VALID(block->rec_lsn));
+ if (cmp_translog_addr(block->rec_lsn, minimum_rec_lsn) < 0)
+ minimum_rec_lsn= block->rec_lsn;
+ } /* otherwise, some trn->rec_lsn should hold the correct info */
+ }
+ }
+end:
+ pagecache_pthread_mutex_unlock(&pagecache->cache_lock);
+ *min_rec_lsn= minimum_rec_lsn;
+ DBUG_RETURN(error);
+
+err:
+ error= 1;
+ goto end;
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+ Verifies that a file has no dirty pages.
+*/
+
+void pagecache_file_no_dirty_page(PAGECACHE *pagecache, PAGECACHE_FILE *file)
+{
+ File fd= file->file;
+ PAGECACHE_BLOCK_LINK *block;
+ for (block= pagecache->changed_blocks[FILE_HASH(*file)];
+ block != NULL;
+ block= block->next_changed)
+ if (block->hash_link->file.file == fd)
+ {
+ DBUG_PRINT("info", ("pagecache_file_not_in error"));
+ PCBLOCK_INFO(block);
+ DBUG_ASSERT(0);
+ }
+}
+
+
+/*
+ Test if disk-cache is ok
+*/
+static void test_key_cache(PAGECACHE *pagecache __attribute__((unused)),
+ const char *where __attribute__((unused)),
+ my_bool lock __attribute__((unused)))
+{
+ /* TODO */
+}
+#endif
+
+uchar *pagecache_block_link_to_buffer(PAGECACHE_BLOCK_LINK *block)
+{
+ return block->buffer;
+}
+
+#if defined(PAGECACHE_TIMEOUT)
+
+#define KEYCACHE_DUMP_FILE "pagecache_dump.txt"
+#define MAX_QUEUE_LEN 100
+
+
+static void pagecache_dump(PAGECACHE *pagecache)
+{
+ FILE *pagecache_dump_file=fopen(KEYCACHE_DUMP_FILE, "w");
+ struct st_my_thread_var *last;
+ struct st_my_thread_var *thread;
+ PAGECACHE_BLOCK_LINK *block;
+ PAGECACHE_HASH_LINK *hash_link;
+ PAGECACHE_PAGE *page;
+ uint i;
+
+ fprintf(pagecache_dump_file, "thread:%u\n", thread->id);
+
+ i=0;
+ thread=last=waiting_for_hash_link.last_thread;
+ fprintf(pagecache_dump_file, "queue of threads waiting for hash link\n");
+ if (thread)
+ do
+ {
+ thread= thread->next;
+ page= (PAGECACHE_PAGE *) thread->opt_info;
+ fprintf(pagecache_dump_file,
+ "thread:%u, (file,pageno)=(%u,%lu)\n",
+ thread->id,(uint) page->file.file,(ulong) page->pageno);
+ if (++i == MAX_QUEUE_LEN)
+ break;
+ }
+ while (thread != last);
+
+ i=0;
+ thread=last=waiting_for_block.last_thread;
+ fprintf(pagecache_dump_file, "queue of threads waiting for block\n");
+ if (thread)
+ do
+ {
+ thread=thread->next;
+ hash_link= (PAGECACHE_HASH_LINK *) thread->opt_info;
+ fprintf(pagecache_dump_file,
+ "thread:%u hash_link:%u (file,pageno)=(%u,%lu)\n",
+ thread->id, (uint) PAGECACHE_HASH_LINK_NUMBER(pagecache, hash_link),
+ (uint) hash_link->file.file,(ulong) hash_link->pageno);
+ if (++i == MAX_QUEUE_LEN)
+ break;
+ }
+ while (thread != last);
+
+ for (i=0 ; i < pagecache->blocks_used ; i++)
+ {
+ int j;
+ block= &pagecache->block_root[i];
+ hash_link= block->hash_link;
+ fprintf(pagecache_dump_file,
+ "block:%u hash_link:%d status:%x #requests=%u waiting_for_readers:%d\n",
+ i, (int) (hash_link ?
+ PAGECACHE_HASH_LINK_NUMBER(pagecache, hash_link) :
+ -1),
+ block->status, block->requests, block->condvar ? 1 : 0);
+ for (j=0 ; j < COND_SIZE; j++)
+ {
+ PAGECACHE_WQUEUE *wqueue=&block->wqueue[j];
+ thread= last= wqueue->last_thread;
+ fprintf(pagecache_dump_file, "queue #%d\n", j);
+ if (thread)
+ {
+ do
+ {
+ thread=thread->next;
+ fprintf(pagecache_dump_file,
+ "thread:%u\n", thread->id);
+ if (++i == MAX_QUEUE_LEN)
+ break;
+ }
+ while (thread != last);
+ }
+ }
+ }
+ fprintf(pagecache_dump_file, "LRU chain:");
+ block= pagecache= used_last;
+ if (block)
+ {
+ do
+ {
+ block= block->next_used;
+ fprintf(pagecache_dump_file,
+ "block:%u, ", PCBLOCK_NUMBER(pagecache, block));
+ }
+ while (block != pagecache->used_last);
+ }
+ fprintf(pagecache_dump_file, "\n");
+
+ fclose(pagecache_dump_file);
+}
+
+#endif /* defined(PAGECACHE_TIMEOUT) */
+
+#if defined(PAGECACHE_TIMEOUT) && !defined(__WIN__)
+
+
+static int pagecache_pthread_cond_wait(pthread_cond_t *cond,
+ pthread_mutex_t *mutex)
+{
+ int rc;
+ struct timeval now; /* time when we started waiting */
+ struct timespec timeout; /* timeout value for the wait function */
+ struct timezone tz;
+#if defined(PAGECACHE_DEBUG)
+ int cnt=0;
+#endif
+
+ /* Get current time */
+ gettimeofday(&now, &tz);
+ /* Prepare timeout value */
+ timeout.tv_sec= now.tv_sec + PAGECACHE_TIMEOUT;
+ /*
+ timeval uses microseconds.
+ timespec uses nanoseconds.
+ 1 nanosecond = 1000 micro seconds
+ */
+ timeout.tv_nsec= now.tv_usec * 1000;
+ KEYCACHE_THREAD_TRACE_END("started waiting");
+#if defined(PAGECACHE_DEBUG)
+ cnt++;
+ if (cnt % 100 == 0)
+ fprintf(pagecache_debug_log, "waiting...\n");
+ fflush(pagecache_debug_log);
+#endif
+ rc= pthread_cond_timedwait(cond, mutex, &timeout);
+ KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
+ if (rc == ETIMEDOUT || rc == ETIME)
+ {
+#if defined(PAGECACHE_DEBUG)
+ fprintf(pagecache_debug_log,"aborted by pagecache timeout\n");
+ fclose(pagecache_debug_log);
+ abort();
+#endif
+ pagecache_dump();
+ }
+
+#if defined(PAGECACHE_DEBUG)
+ KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
+#else
+ assert(rc != ETIMEDOUT);
+#endif
+ return rc;
+}
+#else
+#if defined(PAGECACHE_DEBUG)
+static int pagecache_pthread_cond_wait(pthread_cond_t *cond,
+ pthread_mutex_t *mutex)
+{
+ int rc;
+ KEYCACHE_THREAD_TRACE_END("started waiting");
+ rc= pthread_cond_wait(cond, mutex);
+ KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
+ return rc;
+}
+#endif
+#endif /* defined(PAGECACHE_TIMEOUT) && !defined(__WIN__) */
+
+#if defined(PAGECACHE_DEBUG)
+static int ___pagecache_pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ int rc;
+ rc= pthread_mutex_lock(mutex);
+ KEYCACHE_THREAD_TRACE_BEGIN("");
+ return rc;
+}
+
+
+static void ___pagecache_pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ KEYCACHE_THREAD_TRACE_END("");
+ pthread_mutex_unlock(mutex);
+}
+
+
+static int ___pagecache_pthread_cond_signal(pthread_cond_t *cond)
+{
+ int rc;
+ KEYCACHE_THREAD_TRACE("signal");
+ rc= pthread_cond_signal(cond);
+ return rc;
+}
+
+
+#if defined(PAGECACHE_DEBUG_LOG)
+
+
+static void pagecache_debug_print(const char * fmt, ...)
+{
+ va_list args;
+ va_start(args,fmt);
+ if (pagecache_debug_log)
+ {
+ VOID(vfprintf(pagecache_debug_log, fmt, args));
+ VOID(fputc('\n',pagecache_debug_log));
+ }
+ va_end(args);
+}
+#endif /* defined(PAGECACHE_DEBUG_LOG) */
+
+#if defined(PAGECACHE_DEBUG_LOG)
+
+
+void pagecache_debug_log_close(void)
+{
+ if (pagecache_debug_log)
+ fclose(pagecache_debug_log);
+}
+#endif /* defined(PAGECACHE_DEBUG_LOG) */
+
+#endif /* defined(PAGECACHE_DEBUG) */
diff --git a/storage/maria/ma_pagecache.h b/storage/maria/ma_pagecache.h
new file mode 100644
index 00000000000..821728ef374
--- /dev/null
+++ b/storage/maria/ma_pagecache.h
@@ -0,0 +1,325 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Page cache variable structures */
+
+#ifndef _ma_pagecache_h
+#define _ma_pagecache_h
+C_MODE_START
+
+#include "ma_loghandler_lsn.h"
+#include <m_string.h>
+#include <hash.h>
+
+/* Type of the page */
+enum pagecache_page_type
+{
+ /*
+ Used only for control page type changing during debugging. This define
+ should only be using when using DBUG.
+ */
+ PAGECACHE_EMPTY_PAGE,
+ /* the page does not contain LSN */
+ PAGECACHE_PLAIN_PAGE,
+ /* the page contain LSN (maria tablespace page) */
+ PAGECACHE_LSN_PAGE,
+ /* Page type used when scanning file and we don't care about the type */
+ PAGECACHE_READ_UNKNOWN_PAGE
+};
+
+/*
+ This enum describe lock status changing. every type of page cache will
+ interpret WRITE/READ lock as it need.
+*/
+enum pagecache_page_lock
+{
+ PAGECACHE_LOCK_LEFT_UNLOCKED, /* free -> free */
+ PAGECACHE_LOCK_LEFT_READLOCKED, /* read -> read */
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, /* write -> write */
+ PAGECACHE_LOCK_READ, /* free -> read */
+ PAGECACHE_LOCK_WRITE, /* free -> write */
+ PAGECACHE_LOCK_READ_UNLOCK, /* read -> free */
+ PAGECACHE_LOCK_WRITE_UNLOCK, /* write -> free */
+ PAGECACHE_LOCK_WRITE_TO_READ /* write -> read */
+};
+/*
+ This enum describe pin status changing
+*/
+enum pagecache_page_pin
+{
+ PAGECACHE_PIN_LEFT_PINNED, /* pinned -> pinned */
+ PAGECACHE_PIN_LEFT_UNPINNED, /* unpinned -> unpinned */
+ PAGECACHE_PIN, /* unpinned -> pinned */
+ PAGECACHE_UNPIN /* pinned -> unpinned */
+};
+/* How to write the page */
+enum pagecache_write_mode
+{
+ /* do not write immediately, i.e. it will be dirty page */
+ PAGECACHE_WRITE_DELAY,
+ /* page already is in the file. (key cache insert analogue) */
+ PAGECACHE_WRITE_DONE
+};
+
+/* page number for maria */
+typedef ulonglong pgcache_page_no_t;
+
+/* file descriptor for Maria */
+typedef struct st_pagecache_file
+{
+ File file;
+ /** Cannot be NULL */
+ my_bool (*read_callback)(uchar *page, pgcache_page_no_t offset,
+ uchar *data);
+ /** Cannot be NULL */
+ my_bool (*write_callback)(uchar *page, pgcache_page_no_t offset,
+ uchar *data);
+ void (*write_fail)(uchar *data);
+ /** Cannot be NULL */
+ my_bool (*flush_log_callback)(uchar *page, pgcache_page_no_t offset,
+ uchar *data);
+ uchar *callback_data;
+} PAGECACHE_FILE;
+
+/* declare structures that is used by st_pagecache */
+
+struct st_pagecache_block_link;
+typedef struct st_pagecache_block_link PAGECACHE_BLOCK_LINK;
+struct st_pagecache_page;
+typedef struct st_pagecache_page PAGECACHE_PAGE;
+struct st_pagecache_hash_link;
+typedef struct st_pagecache_hash_link PAGECACHE_HASH_LINK;
+
+#include <wqueue.h>
+
+#define PAGECACHE_CHANGED_BLOCKS_HASH 128 /* must be power of 2 */
+#define PAGECACHE_PRIORITY_LOW 0
+#define PAGECACHE_PRIORITY_DEFAULT 3
+#define PAGECACHE_PRIORITY_HIGH 6
+
+/*
+ The page cache structure
+ It also contains read-only statistics parameters.
+*/
+
+typedef struct st_pagecache
+{
+ size_t mem_size; /* specified size of the cache memory */
+ ulong min_warm_blocks; /* min number of warm blocks; */
+ ulong age_threshold; /* age threshold for hot blocks */
+ ulonglong time; /* total number of block link operations */
+ ulong hash_entries; /* max number of entries in the hash table */
+ long hash_links; /* max number of hash links */
+ long hash_links_used; /* number of hash links taken from free links pool */
+ long disk_blocks; /* max number of blocks in the cache */
+ ulong blocks_used; /* maximum number of concurrently used blocks */
+ ulong blocks_unused; /* number of currently unused blocks */
+ ulong blocks_changed; /* number of currently dirty blocks */
+ ulong warm_blocks; /* number of blocks in warm sub-chain */
+ ulong cnt_for_resize_op; /* counter to block resize operation */
+ ulong blocks_available; /* number of blocks available in the LRU chain */
+ long blocks; /* max number of blocks in the cache */
+ uint32 block_size; /* size of the page buffer of a cache block */
+ PAGECACHE_HASH_LINK **hash_root;/* arr. of entries into hash table buckets */
+ PAGECACHE_HASH_LINK *hash_link_root;/* memory for hash table links */
+ PAGECACHE_HASH_LINK *free_hash_list;/* list of free hash links */
+ PAGECACHE_BLOCK_LINK *free_block_list;/* list of free blocks */
+ PAGECACHE_BLOCK_LINK *block_root;/* memory for block links */
+ uchar HUGE_PTR *block_mem; /* memory for block buffers */
+ PAGECACHE_BLOCK_LINK *used_last;/* ptr to the last block of the LRU chain */
+ PAGECACHE_BLOCK_LINK *used_ins;/* ptr to the insertion block in LRU chain */
+ pthread_mutex_t cache_lock; /* to lock access to the cache structure */
+ WQUEUE resize_queue; /* threads waiting during resize operation */
+ WQUEUE waiting_for_hash_link;/* waiting for a free hash link */
+ WQUEUE waiting_for_block; /* requests waiting for a free block */
+ /* hash for dirty file bl.*/
+ PAGECACHE_BLOCK_LINK *changed_blocks[PAGECACHE_CHANGED_BLOCKS_HASH];
+ /* hash for other file bl.*/
+ PAGECACHE_BLOCK_LINK *file_blocks[PAGECACHE_CHANGED_BLOCKS_HASH];
+
+ /*
+ The following variables are and variables used to hold parameters for
+ initializing the key cache.
+ */
+
+ ulonglong param_buff_size; /* size the memory allocated for the cache */
+ ulong param_block_size; /* size of the blocks in the key cache */
+ ulong param_division_limit; /* min. percentage of warm blocks */
+ ulong param_age_threshold; /* determines when hot block is downgraded */
+
+ /* Statistics variables. These are reset in reset_pagecache_counters(). */
+ ulong global_blocks_changed; /* number of currently dirty blocks */
+ ulonglong global_cache_w_requests;/* number of write requests (write hits) */
+ ulonglong global_cache_write; /* number of writes from cache to files */
+ ulonglong global_cache_r_requests;/* number of read requests (read hits) */
+ ulonglong global_cache_read; /* number of reads from files to cache */
+
+ uint shift; /* block size = 2 ^ shift */
+ myf readwrite_flags; /* Flags to pread/pwrite() */
+ myf org_readwrite_flags; /* Flags to pread/pwrite() at init */
+ my_bool inited;
+ my_bool resize_in_flush; /* true during flush of resize operation */
+ my_bool can_be_used; /* usage of cache for read/write is allowed */
+ my_bool in_init; /* Set to 1 in MySQL during init/resize */
+ HASH files_in_flush; /**< files in flush_pagecache_blocks_int() */
+} PAGECACHE;
+
+/** @brief Return values for PAGECACHE_FLUSH_FILTER */
+enum pagecache_flush_filter_result
+{
+ FLUSH_FILTER_SKIP_TRY_NEXT= 0,/**< skip page and move on to next one */
+ FLUSH_FILTER_OK, /**< flush page and move on to next one */
+ FLUSH_FILTER_SKIP_ALL /**< skip page and all next ones */
+};
+/** @brief a filter function type for flush_pagecache_blocks_with_filter() */
+typedef enum pagecache_flush_filter_result
+(*PAGECACHE_FLUSH_FILTER)(enum pagecache_page_type type,
+ pgcache_page_no_t page,
+ LSN rec_lsn, void *arg);
+
+/* The default key cache */
+extern PAGECACHE dflt_pagecache_var, *dflt_pagecache;
+
+extern ulong init_pagecache(PAGECACHE *pagecache, size_t use_mem,
+ uint division_limit, uint age_threshold,
+ uint block_size, myf my_read_flags);
+extern ulong resize_pagecache(PAGECACHE *pagecache,
+ size_t use_mem, uint division_limit,
+ uint age_threshold);
+extern void change_pagecache_param(PAGECACHE *pagecache, uint division_limit,
+ uint age_threshold);
+
+extern uchar *pagecache_read(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ uint level,
+ uchar *buff,
+ enum pagecache_page_type type,
+ enum pagecache_page_lock lock,
+ PAGECACHE_BLOCK_LINK **link);
+
+#define pagecache_write(P,F,N,L,B,T,O,I,M,K,R) \
+ pagecache_write_part(P,F,N,L,B,T,O,I,M,K,R,0,(P)->block_size)
+
+#define pagecache_inject(P,F,N,L,B,T,O,I,K,R) \
+ pagecache_write_part(P,F,N,L,B,T,O,I,PAGECACHE_WRITE_DONE, \
+ K,R,0,(P)->block_size)
+
+extern my_bool pagecache_write_part(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ uint level,
+ uchar *buff,
+ enum pagecache_page_type type,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin,
+ enum pagecache_write_mode write_mode,
+ PAGECACHE_BLOCK_LINK **link,
+ LSN first_REDO_LSN_for_page,
+ uint offset,
+ uint size);
+extern void pagecache_unlock(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin,
+ LSN first_REDO_LSN_for_page,
+ LSN lsn, my_bool was_changed);
+extern void pagecache_unlock_by_link(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *block,
+ enum pagecache_page_lock lock,
+ enum pagecache_page_pin pin,
+ LSN first_REDO_LSN_for_page,
+ LSN lsn, my_bool was_changed,
+ my_bool any);
+extern void pagecache_unpin(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ LSN lsn);
+extern void pagecache_unpin_by_link(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *link,
+ LSN lsn);
+
+
+/* Results of flush operation (bit field in fact) */
+
+/* The flush is done. */
+#define PCFLUSH_OK 0
+/* There was errors during the flush process. */
+#define PCFLUSH_ERROR 1
+/* Pinned blocks was met and skipped. */
+#define PCFLUSH_PINNED 2
+/* PCFLUSH_ERROR and PCFLUSH_PINNED. */
+#define PCFLUSH_PINNED_AND_ERROR (PCFLUSH_ERROR|PCFLUSH_PINNED)
+
+#define pagecache_file_init(F,RC,WC,WF,GLC,D) \
+ do{ \
+ (F).read_callback= (RC); (F).write_callback= (WC); \
+ (F).write_fail= (WF); \
+ (F).flush_log_callback= (GLC); (F).callback_data= (uchar*)(D); \
+ } while(0)
+
+#define flush_pagecache_blocks(A,B,C) \
+ flush_pagecache_blocks_with_filter(A,B,C,NULL,NULL)
+extern int flush_pagecache_blocks_with_filter(PAGECACHE *keycache,
+ PAGECACHE_FILE *file,
+ enum flush_type type,
+ PAGECACHE_FLUSH_FILTER filter,
+ void *filter_arg);
+extern my_bool pagecache_delete(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ enum pagecache_page_lock lock,
+ my_bool flush);
+extern my_bool pagecache_delete_by_link(PAGECACHE *pagecache,
+ PAGECACHE_BLOCK_LINK *link,
+ enum pagecache_page_lock lock,
+ my_bool flush);
+extern my_bool pagecache_delete_pages(PAGECACHE *pagecache,
+ PAGECACHE_FILE *file,
+ pgcache_page_no_t pageno,
+ uint page_count,
+ enum pagecache_page_lock lock,
+ my_bool flush);
+extern void end_pagecache(PAGECACHE *keycache, my_bool cleanup);
+extern my_bool pagecache_collect_changed_blocks_with_lsn(PAGECACHE *pagecache,
+ LEX_STRING *str,
+ LSN *min_lsn);
+extern int reset_pagecache_counters(const char *name, PAGECACHE *pagecache);
+extern uchar *pagecache_block_link_to_buffer(PAGECACHE_BLOCK_LINK *block);
+
+extern uint pagecache_pagelevel(PAGECACHE_BLOCK_LINK *block);
+extern void pagecache_add_level_by_link(PAGECACHE_BLOCK_LINK *block,
+ uint level);
+
+/* Functions to handle multiple key caches */
+extern my_bool multi_pagecache_init(void);
+extern void multi_pagecache_free(void);
+extern PAGECACHE *multi_pagecache_search(uchar *key, uint length,
+ PAGECACHE *def);
+extern my_bool multi_pagecache_set(const uchar *key, uint length,
+ PAGECACHE *pagecache);
+extern void multi_pagecache_change(PAGECACHE *old_data,
+ PAGECACHE *new_data);
+extern int reset_pagecache_counters(const char *name,
+ PAGECACHE *pagecache);
+#ifndef DBUG_OFF
+void pagecache_file_no_dirty_page(PAGECACHE *pagecache, PAGECACHE_FILE *file);
+#else
+#define pagecache_file_no_dirty_page(A,B) {}
+#endif
+
+C_MODE_END
+#endif /* _keycache_h */
diff --git a/storage/maria/ma_pagecaches.c b/storage/maria/ma_pagecaches.c
new file mode 100644
index 00000000000..8a1423ee0d7
--- /dev/null
+++ b/storage/maria/ma_pagecaches.c
@@ -0,0 +1,104 @@
+/* Copyright (C) 2003-2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Handling of multiple key caches
+
+ The idea is to have a thread safe hash on the table name,
+ with a default key cache value that is returned if the table name is not in
+ the cache.
+*/
+
+#include "maria_def.h"
+#include "ma_pagecache.h"
+#include <hash.h>
+#include <m_string.h>
+#include "../../mysys/my_safehash.h"
+
+/*****************************************************************************
+ Functions to handle the pagecache objects
+*****************************************************************************/
+
+/* Variable to store all key cache objects */
+static SAFE_HASH pagecache_hash;
+
+
+my_bool multi_pagecache_init(void)
+{
+ return safe_hash_init(&pagecache_hash, 16, (uchar*) maria_pagecache);
+}
+
+
+void multi_pagecache_free(void)
+{
+ safe_hash_free(&pagecache_hash);
+}
+
+/*
+ Get a key cache to be used for a specific table.
+
+ SYNOPSIS
+ multi_pagecache_search()
+ key key to find (usually table path)
+ uint length Length of key.
+ def Default value if no key cache
+
+ NOTES
+ This function is coded in such a way that we will return the
+ default key cache even if one never called multi_pagecache_init.
+ This will ensure that it works with old MyISAM clients.
+
+ RETURN
+ key cache to use
+*/
+
+PAGECACHE *multi_pagecache_search(uchar *key, uint length,
+ PAGECACHE *def)
+{
+ if (!pagecache_hash.hash.records)
+ return def;
+ return (PAGECACHE*) safe_hash_search(&pagecache_hash, key, length,
+ (void*) def);
+}
+
+
+/*
+ Assosiate a key cache with a key
+
+
+ SYONOPSIS
+ multi_pagecache_set()
+ key key (path to table etc..)
+ length Length of key
+ pagecache cache to assococite with the table
+
+ NOTES
+ This can be used both to insert a new entry and change an existing
+ entry
+*/
+
+
+my_bool multi_pagecache_set(const uchar *key, uint length,
+ PAGECACHE *pagecache)
+{
+ return safe_hash_set(&pagecache_hash, key, length, (uchar*) pagecache);
+}
+
+
+void multi_pagecache_change(PAGECACHE *old_data,
+ PAGECACHE *new_data)
+{
+ safe_hash_change(&pagecache_hash, (uchar*) old_data, (uchar*) new_data);
+}
diff --git a/storage/maria/ma_pagecrc.c b/storage/maria/ma_pagecrc.c
new file mode 100644
index 00000000000..ffb4e90e400
--- /dev/null
+++ b/storage/maria/ma_pagecrc.c
@@ -0,0 +1,378 @@
+/* Copyright (C) 2007-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+
+
+/**
+ @brief calculate crc of the page avoiding special values
+
+ @param start The value to start CRC (we use page number here)
+ @param data data pointer
+ @param length length of the data
+
+ @return crc of the page without special values
+*/
+
+static uint32 maria_page_crc(uint32 start, uchar *data, uint length)
+{
+ uint32 crc= crc32(start, data, length);
+
+ /* we need this assert to get following comparison working */
+ compile_time_assert(MARIA_NO_CRC_BITMAP_PAGE ==
+ MARIA_NO_CRC_NORMAL_PAGE - 1 &&
+ MARIA_NO_CRC_NORMAL_PAGE == 0xffffffff);
+ if (crc >= MARIA_NO_CRC_BITMAP_PAGE)
+ crc= MARIA_NO_CRC_BITMAP_PAGE - 1;
+
+ return(crc);
+}
+
+/**
+ @brief Maria pages read callback (checks the page CRC)
+
+ @param page The page data to check
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr pointer to MARIA_SHARE
+ @param no_crc_val Value which means CRC absence
+ (MARIA_NO_CRC_NORMAL_PAGE or MARIA_NO_CRC_BITMAP_PAGE)
+ @param data_length length of data to calculate CRC
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+static my_bool maria_page_crc_check(uchar *page,
+ pgcache_page_no_t page_no,
+ MARIA_SHARE *share,
+ uint32 no_crc_val,
+ int data_length)
+{
+ uint32 crc= uint4korr(page + share->block_size - CRC_SIZE), new_crc;
+ my_bool res;
+ DBUG_ENTER("maria_page_crc_check");
+
+ DBUG_ASSERT((uint)data_length <= share->block_size - CRC_SIZE);
+
+ /* we need this assert to get following comparison working */
+ compile_time_assert(MARIA_NO_CRC_BITMAP_PAGE ==
+ MARIA_NO_CRC_NORMAL_PAGE - 1 &&
+ MARIA_NO_CRC_NORMAL_PAGE == 0xffffffff);
+ /*
+ If crc is no_crc_val then
+ the page has no crc, so there is nothing to check.
+ */
+ if (crc >= MARIA_NO_CRC_BITMAP_PAGE)
+ {
+ DBUG_PRINT("info", ("No crc: %lu crc: %lu page: %lu ",
+ (ulong) no_crc_val, (ulong) crc, (ulong) page_no));
+ if (crc != no_crc_val)
+ {
+ my_errno= HA_ERR_WRONG_CRC;
+ DBUG_PRINT("error", ("Wrong no CRC value"));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+ new_crc= maria_page_crc((uint32) page_no, page, data_length);
+ DBUG_ASSERT(new_crc != no_crc_val);
+ res= test(new_crc != crc);
+ if (res)
+ {
+ /*
+ Bitmap pages may be totally zero filled in some cases.
+ This happens when we get a crash after the pagecache has written
+ out a page that is on a newly created bitmap page and we get
+ a crash before the bitmap page is written out.
+
+ We handle this case with the following logic:
+ When reading, approve of bitmap pages where all bytes are zero
+ (This is after all a bitmap pages where no data is reserved and
+ the CRC will be corrected at next write)
+ */
+ if (no_crc_val == MARIA_NO_CRC_BITMAP_PAGE &&
+ crc == 0 && _ma_check_if_zero(page, data_length))
+ {
+ DBUG_PRINT("warning", ("Found bitmap page that was not initialized"));
+ DBUG_RETURN(0);
+ }
+
+ DBUG_PRINT("error", ("Page: %lu crc: %lu calculated crc: %lu",
+ (ulong) page_no, (ulong) crc, (ulong) new_crc));
+ my_errno= HA_ERR_WRONG_CRC;
+ }
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Maria pages write callback (sets the page CRC for data and index
+ files)
+
+ @param page The page data to set
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+*/
+
+my_bool maria_page_crc_set_normal(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr)
+{
+ MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
+ int data_length= share->block_size - CRC_SIZE;
+ uint32 crc= maria_page_crc((uint32) page_no, page, data_length);
+ DBUG_ENTER("maria_page_crc_set_normal");
+ DBUG_PRINT("info", ("Page %lu crc: %lu", (ulong) page_no, (ulong)crc));
+
+ /* crc is on the stack so it is aligned, pagecache buffer is aligned, too */
+ int4store_aligned(page + data_length, crc);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Maria pages write callback (sets the page CRC for keys)
+
+ @param page The page data to set
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+*/
+
+my_bool maria_page_crc_set_index(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr)
+{
+ MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
+ int data_length= _ma_get_page_used(share, page);
+ uint32 crc= maria_page_crc((uint32) page_no, page, data_length);
+ DBUG_ENTER("maria_page_crc_set_index");
+ DBUG_PRINT("info", ("Page %lu crc: %lu",
+ (ulong) page_no, (ulong) crc));
+ DBUG_ASSERT((uint)data_length <= share->block_size - CRC_SIZE);
+ /* crc is on the stack so it is aligned, pagecache buffer is aligned, too */
+ int4store_aligned(page + share->block_size - CRC_SIZE, crc);
+ DBUG_RETURN(0);
+}
+
+
+/* interface functions */
+
+
+/**
+ @brief Maria pages read callback (checks the page CRC) for index/data pages
+
+ @param page The page data to check
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Read callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool maria_page_crc_check_data(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr)
+{
+ MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
+ return (maria_page_crc_check(page, (uint32) page_no, share,
+ MARIA_NO_CRC_NORMAL_PAGE,
+ share->block_size - CRC_SIZE));
+}
+
+
+/**
+ @brief Maria pages read callback (checks the page CRC) for bitmap pages
+
+ @param page The page data to check
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Read callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool maria_page_crc_check_bitmap(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr)
+{
+ MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
+ return (maria_page_crc_check(page, (uint32) page_no, share,
+ MARIA_NO_CRC_BITMAP_PAGE,
+ share->block_size - CRC_SIZE));
+}
+
+
+/**
+ @brief Maria pages read callback (checks the page CRC) for index pages
+
+ @param page The page data to check
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Read callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool maria_page_crc_check_index(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr)
+{
+ MARIA_SHARE *share= (MARIA_SHARE *)data_ptr;
+ uint length= _ma_get_page_used(share, page);
+ if (length > share->block_size - CRC_SIZE)
+ {
+ DBUG_PRINT("error", ("Wrong page length: %u", length));
+ return (my_errno= HA_ERR_WRONG_CRC);
+ }
+ return maria_page_crc_check(page, (uint32) page_no, share,
+ MARIA_NO_CRC_NORMAL_PAGE,
+ length);
+}
+
+
+/**
+ @brief Maria pages dumme read callback for temporary tables
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool maria_page_crc_check_none(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no
+ __attribute__((unused)),
+ uchar *data_ptr __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/**
+ @brief Maria pages write callback (sets the page filler for index/data)
+
+ @param page The page data to set
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+*/
+
+my_bool maria_page_filler_set_normal(uchar *page,
+ pgcache_page_no_t page_no
+ __attribute__((unused)),
+ uchar *data_ptr)
+{
+ DBUG_ENTER("maria_page_filler_set_normal");
+ DBUG_ASSERT(page_no != 0); /* Catches some simple bugs */
+ int4store_aligned(page + ((MARIA_SHARE *)data_ptr)->block_size - CRC_SIZE,
+ MARIA_NO_CRC_NORMAL_PAGE);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Maria pages write callback (sets the page filler for bitmap)
+
+ @param page The page data to set
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+*/
+
+my_bool maria_page_filler_set_bitmap(uchar *page,
+ pgcache_page_no_t page_no
+ __attribute__((unused)),
+ uchar *data_ptr)
+{
+ DBUG_ENTER("maria_page_filler_set_bitmap");
+ int4store_aligned(page + ((MARIA_SHARE *)data_ptr)->block_size - CRC_SIZE,
+ MARIA_NO_CRC_BITMAP_PAGE);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Maria pages dummy write callback for temporary tables
+
+ @retval 0 OK
+*/
+
+my_bool maria_page_filler_set_none(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no
+ __attribute__((unused)),
+ uchar *data_ptr __attribute__((unused)))
+{
+#ifdef HAVE_purify
+ int4store_aligned(page + ((MARIA_SHARE *)data_ptr)->block_size - CRC_SIZE,
+ 0);
+#endif
+ return 0;
+}
+
+
+/**
+ @brief Write failure callback (mark table as corrupted)
+
+ @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
+*/
+
+void maria_page_write_failure(uchar* data_ptr)
+{
+ maria_mark_crashed_share((MARIA_SHARE *)data_ptr);
+}
+
+
+/**
+ @brief Maria flush log log if needed
+
+ @param page The page data to set
+ @param page_no The page number (<offset>/<page length>)
+ @param data_ptr Write callback data pointer (pointer to MARIA_SHARE)
+
+ @retval 0 OK
+ @retval 1 error
+*/
+
+my_bool maria_flush_log_for_page(uchar *page,
+ pgcache_page_no_t page_no
+ __attribute__((unused)),
+ uchar *data_ptr __attribute__((unused)))
+{
+ LSN lsn;
+#ifndef DBUG_OFF
+ const MARIA_SHARE *share= (MARIA_SHARE*) data_ptr;
+#endif
+ DBUG_ENTER("maria_flush_log_for_page");
+ /* share is 0 here only in unittest */
+ DBUG_ASSERT(!share || (share->page_type == PAGECACHE_LSN_PAGE &&
+ share->now_transactional));
+ lsn= lsn_korr(page);
+ if (translog_flush(lsn))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+my_bool maria_flush_log_for_page_none(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no
+ __attribute__((unused)),
+ uchar *data_ptr __attribute__((unused)))
+{
+ return 0;
+}
diff --git a/storage/maria/ma_panic.c b/storage/maria/ma_panic.c
new file mode 100644
index 00000000000..a86563f31fb
--- /dev/null
+++ b/storage/maria/ma_panic.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "ma_fulltext.h"
+
+/*
+ Stop usage of Maria
+
+ SYNOPSIS
+ maria_panic()
+ flag HA_PANIC_CLOSE: All maria files (tables and log) are closed.
+ maria_end() is called.
+ HA_PANIC_WRITE: All misam files are unlocked and
+ all changed data in single user maria is
+ written to file
+ HA_PANIC_READ All maria files that was locked when
+ maria_panic(HA_PANIC_WRITE) was done is
+ locked. A maria_readinfo() is done for
+ all single user files to get changes
+ in database
+
+ RETURN
+ 0 ok
+ # error number in case of error
+*/
+
+int maria_panic(enum ha_panic_function flag)
+{
+ int error=0;
+ LIST *list_element,*next_open;
+ MARIA_HA *info;
+ DBUG_ENTER("maria_panic");
+
+ if (!maria_inited)
+ DBUG_RETURN(0);
+ pthread_mutex_lock(&THR_LOCK_maria);
+ for (list_element=maria_open_list ; list_element ; list_element=next_open)
+ {
+ next_open=list_element->next; /* Save if close */
+ info=(MARIA_HA*) list_element->data;
+ switch (flag) {
+ case HA_PANIC_CLOSE:
+ /*
+ If bad luck (if some tables would be used now, which normally does not
+ happen in MySQL), as we release the mutex, the list may change and so
+ we may crash.
+ */
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ if (maria_close(info))
+ error=my_errno;
+ pthread_mutex_lock(&THR_LOCK_maria);
+ break;
+ case HA_PANIC_WRITE: /* Do this to free databases */
+#ifdef CANT_OPEN_FILES_TWICE
+ if (info->s->options & HA_OPTION_READ_ONLY_DATA)
+ break;
+#endif
+ if (flush_pagecache_blocks(info->s->pagecache, &info->s->kfile,
+ FLUSH_RELEASE))
+ error=my_errno;
+ if (info->opt_flag & WRITE_CACHE_USED)
+ if (flush_io_cache(&info->rec_cache))
+ error=my_errno;
+ if (info->opt_flag & READ_CACHE_USED)
+ {
+ if (flush_io_cache(&info->rec_cache))
+ error=my_errno;
+ reinit_io_cache(&info->rec_cache,READ_CACHE,0,
+ (pbool) (info->lock_type != F_UNLCK),1);
+ }
+ if (info->lock_type != F_UNLCK && ! info->was_locked)
+ {
+ info->was_locked=info->lock_type;
+ if (maria_lock_database(info,F_UNLCK))
+ error=my_errno;
+ }
+#ifdef CANT_OPEN_FILES_TWICE
+ if (info->s->kfile.file >= 0 && my_close(info->s->kfile.file, MYF(0)))
+ error = my_errno;
+ if (info->dfile.file >= 0 && my_close(info->dfile.file, MYF(0)))
+ error = my_errno;
+ info->s->kfile.file= info->dfile.file= -1;/* Files aren't open anymore */
+ break;
+#endif
+ case HA_PANIC_READ: /* Restore to before WRITE */
+#ifdef CANT_OPEN_FILES_TWICE
+ { /* Open closed files */
+ char name_buff[FN_REFLEN];
+ MARIA_SHARE *share= info->s;
+ if (share->kfile.file < 0)
+ {
+
+ if ((share->kfile.file= my_open(fn_format(name_buff,
+ info->filename, "",
+ N_NAME_IEXT,4),
+ info->mode,
+ MYF(MY_WME))) < 0)
+ error = my_errno;
+ }
+ if (info->dfile.file < 0)
+ {
+ if ((info->dfile.file= my_open(fn_format(name_buff, info->filename,
+ "", N_NAME_DEXT, 4),
+ info->mode,
+ MYF(MY_WME))) < 0)
+ error = my_errno;
+ info->rec_cache.file= info->dfile.file;
+ }
+ if (share->bitmap.file.file < 0)
+ share->bitmap.file.file= info->dfile.file;
+ }
+#endif
+ if (info->was_locked)
+ {
+ if (maria_lock_database(info, info->was_locked))
+ error=my_errno;
+ info->was_locked=0;
+ }
+ break;
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ if (flag == HA_PANIC_CLOSE)
+ maria_end();
+ if (!error)
+ DBUG_RETURN(0);
+ DBUG_RETURN(my_errno=error);
+} /* maria_panic */
diff --git a/storage/maria/ma_preload.c b/storage/maria/ma_preload.c
new file mode 100644
index 00000000000..6367d013f60
--- /dev/null
+++ b/storage/maria/ma_preload.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Preload indexes into key cache
+*/
+
+#include "maria_def.h"
+
+
+/*
+ Preload pages of the index file for a table into the key cache
+
+ SYNOPSIS
+ maria_preload()
+ info open table
+ map map of indexes to preload into key cache
+ ignore_leaves only non-leaves pages are to be preloaded
+
+ RETURN VALUE
+ 0 if a success. error code - otherwise.
+
+ NOTES.
+ At present pages for all indexes are preloaded.
+ In future only pages for indexes specified in the key_map parameter
+ of the table will be preloaded.
+ We don't yet use preload_buff_size (we read page after page).
+*/
+
+int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves)
+{
+ ulong block_length= 0;
+ uchar *buff= NULL;
+ MARIA_SHARE* share= info->s;
+ uint keynr;
+ my_off_t key_file_length= share->state.state.key_file_length;
+ pgcache_page_no_t page_no, page_no_max;
+ PAGECACHE_BLOCK_LINK *page_link;
+ DBUG_ENTER("maria_preload");
+
+ if (!share->state.header.keys || !maria_is_any_key_active(key_map) ||
+ (key_file_length == share->base.keystart))
+ DBUG_RETURN(0);
+
+ block_length= share->pagecache->block_size;
+
+ if (!(buff= (uchar *) my_malloc(block_length, MYF(MY_WME))))
+ DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
+
+ if (flush_pagecache_blocks(share->pagecache, &share->kfile, FLUSH_RELEASE))
+ goto err;
+
+ /*
+ Currently when we come here all other open instances of the table have
+ been closed, and we flushed all pages of our own instance, so there
+ cannot be any page of this table in the cache. Thus my_pread() would be
+ safe. But in the future, we will allow more concurrency during
+ preloading, so we use pagecache_read() instead of my_pread() because we
+ observed that on some Linux, concurrent pread() and pwrite() (which
+ could be from a page eviction by another thread) to the same page can
+ make pread() see an half-written page.
+ In this future, we should find a way to read state.key_file_length
+ reliably, handle concurrent shrinks (delete_all_rows()) etc.
+ */
+ for ((page_no= share->base.keystart / block_length),
+ (page_no_max= key_file_length / block_length);
+ page_no < page_no_max; page_no++)
+ {
+ /**
+ @todo instead of reading pages one by one we could have a call
+ pagecache_read_several_pages() which does a single my_pread() for many
+ consecutive pages (like the my_pread() in mi_preload()).
+ */
+ if (pagecache_read(share->pagecache, &share->kfile, page_no,
+ DFLT_INIT_HITS, (uchar*) buff, share->page_type,
+ PAGECACHE_LOCK_WRITE, &page_link) == NULL)
+ goto err;
+ keynr= _ma_get_keynr(share, buff);
+ if (((ignore_leaves && !_ma_test_if_nod(share, buff)) ||
+ keynr == MARIA_DELETE_KEY_NR ||
+ !(key_map & ((ulonglong) 1 << keynr))) &&
+ (pagecache_pagelevel(page_link) == DFLT_INIT_HITS))
+ {
+ /*
+ This page is not interesting, and (last condition above) we are the
+ ones who put it in the cache, so nobody else is interested in it.
+ */
+ if (pagecache_delete_by_link(share->pagecache, page_link,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, FALSE))
+ goto err;
+ }
+ else /* otherwise it stays in cache: */
+ pagecache_unlock_by_link(share->pagecache, page_link,
+ PAGECACHE_LOCK_WRITE_UNLOCK, PAGECACHE_UNPIN,
+ LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, FALSE, FALSE);
+ }
+
+ my_free(buff, MYF(0));
+ DBUG_RETURN(0);
+
+err:
+ my_free(buff, MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(my_errno= errno);
+}
diff --git a/storage/maria/ma_range.c b/storage/maria/ma_range.c
new file mode 100644
index 00000000000..38f1d8aa44d
--- /dev/null
+++ b/storage/maria/ma_range.c
@@ -0,0 +1,313 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Gives a approximated number of how many records there is between two keys.
+ Used when optimizing querries.
+ */
+
+#include "maria_def.h"
+#include "ma_rt_index.h"
+
+static ha_rows _ma_record_pos(MARIA_HA *,const uchar *, key_part_map,
+ enum ha_rkey_function);
+static double _ma_search_pos(MARIA_HA *, MARIA_KEY *, uint32, my_off_t);
+static uint _ma_keynr(MARIA_HA *, MARIA_KEYDEF *, uchar *, uchar *, uint *);
+
+
+/**
+ @brief Estimate how many records there is in a given range
+
+ @param info MARIA handler
+ @param inx Index to use
+ @param min_key Min key. Is = 0 if no min range
+ @param max_key Max key. Is = 0 if no max range
+
+ @note
+ We should ONLY return 0 if there is no rows in range
+
+ @return Estimated number of rows or error
+ @retval HA_POS_ERROR error (or we can't estimate number of rows)
+ @retval number Estimated number of rows
+*/
+
+ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key,
+ key_range *max_key)
+{
+ ha_rows start_pos,end_pos,res;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEY key;
+ MARIA_KEYDEF *keyinfo;
+ DBUG_ENTER("maria_records_in_range");
+
+ if ((inx = _ma_check_index(info,inx)) < 0)
+ DBUG_RETURN(HA_POS_ERROR);
+
+ if (fast_ma_readinfo(info))
+ DBUG_RETURN(HA_POS_ERROR);
+ info->update&= (HA_STATE_CHANGED+HA_STATE_ROW_CHANGED);
+ keyinfo= share->keyinfo + inx;
+ if (share->lock_key_trees)
+ rw_rdlock(&keyinfo->root_lock);
+
+ switch (keyinfo->key_alg) {
+#ifdef HAVE_RTREE_KEYS
+ case HA_KEY_ALG_RTREE:
+ {
+ uchar *key_buff;
+
+ /*
+ The problem is that the optimizer doesn't support
+ RTree keys properly at the moment.
+ Hope this will be fixed some day.
+ But now NULL in the min_key means that we
+ didn't make the task for the RTree key
+ and expect BTree functionality from it.
+ As it's not able to handle such request
+ we return the error.
+ */
+ if (!min_key)
+ {
+ res= HA_POS_ERROR;
+ break;
+ }
+ key_buff= info->last_key.data + share->base.max_key_length;
+ _ma_pack_key(info, &key, inx, key_buff,
+ min_key->key, min_key->keypart_map,
+ (HA_KEYSEG**) 0);
+ res= maria_rtree_estimate(info, &key, maria_read_vec[min_key->flag]);
+ res= res ? res : 1; /* Don't return 0 */
+ break;
+ }
+#endif
+ case HA_KEY_ALG_BTREE:
+ default:
+ start_pos= (min_key ?
+ _ma_record_pos(info, min_key->key, min_key->keypart_map,
+ min_key->flag) :
+ (ha_rows) 0);
+ end_pos= (max_key ?
+ _ma_record_pos(info, max_key->key, max_key->keypart_map,
+ max_key->flag) :
+ info->state->records + (ha_rows) 1);
+ res= (end_pos < start_pos ? (ha_rows) 0 :
+ (end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos));
+ if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR)
+ res=HA_POS_ERROR;
+ }
+
+ if (share->lock_key_trees)
+ rw_unlock(&keyinfo->root_lock);
+ fast_ma_writeinfo(info);
+
+ /**
+ @todo LOCK
+ If res==0 (no rows), if we need to guarantee repeatability of the search,
+ we will need to set a next-key lock in this statement.
+ Also SELECT COUNT(*)...
+ */
+
+ DBUG_PRINT("info",("records: %ld",(ulong) (res)));
+ DBUG_RETURN(res);
+}
+
+
+ /* Find relative position (in records) for key in index-tree */
+
+static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key_data,
+ key_part_map keypart_map,
+ enum ha_rkey_function search_flag)
+{
+ uint inx= (uint) info->lastinx;
+ uint32 nextflag;
+ uchar *key_buff;
+ double pos;
+ MARIA_KEY key;
+ DBUG_ENTER("_ma_record_pos");
+ DBUG_PRINT("enter",("search_flag: %d",search_flag));
+ DBUG_ASSERT(keypart_map);
+
+ key_buff= info->lastkey_buff+info->s->base.max_key_length;
+ _ma_pack_key(info, &key, inx, key_buff, key_data, keypart_map,
+ (HA_KEYSEG**) 0);
+ DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, &key););
+ nextflag=maria_read_vec[search_flag];
+
+ /*
+ my_handler.c:ha_compare_text() has a flag 'skip_end_space'.
+ This is set in my_handler.c:ha_key_cmp() in dependence on the
+ compare flags 'nextflag' and the column type.
+
+ TEXT columns are of type HA_KEYTYPE_VARTEXT. In this case the
+ condition is skip_end_space= ((nextflag & (SEARCH_FIND |
+ SEARCH_UPDATE)) == SEARCH_FIND).
+
+ SEARCH_FIND is used for an exact key search. The combination
+ SEARCH_FIND | SEARCH_UPDATE is used in write/update/delete
+ operations with a comment like "Not real duplicates", whatever this
+ means. From the condition above we can see that 'skip_end_space' is
+ always false for these operations. The result is that trailing space
+ counts in key comparison and hence, emtpy strings ('', string length
+ zero, but not NULL) compare less that strings starting with control
+ characters and these in turn compare less than strings starting with
+ blanks.
+
+ When estimating the number of records in a key range, we request an
+ exact search for the minimum key. This translates into a plain
+ SEARCH_FIND flag. Using this alone would lead to a 'skip_end_space'
+ compare. Empty strings would be expected above control characters.
+ Their keys would not be found because they are located below control
+ characters.
+
+ This is the reason that we add the SEARCH_UPDATE flag here. It makes
+ the key estimation compare in the same way like key write operations
+ do. Olny so we will find the keys where they have been inserted.
+
+ Adding the flag unconditionally does not hurt as it is used in the
+ above mentioned condition only. So it can safely be used together
+ with other flags.
+ */
+ pos= _ma_search_pos(info, &key,
+ nextflag | SEARCH_SAVE_BUFF | SEARCH_UPDATE,
+ info->s->state.key_root[inx]);
+ if (pos >= 0.0)
+ {
+ DBUG_PRINT("exit",("pos: %ld",(ulong) (pos*info->state->records)));
+ DBUG_RETURN((ulong) (pos*info->state->records+0.5));
+ }
+ DBUG_RETURN(HA_POS_ERROR);
+}
+
+
+/**
+ Find offset for key on index page
+
+ @notes
+ Modified version of _ma_search()
+
+ @return
+ @retval 0.0 <= x <= 1.0
+*/
+
+static double _ma_search_pos(MARIA_HA *info, MARIA_KEY *key,
+ uint32 nextflag, my_off_t pos)
+{
+ int flag;
+ uint nod_flag,keynr,max_keynr;
+ my_bool after_key;
+ uchar *keypos, *buff;
+ double offset;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_search_pos");
+ LINT_INIT(max_keynr);
+
+ if (pos == HA_OFFSET_ERROR)
+ DBUG_RETURN(0.5);
+
+ if (!(buff= _ma_fetch_keypage(info,keyinfo, pos,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, DFLT_INIT_HITS,
+ info->buff, 1, 0)))
+ goto err;
+ flag= (*keyinfo->bin_search)(key, buff, nextflag, &keypos,
+ info->lastkey_buff, &after_key);
+ nod_flag=_ma_test_if_nod(info->s, buff);
+ keynr= _ma_keynr(info,keyinfo,buff,keypos,&max_keynr);
+
+ if (flag)
+ {
+ if (flag == MARIA_FOUND_WRONG_KEY)
+ DBUG_RETURN(-1); /* error */
+ /*
+ Didn't found match. keypos points at next (bigger) key
+ Try to find a smaller, better matching key.
+ Matches keynr + [0-1]
+ */
+ if (flag > 0 && ! nod_flag)
+ offset= 1.0;
+ else if ((offset= _ma_search_pos(info, key, nextflag,
+ _ma_kpos(nod_flag,keypos))) < 0)
+ DBUG_RETURN(offset);
+ }
+ else
+ {
+ /*
+ Found match. Keypos points at the start of the found key
+ Matches keynr+1
+ */
+ offset=1.0; /* Matches keynr+1 */
+ if ((nextflag & SEARCH_FIND) && nod_flag &&
+ ((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
+ (nextflag & (SEARCH_PREFIX | SEARCH_NO_FIND | SEARCH_LAST |
+ SEARCH_PART_KEY))))
+ {
+ /*
+ There may be identical keys in the tree. Try to match on of those.
+ Matches keynr + [0-1]
+ */
+ if ((offset= _ma_search_pos(info, key, SEARCH_FIND,
+ _ma_kpos(nod_flag,keypos))) < 0)
+ DBUG_RETURN(offset); /* Read error */
+ }
+ }
+ DBUG_PRINT("info",("keynr: %d offset: %g max_keynr: %d nod: %d flag: %d",
+ keynr,offset,max_keynr,nod_flag,flag));
+ DBUG_RETURN((keynr+offset)/(max_keynr+1));
+err:
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1.0);
+}
+
+
+/* Get keynummer of current key and max number of keys in nod */
+
+static uint _ma_keynr(MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
+ uchar *page, uchar *keypos, uint *ret_max_key)
+{
+ uint page_flag, nod_flag, used_length, keynr, max_key;
+ uchar t_buff[MARIA_MAX_KEY_BUFF],*end;
+ MARIA_KEY key;
+
+ page_flag= _ma_get_keypage_flag(info->s, page);
+ _ma_get_used_and_nod_with_flag(info->s, page_flag, page, used_length,
+ nod_flag);
+ end= page+ used_length;
+ page+= info->s->keypage_header + nod_flag;
+
+ if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
+ ! (page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ {
+ *ret_max_key= (uint) (end-page)/(keyinfo->keylength+nod_flag);
+ return (uint) (keypos-page)/(keyinfo->keylength+nod_flag);
+ }
+
+ max_key=keynr=0;
+ t_buff[0]=0; /* Safety */
+ key.data= t_buff;
+ key.keyinfo= keyinfo;
+
+ while (page < end)
+ {
+ if (!(page= (*keyinfo->skip_key)(&key, page_flag, nod_flag, page)))
+ {
+ DBUG_ASSERT(0);
+ return 0; /* Error */
+ }
+ max_key++;
+ if (page == keypos)
+ keynr= max_key;
+ }
+ *ret_max_key=max_key;
+ return(keynr);
+}
diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c
new file mode 100644
index 00000000000..08aba4fdcd6
--- /dev/null
+++ b/storage/maria/ma_recovery.c
@@ -0,0 +1,3591 @@
+/* Copyright (C) 2006, 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ WL#3072 Maria recovery
+ First version written by Guilhem Bichot on 2006-04-27.
+*/
+
+/* Here is the implementation of this module */
+
+#include "maria_def.h"
+#include "ma_recovery.h"
+#include "ma_blockrec.h"
+#include "ma_checkpoint.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+#include "ma_recovery_util.h"
+
+struct st_trn_for_recovery /* used only in the REDO phase */
+{
+ LSN group_start_lsn, undo_lsn, first_undo_lsn;
+ TrID long_trid;
+};
+struct st_table_for_recovery /* used in the REDO and UNDO phase */
+{
+ MARIA_HA *info;
+};
+/* Variables used by all functions of this module. Ok as single-threaded */
+static struct st_trn_for_recovery *all_active_trans;
+static struct st_table_for_recovery *all_tables;
+static struct st_dirty_page *dirty_pages_pool;
+static LSN current_group_end_lsn;
+#ifndef DBUG_OFF
+/** Current group of REDOs is about this table and only this one */
+static MARIA_HA *current_group_table;
+#endif
+static TrID max_long_trid= 0; /**< max long trid seen by REDO phase */
+static my_bool skip_DDLs; /**< if REDO phase should skip DDL records */
+/** @brief to avoid writing a checkpoint if recovery did nothing. */
+static my_bool checkpoint_useful;
+static my_bool in_redo_phase;
+static my_bool trns_created;
+static ulong skipped_undo_phase;
+static ulonglong now; /**< for tracking execution time of phases */
+static int (*save_error_handler_hook)(uint, const char *,myf);
+static uint recovery_warnings; /**< count of warnings */
+
+#define prototype_redo_exec_hook(R) \
+ static int exec_REDO_LOGREC_ ## R(const TRANSLOG_HEADER_BUFFER *rec)
+
+#define prototype_redo_exec_hook_dummy(R) \
+ static int exec_REDO_LOGREC_ ## R(const TRANSLOG_HEADER_BUFFER *rec \
+ __attribute__ ((unused)))
+
+#define prototype_undo_exec_hook(R) \
+ static int exec_UNDO_LOGREC_ ## R(const TRANSLOG_HEADER_BUFFER *rec, TRN *trn)
+
+prototype_redo_exec_hook(LONG_TRANSACTION_ID);
+prototype_redo_exec_hook_dummy(CHECKPOINT);
+prototype_redo_exec_hook(REDO_CREATE_TABLE);
+prototype_redo_exec_hook(REDO_RENAME_TABLE);
+prototype_redo_exec_hook(REDO_REPAIR_TABLE);
+prototype_redo_exec_hook(REDO_DROP_TABLE);
+prototype_redo_exec_hook(FILE_ID);
+prototype_redo_exec_hook(INCOMPLETE_LOG);
+prototype_redo_exec_hook_dummy(INCOMPLETE_GROUP);
+prototype_redo_exec_hook(UNDO_BULK_INSERT);
+prototype_redo_exec_hook(IMPORTED_TABLE);
+prototype_redo_exec_hook(REDO_INSERT_ROW_HEAD);
+prototype_redo_exec_hook(REDO_INSERT_ROW_TAIL);
+prototype_redo_exec_hook(REDO_INSERT_ROW_HEAD);
+prototype_redo_exec_hook(REDO_PURGE_ROW_HEAD);
+prototype_redo_exec_hook(REDO_PURGE_ROW_TAIL);
+prototype_redo_exec_hook(REDO_FREE_HEAD_OR_TAIL);
+prototype_redo_exec_hook(REDO_FREE_BLOCKS);
+prototype_redo_exec_hook(REDO_DELETE_ALL);
+prototype_redo_exec_hook(REDO_INDEX);
+prototype_redo_exec_hook(REDO_INDEX_NEW_PAGE);
+prototype_redo_exec_hook(REDO_INDEX_FREE_PAGE);
+prototype_redo_exec_hook(REDO_BITMAP_NEW_PAGE);
+prototype_redo_exec_hook(UNDO_ROW_INSERT);
+prototype_redo_exec_hook(UNDO_ROW_DELETE);
+prototype_redo_exec_hook(UNDO_ROW_UPDATE);
+prototype_redo_exec_hook(UNDO_KEY_INSERT);
+prototype_redo_exec_hook(UNDO_KEY_DELETE);
+prototype_redo_exec_hook(UNDO_KEY_DELETE_WITH_ROOT);
+prototype_redo_exec_hook(COMMIT);
+prototype_redo_exec_hook(CLR_END);
+prototype_redo_exec_hook(DEBUG_INFO);
+prototype_undo_exec_hook(UNDO_ROW_INSERT);
+prototype_undo_exec_hook(UNDO_ROW_DELETE);
+prototype_undo_exec_hook(UNDO_ROW_UPDATE);
+prototype_undo_exec_hook(UNDO_KEY_INSERT);
+prototype_undo_exec_hook(UNDO_KEY_DELETE);
+prototype_undo_exec_hook(UNDO_KEY_DELETE_WITH_ROOT);
+prototype_undo_exec_hook(UNDO_BULK_INSERT);
+
+static int run_redo_phase(LSN lsn, enum maria_apply_log_way apply);
+static uint end_of_redo_phase(my_bool prepare_for_undo_phase);
+static int run_undo_phase(uint uncommitted);
+static void display_record_position(const LOG_DESC *log_desc,
+ const TRANSLOG_HEADER_BUFFER *rec,
+ uint number);
+static int display_and_apply_record(const LOG_DESC *log_desc,
+ const TRANSLOG_HEADER_BUFFER *rec);
+static MARIA_HA *get_MARIA_HA_from_REDO_record(const
+ TRANSLOG_HEADER_BUFFER *rec);
+static MARIA_HA *get_MARIA_HA_from_UNDO_record(const
+ TRANSLOG_HEADER_BUFFER *rec);
+static void prepare_table_for_close(MARIA_HA *info, TRANSLOG_ADDRESS horizon);
+static LSN parse_checkpoint_record(LSN lsn);
+static void new_transaction(uint16 sid, TrID long_id, LSN undo_lsn,
+ LSN first_undo_lsn);
+static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id);
+static int new_page(uint32 fileid, pgcache_page_no_t pageid, LSN rec_lsn,
+ struct st_dirty_page *dirty_page);
+static int close_all_tables(void);
+static my_bool close_one_table(const char *name, TRANSLOG_ADDRESS addr);
+static void print_redo_phase_progress(TRANSLOG_ADDRESS addr);
+static void delete_all_transactions();
+
+/** @brief global [out] buffer for translog_read_record(); never shrinks */
+static struct
+{
+ /*
+ uchar* is more adapted (less casts) than char*, thus we don't use
+ LEX_STRING.
+ */
+ uchar *str;
+ size_t length;
+} log_record_buffer;
+static void enlarge_buffer(const TRANSLOG_HEADER_BUFFER *rec)
+{
+ if (log_record_buffer.length < rec->record_length)
+ {
+ log_record_buffer.length= rec->record_length;
+ log_record_buffer.str= my_realloc(log_record_buffer.str,
+ rec->record_length,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR));
+ }
+}
+/** @brief Tells what kind of progress message was printed to the error log */
+static enum recovery_message_type
+{
+ REC_MSG_NONE= 0, REC_MSG_REDO, REC_MSG_UNDO, REC_MSG_FLUSH
+} recovery_message_printed;
+
+
+/* Hook to ensure we get nicer output if we get an error */
+
+int maria_recover_error_handler_hook(uint error, const char *str,
+ myf flags)
+{
+ if (procent_printed)
+ {
+ procent_printed= 0;
+ fputc('\n', stderr);
+ fflush(stderr);
+ }
+ return (*save_error_handler_hook)(error, str, flags);
+}
+
+/* Define this if you want gdb to break in some interesting situations */
+#define ALERT_USER()
+
+static void print_preamble()
+{
+ ma_message_no_user(ME_JUST_INFO, "starting recovery");
+}
+
+
+/**
+ @brief Recovers from the last checkpoint.
+
+ Runs the REDO phase using special structures, then sets up the playground
+ of runtime: recreates transactions inside trnman, open tables with their
+ two-byte-id mapping; takes a checkpoint and runs the UNDO phase. Closes all
+ tables.
+
+ @return Operation status
+ @retval 0 OK
+ @retval !=0 Error
+*/
+
+int maria_recovery_from_log(void)
+{
+ int res= 1;
+ FILE *trace_file;
+ uint warnings_count;
+ DBUG_ENTER("maria_recovery_from_log");
+
+ DBUG_ASSERT(!maria_in_recovery);
+ maria_in_recovery= TRUE;
+
+#ifdef EXTRA_DEBUG
+ trace_file= fopen("maria_recovery.trace", "a+");
+#else
+ trace_file= NULL; /* no trace file for being fast */
+#endif
+ tprint(trace_file, "TRACE of the last MARIA recovery from mysqld\n");
+ DBUG_ASSERT(maria_pagecache->inited);
+ res= maria_apply_log(LSN_IMPOSSIBLE, MARIA_LOG_APPLY, trace_file,
+ TRUE, TRUE, TRUE, &warnings_count);
+ if (!res)
+ {
+ if (warnings_count == 0)
+ tprint(trace_file, "SUCCESS\n");
+ else
+ tprint(trace_file, "DOUBTFUL (%u warnings, check previous output)\n",
+ warnings_count);
+ }
+ if (trace_file)
+ fclose(trace_file);
+ maria_in_recovery= FALSE;
+ DBUG_RETURN(res);
+}
+
+
+/**
+ @brief Displays and/or applies the log
+
+ @param from_lsn LSN from which log reading/applying should start;
+ LSN_IMPOSSIBLE means "use last checkpoint"
+ @param apply how log records should be applied or not
+ @param trace_file trace file where progress/debug messages will go
+ @param skip_DDLs_arg Should DDL records (CREATE/RENAME/DROP/REPAIR)
+ be skipped by the REDO phase or not
+ @param take_checkpoints Should we take checkpoints or not.
+ @param[out] warnings_count Count of warnings will be put there
+
+ @todo This trace_file thing is primitive; soon we will make it similar to
+ ma_check_print_warning() etc, and a successful recovery does not need to
+ create a trace file. But for debugging now it is useful.
+
+ @return Operation status
+ @retval 0 OK
+ @retval !=0 Error
+*/
+
+int maria_apply_log(LSN from_lsn, enum maria_apply_log_way apply,
+ FILE *trace_file,
+ my_bool should_run_undo_phase, my_bool skip_DDLs_arg,
+ my_bool take_checkpoints, uint *warnings_count)
+{
+ int error= 0;
+ uint uncommitted_trans;
+ ulonglong old_now;
+ DBUG_ENTER("maria_apply_log");
+
+ DBUG_ASSERT(apply == MARIA_LOG_APPLY || !should_run_undo_phase);
+ DBUG_ASSERT(!maria_multi_threaded);
+ recovery_warnings= 0;
+ /* checkpoints can happen only if TRNs have been built */
+ DBUG_ASSERT(should_run_undo_phase || !take_checkpoints);
+ all_active_trans= (struct st_trn_for_recovery *)
+ my_malloc((SHORT_TRID_MAX + 1) * sizeof(struct st_trn_for_recovery),
+ MYF(MY_ZEROFILL));
+ all_tables= (struct st_table_for_recovery *)
+ my_malloc((SHARE_ID_MAX + 1) * sizeof(struct st_table_for_recovery),
+ MYF(MY_ZEROFILL));
+
+ save_error_handler_hook= error_handler_hook;
+ error_handler_hook= maria_recover_error_handler_hook;
+
+ if (!all_active_trans || !all_tables)
+ goto err;
+
+ if (take_checkpoints && ma_checkpoint_init(0))
+ goto err;
+
+ recovery_message_printed= REC_MSG_NONE;
+ checkpoint_useful= trns_created= FALSE;
+ tracef= trace_file;
+#ifdef INSTANT_FLUSH_OF_MESSAGES
+ /* enable this for instant flush of messages to trace file */
+ setbuf(tracef, NULL);
+#endif
+ skip_DDLs= skip_DDLs_arg;
+ skipped_undo_phase= 0;
+
+ if (from_lsn == LSN_IMPOSSIBLE)
+ {
+ if (last_checkpoint_lsn == LSN_IMPOSSIBLE)
+ {
+ from_lsn= translog_first_lsn_in_log();
+ if (unlikely(from_lsn == LSN_ERROR))
+ goto err;
+ }
+ else
+ {
+ from_lsn= parse_checkpoint_record(last_checkpoint_lsn);
+ if (from_lsn == LSN_ERROR)
+ goto err;
+ }
+ }
+
+ now= my_getsystime();
+ in_redo_phase= TRUE;
+ if (run_redo_phase(from_lsn, apply))
+ {
+ ma_message_no_user(0, "Redo phase failed");
+ goto err;
+ }
+
+ if ((uncommitted_trans=
+ end_of_redo_phase(should_run_undo_phase)) == (uint)-1)
+ {
+ ma_message_no_user(0, "End of redo phase failed");
+ goto err;
+ }
+ in_redo_phase= FALSE;
+
+ old_now= now;
+ now= my_getsystime();
+ if (recovery_message_printed == REC_MSG_REDO)
+ {
+ double phase_took= (now - old_now)/10000000.0;
+ /*
+ Detailed progress info goes to stderr, because ma_message_no_user()
+ cannot put several messages on one line.
+ */
+ procent_printed= 1;
+ fprintf(stderr, " (%.1f seconds); ", phase_took);
+ fflush(stderr);
+ }
+
+ /**
+ REDO phase does not fill blocks' rec_lsn, so a checkpoint now would be
+ wrong: if a future recovery used it, the REDO phase would always
+ start from the checkpoint and never from before, wrongly skipping REDOs
+ (tested). Another problem is that the REDO phase uses
+ PAGECACHE_PLAIN_PAGE, while Checkpoint only collects PAGECACHE_LSN_PAGE.
+
+ @todo fix this. pagecache_write() now can have a rec_lsn argument. And we
+ could make a function which goes through pages at end of REDO phase and
+ changes their type.
+ */
+#ifdef FIX_AND_ENABLE_LATER
+ if (take_checkpoints && checkpoint_useful)
+ {
+ /*
+ We take a checkpoint as it can save future recovery work if we crash
+ during the UNDO phase. But we don't flush pages, as UNDOs will change
+ them again probably.
+ If we wanted to take checkpoints in the middle of the REDO phase, at a
+ moment when we haven't reached the end of log so don't have exact data
+ about transactions, we could write a special checkpoint: containing only
+ the list of dirty pages, otherwise to be treated as if it was at the
+ same LSN as the last checkpoint.
+ */
+ if (ma_checkpoint_execute(CHECKPOINT_INDIRECT, FALSE))
+ goto err;
+ }
+#endif
+
+ if (should_run_undo_phase)
+ {
+ if (run_undo_phase(uncommitted_trans))
+ {
+ ma_message_no_user(0, "Undo phase failed");
+ goto err;
+ }
+ }
+ else if (uncommitted_trans > 0)
+ {
+ eprint(tracef, "***WARNING: %u uncommitted transactions; some tables may"
+ " be left inconsistent!***", uncommitted_trans);
+ recovery_warnings++;
+ }
+
+ if (skipped_undo_phase)
+ {
+ /*
+ We could want to print a list of tables for which UNDOs were skipped,
+ but not one line per skipped UNDO.
+ */
+ eprint(tracef, "***WARNING: %lu UNDO records skipped in UNDO phase; some"
+ " tables may be left inconsistent!***", skipped_undo_phase);
+ recovery_warnings++;
+ }
+
+ old_now= now;
+ now= my_getsystime();
+ if (recovery_message_printed == REC_MSG_UNDO)
+ {
+ double phase_took= (now - old_now)/10000000.0;
+ procent_printed= 1;
+ fprintf(stderr, " (%.1f seconds); ", phase_took);
+ fflush(stderr);
+ }
+
+ /*
+ we don't use maria_panic() because it would maria_end(), and Recovery does
+ not want that (we want to keep some modules initialized for runtime).
+ */
+ if (close_all_tables())
+ {
+ ma_message_no_user(0, "closing of tables failed");
+ goto err;
+ }
+
+ old_now= now;
+ now= my_getsystime();
+ if (recovery_message_printed == REC_MSG_FLUSH)
+ {
+ double phase_took= (now - old_now)/10000000.0;
+ procent_printed= 1;
+ fprintf(stderr, " (%.1f seconds); ", phase_took);
+ fflush(stderr);
+ }
+
+ if (take_checkpoints && checkpoint_useful)
+ {
+ /* No dirty pages, all tables are closed, no active transactions, save: */
+ if (ma_checkpoint_execute(CHECKPOINT_FULL, FALSE))
+ goto err;
+ }
+
+ goto end;
+err:
+ error= 1;
+ tprint(tracef, "\nRecovery of tables with transaction logs FAILED\n");
+ if (trns_created)
+ delete_all_transactions();
+end:
+ error_handler_hook= save_error_handler_hook;
+ hash_free(&all_dirty_pages);
+ bzero(&all_dirty_pages, sizeof(all_dirty_pages));
+ my_free(dirty_pages_pool, MYF(MY_ALLOW_ZERO_PTR));
+ dirty_pages_pool= NULL;
+ my_free(all_tables, MYF(MY_ALLOW_ZERO_PTR));
+ all_tables= NULL;
+ my_free(all_active_trans, MYF(MY_ALLOW_ZERO_PTR));
+ all_active_trans= NULL;
+ my_free(log_record_buffer.str, MYF(MY_ALLOW_ZERO_PTR));
+ log_record_buffer.str= NULL;
+ log_record_buffer.length= 0;
+ ma_checkpoint_end();
+ *warnings_count= recovery_warnings;
+ if (recovery_message_printed != REC_MSG_NONE)
+ {
+ if (procent_printed)
+ {
+ procent_printed= 0;
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+ if (!error)
+ ma_message_no_user(ME_JUST_INFO, "recovery done");
+ }
+ if (error)
+ my_message(HA_ERR_INITIALIZATION,
+ "Maria recovery failed. Please run maria_chk -r on all maria "
+ "tables and delete all maria_log.######## files", MYF(0));
+ procent_printed= 0;
+ /*
+ We don't cleanly close tables if we hit some error (may corrupt them by
+ flushing some wrong blocks made from wrong REDOs). It also leaves their
+ open_count>0, which ensures that --maria-recover, if used, will try to
+ repair them.
+ */
+ DBUG_RETURN(error);
+}
+
+
+/* very basic info about the record's header */
+static void display_record_position(const LOG_DESC *log_desc,
+ const TRANSLOG_HEADER_BUFFER *rec,
+ uint number)
+{
+ /*
+ if number==0, we're going over records which we had already seen and which
+ form a group, so we indent below the group's end record
+ */
+ tprint(tracef,
+ "%sRec#%u LSN (%lu,0x%lx) short_trid %u %s(num_type:%u) len %lu\n",
+ number ? "" : " ", number, LSN_IN_PARTS(rec->lsn),
+ rec->short_trid, log_desc->name, rec->type,
+ (ulong)rec->record_length);
+ if (rec->type == LOGREC_DEBUG_INFO)
+ {
+ /* Print some extra information */
+ (*log_desc->record_execute_in_redo_phase)(rec);
+ }
+}
+
+
+static int display_and_apply_record(const LOG_DESC *log_desc,
+ const TRANSLOG_HEADER_BUFFER *rec)
+{
+ int error;
+ if (log_desc->record_execute_in_redo_phase == NULL)
+ {
+ /* die on all not-yet-handled records :) */
+ DBUG_ASSERT("one more hook" == "to write");
+ return 1;
+ }
+ if ((error= (*log_desc->record_execute_in_redo_phase)(rec)))
+ eprint(tracef, "Got error %d when executing record %s",
+ my_errno, log_desc->name);
+ return error;
+}
+
+
+prototype_redo_exec_hook(LONG_TRANSACTION_ID)
+{
+ uint16 sid= rec->short_trid;
+ TrID long_trid= all_active_trans[sid].long_trid;
+ /*
+ Any incomplete group should be of an old crash which already had a
+ recovery and thus has logged INCOMPLETE_GROUP which we must have seen.
+ */
+ DBUG_ASSERT(all_active_trans[sid].group_start_lsn == LSN_IMPOSSIBLE);
+ if (long_trid != 0)
+ {
+ LSN ulsn= all_active_trans[sid].undo_lsn;
+ /*
+ If the first record of that transaction is after 'rec', it's probably
+ because that transaction was found in the checkpoint record, and then
+ it's ok, we can forget about that transaction (we'll meet it later
+ again in the REDO phase) and replace it with the one in 'rec'.
+ */
+ if ((ulsn != LSN_IMPOSSIBLE) &&
+ (cmp_translog_addr(ulsn, rec->lsn) < 0))
+ {
+ char llbuf[22];
+ llstr(long_trid, llbuf);
+ eprint(tracef, "Found an old transaction long_trid %s short_trid %u"
+ " with same short id as this new transaction, and has neither"
+ " committed nor rollback (undo_lsn: (%lu,0x%lx))",
+ llbuf, sid, LSN_IN_PARTS(ulsn));
+ goto err;
+ }
+ }
+ long_trid= uint6korr(rec->header);
+ new_transaction(sid, long_trid, LSN_IMPOSSIBLE, LSN_IMPOSSIBLE);
+ goto end;
+err:
+ ALERT_USER();
+ return 1;
+end:
+ return 0;
+}
+
+
+static void new_transaction(uint16 sid, TrID long_id, LSN undo_lsn,
+ LSN first_undo_lsn)
+{
+ char llbuf[22];
+ all_active_trans[sid].long_trid= long_id;
+ llstr(long_id, llbuf);
+ tprint(tracef, "Transaction long_trid %s short_trid %u starts,"
+ " undo_lsn (%lu,0x%lx) first_undo_lsn (%lu,0x%lx)\n",
+ llbuf, sid, LSN_IN_PARTS(undo_lsn), LSN_IN_PARTS(first_undo_lsn));
+ all_active_trans[sid].undo_lsn= undo_lsn;
+ all_active_trans[sid].first_undo_lsn= first_undo_lsn;
+ set_if_bigger(max_long_trid, long_id);
+}
+
+
+prototype_redo_exec_hook_dummy(CHECKPOINT)
+{
+ /* the only checkpoint we care about was found via control file, ignore */
+ return 0;
+}
+
+
+prototype_redo_exec_hook_dummy(INCOMPLETE_GROUP)
+{
+ /* abortion was already made */
+ return 0;
+}
+
+
+prototype_redo_exec_hook(INCOMPLETE_LOG)
+{
+ MARIA_HA *info;
+ if (skip_DDLs)
+ {
+ tprint(tracef, "we skip DDLs\n");
+ return 0;
+ }
+ if ((info= get_MARIA_HA_from_REDO_record(rec)) == NULL)
+ {
+ /* no such table, don't need to warn */
+ return 0;
+ }
+ /*
+ Example of what can go wrong when replaying DDLs:
+ CREATE TABLE t (logged); INSERT INTO t VALUES(1) (logged);
+ ALTER TABLE t ... which does
+ CREATE a temporary table #sql... (logged)
+ INSERT data from t into #sql... (not logged)
+ RENAME #sql TO t (logged)
+ Removing tables by hand and replaying the log will leave in the
+ end an empty table "t": missing records. If after the RENAME an INSERT
+ into t was done, that row had number 1 in its page, executing the
+ REDO_INSERT_ROW_HEAD on the recreated empty t will fail (assertion
+ failure in _ma_apply_redo_insert_row_head_or_tail(): new data page is
+ created whereas rownr is not 0).
+ So when the server disables logging for ALTER TABLE or CREATE SELECT, it
+ logs LOGREC_INCOMPLETE_LOG to warn maria_read_log and then the user.
+
+ Another issue is that replaying of DDLs is not correct enough to work if
+ there was a crash during a DDL (see comment in execution of
+ REDO_RENAME_TABLE ).
+ */
+ tprint(tracef, "***WARNING: MySQL server currently logs no records"
+ " about insertion of data by ALTER TABLE and CREATE SELECT,"
+ " as they are not necessary for recovery;"
+ " present applying of log records may well not work.***\n");
+ recovery_warnings++;
+ return 0;
+}
+
+
+prototype_redo_exec_hook(REDO_CREATE_TABLE)
+{
+ File dfile= -1, kfile= -1;
+ char *linkname_ptr, filename[FN_REFLEN], *name, *ptr, *ptr2,
+ *data_file_name, *index_file_name;
+ uchar *kfile_header;
+ myf create_flag;
+ uint flags;
+ int error= 1, create_mode= O_RDWR | O_TRUNC, i;
+ MARIA_HA *info= NULL;
+ uint kfile_size_before_extension, keystart;
+
+ if (skip_DDLs)
+ {
+ tprint(tracef, "we skip DDLs\n");
+ return 0;
+ }
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+ name= (char *)log_record_buffer.str;
+ /*
+ TRUNCATE TABLE and REPAIR USE_FRM call maria_create(), so below we can
+ find a REDO_CREATE_TABLE for a table which we have open, that's why we
+ need to look for any open instances and close them first.
+ */
+ if (close_one_table(name, rec->lsn))
+ {
+ eprint(tracef, "Table '%s' got error %d on close", name, my_errno);
+ ALERT_USER();
+ goto end;
+ }
+ /* we try hard to get create_rename_lsn, to avoid mistakes if possible */
+ info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR);
+ if (info)
+ {
+ MARIA_SHARE *share= info->s;
+ /* check that we're not already using it */
+ if (share->reopen != 1)
+ {
+ eprint(tracef, "Table '%s is already open (reopen=%u)",
+ name, share->reopen);
+ ALERT_USER();
+ goto end;
+ }
+ DBUG_ASSERT(share->now_transactional == share->base.born_transactional);
+ if (!share->base.born_transactional)
+ {
+ /*
+ could be that transactional table was later dropped, and a non-trans
+ one was renamed to its name, thus create_rename_lsn is 0 and should
+ not be trusted.
+ */
+ tprint(tracef, "Table '%s' is not transactional, ignoring creation\n",
+ name);
+ ALERT_USER();
+ error= 0;
+ goto end;
+ }
+ if (cmp_translog_addr(share->state.create_rename_lsn, rec->lsn) >= 0)
+ {
+ tprint(tracef, "Table '%s' has create_rename_lsn (%lu,0x%lx) more "
+ "recent than record, ignoring creation",
+ name, LSN_IN_PARTS(share->state.create_rename_lsn));
+ error= 0;
+ goto end;
+ }
+ if (maria_is_crashed(info))
+ {
+ eprint(tracef, "Table '%s' is crashed, can't recreate it", name);
+ ALERT_USER();
+ goto end;
+ }
+ maria_close(info);
+ info= NULL;
+ }
+ else /* one or two files absent, or header corrupted... */
+ tprint(tracef, "Table '%s' can't be opened, probably does not exist\n",
+ name);
+ /* if does not exist, or is older, overwrite it */
+ ptr= name + strlen(name) + 1;
+ if ((flags= ptr[0] ? HA_DONT_TOUCH_DATA : 0))
+ tprint(tracef, ", we will only touch index file");
+ ptr++;
+ kfile_size_before_extension= uint2korr(ptr);
+ ptr+= 2;
+ keystart= uint2korr(ptr);
+ ptr+= 2;
+ kfile_header= (uchar *)ptr;
+ ptr+= kfile_size_before_extension;
+ /* set header lsns */
+ ptr2= (char *) kfile_header + sizeof(info->s->state.header) +
+ MARIA_FILE_CREATE_RENAME_LSN_OFFSET;
+ for (i= 0; i<3; i++)
+ {
+ lsn_store(ptr2, rec->lsn);
+ ptr2+= LSN_STORE_SIZE;
+ }
+ data_file_name= ptr;
+ ptr+= strlen(data_file_name) + 1;
+ index_file_name= ptr;
+ ptr+= strlen(index_file_name) + 1;
+ /** @todo handle symlinks */
+ if (data_file_name[0] || index_file_name[0])
+ {
+ eprint(tracef, "Table '%s' DATA|INDEX DIRECTORY clauses are not handled",
+ name);
+ goto end;
+ }
+ fn_format(filename, name, "", MARIA_NAME_IEXT,
+ (MY_UNPACK_FILENAME |
+ (flags & HA_DONT_TOUCH_DATA) ? MY_RETURN_REAL_PATH : 0) |
+ MY_APPEND_EXT);
+ linkname_ptr= NULL;
+ create_flag= MY_DELETE_OLD;
+ tprint(tracef, "Table '%s' creating as '%s'\n", name, filename);
+ if ((kfile= my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
+ MYF(MY_WME|create_flag))) < 0)
+ {
+ eprint(tracef, "Failed to create index file");
+ goto end;
+ }
+ if (my_pwrite(kfile, kfile_header,
+ kfile_size_before_extension, 0, MYF(MY_NABP|MY_WME)) ||
+ my_chsize(kfile, keystart, 0, MYF(MY_WME)))
+ {
+ eprint(tracef, "Failed to write to index file");
+ goto end;
+ }
+ if (!(flags & HA_DONT_TOUCH_DATA))
+ {
+ fn_format(filename,name,"", MARIA_NAME_DEXT,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ linkname_ptr= NULL;
+ create_flag=MY_DELETE_OLD;
+ if (((dfile=
+ my_create_with_symlink(linkname_ptr, filename, 0, create_mode,
+ MYF(MY_WME | create_flag))) < 0) ||
+ my_close(dfile, MYF(MY_WME)))
+ {
+ eprint(tracef, "Failed to create data file");
+ goto end;
+ }
+ /*
+ we now have an empty data file. To be able to
+ _ma_initialize_data_file() we need some pieces of the share to be
+ correctly filled. So we just open the table (fortunately, an empty
+ data file does not preclude this).
+ */
+ if (((info= maria_open(name, O_RDONLY, 0)) == NULL) ||
+ _ma_initialize_data_file(info->s, info->dfile.file))
+ {
+ eprint(tracef, "Failed to open new table or write to data file");
+ goto end;
+ }
+ }
+ error= 0;
+end:
+ if (kfile >= 0)
+ error|= my_close(kfile, MYF(MY_WME));
+ if (info != NULL)
+ error|= maria_close(info);
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_RENAME_TABLE)
+{
+ char *old_name, *new_name;
+ int error= 1;
+ MARIA_HA *info= NULL;
+ if (skip_DDLs)
+ {
+ tprint(tracef, "we skip DDLs\n");
+ return 0;
+ }
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+ old_name= (char *)log_record_buffer.str;
+ new_name= old_name + strlen(old_name) + 1;
+ tprint(tracef, "Table '%s' to rename to '%s'; old-name table ", old_name,
+ new_name);
+ /*
+ Here is why we skip CREATE/DROP/RENAME when doing a recovery from
+ ha_maria (whereas we do when called from maria_read_log). Consider:
+ CREATE TABLE t;
+ RENAME TABLE t to u;
+ DROP TABLE u;
+ RENAME TABLE v to u; # crash between index rename and data rename.
+ And do a Recovery (not removing tables beforehand).
+ Recovery replays CREATE, then RENAME: the maria_open("t") works,
+ maria_open("u") does not (no data file) so table "u" is considered
+ inexistent and so maria_rename() is done which overwrites u's index file,
+ which is lost. Ok, the data file (v.MAD) is still available, but only a
+ REPAIR USE_FRM can rebuild the index, which is unsafe and downtime.
+ So it is preferrable to not execute RENAME, and leave the "mess" of files,
+ rather than possibly destroy a file. DBA will manually rename files.
+ A safe recovery method would probably require checking the existence of
+ the index file and of the data file separately (not via maria_open()), and
+ maybe also to store a create_rename_lsn in the data file too
+ For now, all we risk is to leave the mess (half-renamed files) left by the
+ crash. We however sync files and directories at each file rename. The SQL
+ layer is anyway not crash-safe for DDLs (except the repartioning-related
+ ones).
+ We replay DDLs in maria_read_log to be able to recreate tables from
+ scratch. It means that "maria_read_log -a" should not be used on a
+ database which just crashed during a DDL. And also ALTER TABLE does not
+ log insertions of records into the temporary table, so replaying may
+ fail (grep for INCOMPLETE_LOG in files).
+ */
+ info= maria_open(old_name, O_RDONLY, HA_OPEN_FOR_REPAIR);
+ if (info)
+ {
+ MARIA_SHARE *share= info->s;
+ if (!share->base.born_transactional)
+ {
+ tprint(tracef, ", is not transactional, ignoring renaming\n");
+ ALERT_USER();
+ error= 0;
+ goto end;
+ }
+ if (cmp_translog_addr(share->state.create_rename_lsn, rec->lsn) >= 0)
+ {
+ tprint(tracef, ", has create_rename_lsn (%lu,0x%lx) more recent than"
+ " record, ignoring renaming",
+ LSN_IN_PARTS(share->state.create_rename_lsn));
+ error= 0;
+ goto end;
+ }
+ if (maria_is_crashed(info))
+ {
+ tprint(tracef, ", is crashed, can't rename it");
+ ALERT_USER();
+ goto end;
+ }
+ if (close_one_table(info->s->open_file_name.str, rec->lsn) ||
+ maria_close(info))
+ goto end;
+ info= NULL;
+ tprint(tracef, ", is ok for renaming; new-name table ");
+ }
+ else /* one or two files absent, or header corrupted... */
+ {
+ tprint(tracef, ", can't be opened, probably does not exist");
+ error= 0;
+ goto end;
+ }
+ /*
+ We must also check the create_rename_lsn of the 'new_name' table if it
+ exists: otherwise we may, with our rename which overwrites, destroy
+ another table. For example:
+ CREATE TABLE t;
+ RENAME t to u;
+ DROP TABLE u;
+ RENAME v to u; # v is an old table, its creation/insertions not in log
+ And start executing the log (without removing tables beforehand): creates
+ t, renames it to u (if not testing create_rename_lsn) thus overwriting
+ old-named v, drops u, and we are stuck, we have lost data.
+ */
+ info= maria_open(new_name, O_RDONLY, HA_OPEN_FOR_REPAIR);
+ if (info)
+ {
+ MARIA_SHARE *share= info->s;
+ /* We should not have open instances on this table. */
+ if (share->reopen != 1)
+ {
+ tprint(tracef, ", is already open (reopen=%u)\n", share->reopen);
+ ALERT_USER();
+ goto end;
+ }
+ if (!share->base.born_transactional)
+ {
+ tprint(tracef, ", is not transactional, ignoring renaming\n");
+ ALERT_USER();
+ goto drop;
+ }
+ if (cmp_translog_addr(share->state.create_rename_lsn, rec->lsn) >= 0)
+ {
+ tprint(tracef, ", has create_rename_lsn (%lu,0x%lx) more recent than"
+ " record, ignoring renaming",
+ LSN_IN_PARTS(share->state.create_rename_lsn));
+ /*
+ We have to drop the old_name table. Consider:
+ CREATE TABLE t;
+ CREATE TABLE v;
+ RENAME TABLE t to u;
+ DROP TABLE u;
+ RENAME TABLE v to u;
+ and apply the log without removing tables beforehand. t will be
+ created, v too; in REDO_RENAME u will be more recent, but we still
+ have to drop t otherwise it stays.
+ */
+ goto drop;
+ }
+ if (maria_is_crashed(info))
+ {
+ tprint(tracef, ", is crashed, can't rename it");
+ ALERT_USER();
+ goto end;
+ }
+ if (maria_close(info))
+ goto end;
+ info= NULL;
+ /* abnormal situation */
+ tprint(tracef, ", exists but is older than record, can't rename it");
+ goto end;
+ }
+ else /* one or two files absent, or header corrupted... */
+ tprint(tracef, ", can't be opened, probably does not exist");
+ tprint(tracef, ", renaming '%s'", old_name);
+ if (maria_rename(old_name, new_name))
+ {
+ eprint(tracef, "Failed to rename table");
+ goto end;
+ }
+ info= maria_open(new_name, O_RDONLY, 0);
+ if (info == NULL)
+ {
+ eprint(tracef, "Failed to open renamed table");
+ goto end;
+ }
+ if (_ma_update_state_lsns(info->s, rec->lsn, info->s->state.create_trid,
+ TRUE, TRUE))
+ goto end;
+ if (maria_close(info))
+ goto end;
+ info= NULL;
+ error= 0;
+ goto end;
+drop:
+ tprint(tracef, ", only dropping '%s'", old_name);
+ if (maria_delete_table(old_name))
+ {
+ eprint(tracef, "Failed to drop table");
+ goto end;
+ }
+ error= 0;
+ goto end;
+end:
+ tprint(tracef, "\n");
+ if (info != NULL)
+ error|= maria_close(info);
+ return error;
+}
+
+
+/*
+ The record may come from REPAIR, ALTER TABLE ENABLE KEYS, OPTIMIZE.
+*/
+prototype_redo_exec_hook(REDO_REPAIR_TABLE)
+{
+ int error= 1;
+ MARIA_HA *info;
+ HA_CHECK param;
+ char *name;
+ my_bool quick_repair;
+ DBUG_ENTER("exec_REDO_LOGREC_REDO_REPAIR_TABLE");
+
+ if (skip_DDLs)
+ {
+ /*
+ REPAIR is not exactly a DDL, but it manipulates files without logging
+ insertions into them.
+ */
+ tprint(tracef, "we skip DDLs\n");
+ DBUG_RETURN(0);
+ }
+ if ((info= get_MARIA_HA_from_REDO_record(rec)) == NULL)
+ DBUG_RETURN(0);
+
+ /*
+ Otherwise, the mapping is newer than the table, and our record is newer
+ than the mapping, so we can repair.
+ */
+ tprint(tracef, " repairing...\n");
+
+ maria_chk_init(&param);
+ param.isam_file_name= name= info->s->open_file_name.str;
+ param.testflag= uint8korr(rec->header + FILEID_STORE_SIZE);
+ param.tmpdir= maria_tmpdir;
+ DBUG_ASSERT(maria_tmpdir);
+
+ info->s->state.key_map= uint8korr(rec->header + FILEID_STORE_SIZE + 8);
+ quick_repair= test(param.testflag & T_QUICK);
+
+ if (param.testflag & T_REP_PARALLEL)
+ {
+ if (maria_repair_parallel(&param, info, name, quick_repair))
+ goto end;
+ }
+ else if (param.testflag & T_REP_BY_SORT)
+ {
+ if (maria_repair_by_sort(&param, info, name, quick_repair))
+ goto end;
+ }
+ else if (maria_repair(&param, info, name, quick_repair))
+ goto end;
+
+ if (_ma_update_state_lsns(info->s, rec->lsn, trnman_get_min_safe_trid(),
+ TRUE, !(param.testflag & T_NO_CREATE_RENAME_LSN)))
+ goto end;
+ error= 0;
+
+end:
+ DBUG_RETURN(error);
+}
+
+
+prototype_redo_exec_hook(REDO_DROP_TABLE)
+{
+ char *name;
+ int error= 1;
+ MARIA_HA *info;
+ if (skip_DDLs)
+ {
+ tprint(tracef, "we skip DDLs\n");
+ return 0;
+ }
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ name= (char *)log_record_buffer.str;
+ tprint(tracef, "Table '%s'", name);
+ info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR);
+ if (info)
+ {
+ MARIA_SHARE *share= info->s;
+ if (!share->base.born_transactional)
+ {
+ tprint(tracef, ", is not transactional, ignoring removal\n");
+ ALERT_USER();
+ error= 0;
+ goto end;
+ }
+ if (cmp_translog_addr(share->state.create_rename_lsn, rec->lsn) >= 0)
+ {
+ tprint(tracef, ", has create_rename_lsn (%lu,0x%lx) more recent than"
+ " record, ignoring removal",
+ LSN_IN_PARTS(share->state.create_rename_lsn));
+ error= 0;
+ goto end;
+ }
+ if (maria_is_crashed(info))
+ {
+ tprint(tracef, ", is crashed, can't drop it");
+ ALERT_USER();
+ goto end;
+ }
+ if (close_one_table(info->s->open_file_name.str, rec->lsn) ||
+ maria_close(info))
+ goto end;
+ info= NULL;
+ /* if it is older, or its header is corrupted, drop it */
+ tprint(tracef, ", dropping '%s'", name);
+ if (maria_delete_table(name))
+ {
+ eprint(tracef, "Failed to drop table");
+ goto end;
+ }
+ }
+ else /* one or two files absent, or header corrupted... */
+ tprint(tracef,", can't be opened, probably does not exist");
+ error= 0;
+end:
+ tprint(tracef, "\n");
+ if (info != NULL)
+ error|= maria_close(info);
+ return error;
+}
+
+
+prototype_redo_exec_hook(FILE_ID)
+{
+ uint16 sid;
+ int error= 1;
+ const char *name;
+ MARIA_HA *info;
+ DBUG_ENTER("exec_REDO_LOGREC_FILE_ID");
+
+ if (cmp_translog_addr(rec->lsn, checkpoint_start) < 0)
+ {
+ /*
+ If that mapping was still true at checkpoint time, it was found in
+ checkpoint record, no need to recreate it. If that mapping had ended at
+ checkpoint time (table was closed or repaired), a flush and force
+ happened and so mapping is not needed.
+ */
+ tprint(tracef, "ignoring because before checkpoint\n");
+ DBUG_RETURN(0);
+ }
+
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+ sid= fileid_korr(log_record_buffer.str);
+ info= all_tables[sid].info;
+ if (info != NULL)
+ {
+ tprint(tracef, " Closing table '%s'\n", info->s->open_file_name.str);
+ prepare_table_for_close(info, rec->lsn);
+ if (maria_close(info))
+ {
+ eprint(tracef, "Failed to close table");
+ goto end;
+ }
+ all_tables[sid].info= NULL;
+ }
+ name= (char *)log_record_buffer.str + FILEID_STORE_SIZE;
+ if (new_table(sid, name, rec->lsn))
+ goto end;
+ error= 0;
+end:
+ DBUG_RETURN(error);
+}
+
+
+static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
+{
+ /*
+ -1 (skip table): close table and return 0;
+ 1 (error): close table and return 1;
+ 0 (success): leave table open and return 0.
+ */
+ int error= 1;
+ MARIA_HA *info;
+ MARIA_SHARE *share;
+ my_off_t dfile_len, kfile_len;
+
+ checkpoint_useful= TRUE;
+ if ((name == NULL) || (name[0] == 0))
+ {
+ /*
+ we didn't use DBUG_ASSERT() because such record corruption could
+ silently pass in the "info == NULL" test below.
+ */
+ tprint(tracef, ", record is corrupted");
+ info= NULL;
+ goto end;
+ }
+ tprint(tracef, "Table '%s', id %u", name, sid);
+ info= maria_open(name, O_RDWR, HA_OPEN_FOR_REPAIR);
+ if (info == NULL)
+ {
+ tprint(tracef, ", is absent (must have been dropped later?)"
+ " or its header is so corrupted that we cannot open it;"
+ " we skip it");
+ error= 0;
+ goto end;
+ }
+ share= info->s;
+ /* check that we're not already using it */
+ if (share->reopen != 1)
+ {
+ tprint(tracef, ", is already open (reopen=%u)\n", share->reopen);
+ /*
+ It could be that we have in the log
+ FILE_ID(t1,10) ... (t1 was flushed) ... FILE_ID(t1,12);
+ */
+ if (close_one_table(share->open_file_name.str, lsn_of_file_id))
+ goto end;
+ }
+ if (!share->base.born_transactional)
+ {
+ /*
+ This can happen if one converts a transactional table to a
+ not transactional table
+ */
+ tprint(tracef, ", is not transactional. Ignoring open request");
+ error= -1;
+ goto end;
+ }
+ if (cmp_translog_addr(lsn_of_file_id, share->state.create_rename_lsn) <= 0)
+ {
+ tprint(tracef, ", has create_rename_lsn (%lu,0x%lx) more recent than"
+ " LOGREC_FILE_ID's LSN (%lu,0x%lx), ignoring open request",
+ LSN_IN_PARTS(share->state.create_rename_lsn),
+ LSN_IN_PARTS(lsn_of_file_id));
+ error= -1;
+ goto end;
+ /*
+ Note that we tested that before testing corruption; a recent corrupted
+ table is not a blocker for the present log record.
+ */
+ }
+ if (maria_is_crashed(info))
+ {
+ eprint(tracef, "Table '%s' is crashed, skipping it. Please repair it with"
+ " maria_chk -r", share->open_file_name.str);
+ error= -1; /* not fatal, try with other tables */
+ goto end;
+ /*
+ Note that if a first recovery fails to apply a REDO, it marks the table
+ corrupted and stops the entire recovery. A second recovery will find the
+ table is marked corrupted and skip it (and thus possibly handle other
+ tables).
+ */
+ }
+ /* don't log any records for this work */
+ _ma_tmp_disable_logging_for_table(info, FALSE);
+ /* execution of some REDO records relies on data_file_length */
+ dfile_len= my_seek(info->dfile.file, 0, SEEK_END, MYF(MY_WME));
+ kfile_len= my_seek(info->s->kfile.file, 0, SEEK_END, MYF(MY_WME));
+ if ((dfile_len == MY_FILEPOS_ERROR) ||
+ (kfile_len == MY_FILEPOS_ERROR))
+ {
+ tprint(tracef, ", length unknown\n");
+ goto end;
+ }
+ if (share->state.state.data_file_length != dfile_len)
+ {
+ tprint(tracef, ", has wrong state.data_file_length (fixing it)");
+ share->state.state.data_file_length= dfile_len;
+ }
+ if (share->state.state.key_file_length != kfile_len)
+ {
+ tprint(tracef, ", has wrong state.key_file_length (fixing it)");
+ share->state.state.key_file_length= kfile_len;
+ }
+ if ((dfile_len % share->block_size) || (kfile_len % share->block_size))
+ {
+ tprint(tracef, ", has too short last page\n");
+ /* Recovery will fix this, no error */
+ ALERT_USER();
+ }
+ /*
+ This LSN serves in this situation; assume log is:
+ FILE_ID(6->"t2") REDO_INSERT(6) FILE_ID(6->"t1") CHECKPOINT(6->"t1")
+ then crash, checkpoint record is parsed and opens "t1" with id 6; assume
+ REDO phase starts from the REDO_INSERT above: it will wrongly try to
+ update a page of "t1". With this LSN below, REDO_INSERT can realize the
+ mapping is newer than itself, and not execute.
+ Same example is possible with UNDO_INSERT (update of the state).
+ */
+ info->s->lsn_of_file_id= lsn_of_file_id;
+ all_tables[sid].info= info;
+ /*
+ We don't set info->s->id, it would be useless (no logging in REDO phase);
+ if you change that, know that some records in REDO phase call
+ _ma_update_state_lsns() which resets info->s->id.
+ */
+ tprint(tracef, ", opened");
+ error= 0;
+end:
+ tprint(tracef, "\n");
+ if (error)
+ {
+ if (info != NULL)
+ maria_close(info);
+ if (error == -1)
+ error= 0;
+ }
+ return error;
+}
+
+/*
+ NOTE
+ This is called for REDO_INSERT_ROW_HEAD and READ_NEW_ROW_HEAD
+*/
+
+prototype_redo_exec_hook(REDO_INSERT_ROW_HEAD)
+{
+ int error= 1;
+ uchar *buff= NULL;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ {
+ /*
+ Table was skipped at open time (because later dropped/renamed, not
+ transactional, or create_rename_lsn newer than LOGREC_FILE_ID), or
+ record was skipped due to skip_redo_lsn; it is not an error.
+ */
+ return 0;
+ }
+ /*
+ Note that REDO is per page, we still consider it if its transaction
+ committed long ago and is unknown.
+ */
+ /*
+ If REDO's LSN is > page's LSN (read from disk), we are going to modify the
+ page and change its LSN. The normal runtime code stores the UNDO's LSN
+ into the page. Here storing the REDO's LSN (rec->lsn) would work
+ (we are not writing to the log here, so don't have to "flush up to UNDO's
+ LSN"). But in a test scenario where we do updates at runtime, then remove
+ tables, apply the log and check that this results in the same table as at
+ runtime, putting the same LSN as runtime had done will decrease
+ differences. So we use the UNDO's LSN which is current_group_end_lsn.
+ */
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL)
+ {
+ eprint(tracef, "Failed to read allocate buffer for record");
+ goto end;
+ }
+ if (translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+ buff= log_record_buffer.str;
+ if (_ma_apply_redo_insert_row_head_or_tail(info, current_group_end_lsn,
+ HEAD_PAGE,
+ (rec->type ==
+ LOGREC_REDO_NEW_ROW_HEAD),
+ buff + FILEID_STORE_SIZE,
+ buff +
+ FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE +
+ DIRPOS_STORE_SIZE,
+ rec->record_length -
+ (FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE +
+ DIRPOS_STORE_SIZE)))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+/*
+ NOTE
+ This is called for REDO_INSERT_ROW_TAIL and READ_NEW_ROW_TAIL
+*/
+
+prototype_redo_exec_hook(REDO_INSERT_ROW_TAIL)
+{
+ int error= 1;
+ uchar *buff;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+ buff= log_record_buffer.str;
+ if (_ma_apply_redo_insert_row_head_or_tail(info, current_group_end_lsn,
+ TAIL_PAGE,
+ (rec->type ==
+ LOGREC_REDO_NEW_ROW_TAIL),
+ buff + FILEID_STORE_SIZE,
+ buff +
+ FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE +
+ DIRPOS_STORE_SIZE,
+ rec->record_length -
+ (FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE +
+ DIRPOS_STORE_SIZE)))
+ goto end;
+ error= 0;
+
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_INSERT_ROW_BLOBS)
+{
+ int error= 1;
+ uchar *buff;
+ uint number_of_blobs, number_of_ranges;
+ pgcache_page_no_t first_page, last_page;
+ char llbuf1[22], llbuf2[22];
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+ buff= log_record_buffer.str;
+ if (_ma_apply_redo_insert_row_blobs(info, current_group_end_lsn,
+ buff, rec->lsn, &number_of_blobs,
+ &number_of_ranges,
+ &first_page, &last_page))
+ goto end;
+ llstr(first_page, llbuf1);
+ llstr(last_page, llbuf2);
+ tprint(tracef, " %u blobs %u ranges, first page %s last %s",
+ number_of_blobs, number_of_ranges, llbuf1, llbuf2);
+
+ error= 0;
+
+end:
+ tprint(tracef, " \n");
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_PURGE_ROW_HEAD)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ if (_ma_apply_redo_purge_row_head_or_tail(info, current_group_end_lsn,
+ HEAD_PAGE,
+ rec->header + FILEID_STORE_SIZE))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_PURGE_ROW_TAIL)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ if (_ma_apply_redo_purge_row_head_or_tail(info, current_group_end_lsn,
+ TAIL_PAGE,
+ rec->header + FILEID_STORE_SIZE))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_FREE_BLOCKS)
+{
+ int error= 1;
+ uchar *buff;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ enlarge_buffer(rec);
+
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+
+ buff= log_record_buffer.str;
+ if (_ma_apply_redo_free_blocks(info, current_group_end_lsn,
+ buff + FILEID_STORE_SIZE))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_FREE_HEAD_OR_TAIL)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+
+ if (_ma_apply_redo_free_head_or_tail(info, current_group_end_lsn,
+ rec->header + FILEID_STORE_SIZE))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_DELETE_ALL)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ tprint(tracef, " deleting all %lu rows\n",
+ (ulong)info->s->state.state.records);
+ if (maria_delete_all_rows(info))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_INDEX)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ enlarge_buffer(rec);
+
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+
+ if (_ma_apply_redo_index(info, current_group_end_lsn,
+ log_record_buffer.str + FILEID_STORE_SIZE,
+ rec->record_length - FILEID_STORE_SIZE))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+prototype_redo_exec_hook(REDO_INDEX_NEW_PAGE)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ enlarge_buffer(rec);
+
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+
+ if (_ma_apply_redo_index_new_page(info, current_group_end_lsn,
+ log_record_buffer.str + FILEID_STORE_SIZE,
+ rec->record_length - FILEID_STORE_SIZE))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_INDEX_FREE_PAGE)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+
+ if (_ma_apply_redo_index_free_page(info, current_group_end_lsn,
+ rec->header + FILEID_STORE_SIZE))
+ goto end;
+ error= 0;
+end:
+ return error;
+}
+
+
+prototype_redo_exec_hook(REDO_BITMAP_NEW_PAGE)
+{
+ int error= 1;
+ MARIA_HA *info= get_MARIA_HA_from_REDO_record(rec);
+ if (info == NULL)
+ return 0;
+ enlarge_buffer(rec);
+
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ goto end;
+ }
+
+ if (cmp_translog_addr(rec->lsn, checkpoint_start) >= 0)
+ {
+ /*
+ Record is potentially after the bitmap flush made by Checkpoint, so has
+ to be replayed. It may overwrite a more recent state but that will be
+ corrected by all upcoming REDOs for data pages.
+ If the condition is false, we must not apply the record: it is unneeded
+ and nocive (may not be corrected as REDOs can be skipped due to
+ dirty-pages list).
+ */
+ if (_ma_apply_redo_bitmap_new_page(info, current_group_end_lsn,
+ log_record_buffer.str +
+ FILEID_STORE_SIZE))
+ goto end;
+ }
+ error= 0;
+end:
+ return error;
+}
+
+
+static inline void set_undo_lsn_for_active_trans(uint16 short_trid, LSN lsn)
+{
+ if (all_active_trans[short_trid].long_trid == 0)
+ {
+ /* transaction unknown, so has committed or fully rolled back long ago */
+ return;
+ }
+ all_active_trans[short_trid].undo_lsn= lsn;
+ if (all_active_trans[short_trid].first_undo_lsn == LSN_IMPOSSIBLE)
+ all_active_trans[short_trid].first_undo_lsn= lsn;
+}
+
+
+prototype_redo_exec_hook(UNDO_ROW_INSERT)
+{
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ MARIA_SHARE *share;
+
+ set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
+ if (info == NULL)
+ {
+ /*
+ Note that we set undo_lsn anyway. So that if the transaction is later
+ rolled back, this UNDO is tried for execution and we get a warning (as
+ it would then be abnormal that info==NULL).
+ */
+ return 0;
+ }
+ share= info->s;
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
+ {
+ tprint(tracef, " state has LSN (%lu,0x%lx) older than record, updating"
+ " rows' count\n", LSN_IN_PARTS(share->state.is_of_horizon));
+ share->state.state.records++;
+ if (share->calc_checksum)
+ {
+ uchar buff[HA_CHECKSUM_STORE_SIZE];
+ if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
+ HA_CHECKSUM_STORE_SIZE)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ share->state.state.checksum+= ha_checksum_korr(buff);
+ }
+ info->s->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+ }
+ tprint(tracef, " rows' count %lu\n", (ulong)info->s->state.state.records);
+ /* Unpin all pages, stamp them with UNDO's LSN */
+ _ma_unpin_all_pages(info, rec->lsn);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(UNDO_ROW_DELETE)
+{
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ MARIA_SHARE *share;
+
+ set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
+ if (info == NULL)
+ return 0;
+ share= info->s;
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
+ {
+ tprint(tracef, " state older than record\n");
+ share->state.state.records--;
+ if (share->calc_checksum)
+ {
+ uchar buff[HA_CHECKSUM_STORE_SIZE];
+ if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE + 2 +
+ PAGERANGE_STORE_SIZE,
+ HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
+ HA_CHECKSUM_STORE_SIZE)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ share->state.state.checksum+= ha_checksum_korr(buff);
+ }
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+ }
+ tprint(tracef, " rows' count %lu\n", (ulong)share->state.state.records);
+ _ma_unpin_all_pages(info, rec->lsn);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(UNDO_ROW_UPDATE)
+{
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ MARIA_SHARE *share;
+
+ set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
+ if (info == NULL)
+ return 0;
+ share= info->s;
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
+ {
+ if (share->calc_checksum)
+ {
+ uchar buff[HA_CHECKSUM_STORE_SIZE];
+ if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
+ HA_CHECKSUM_STORE_SIZE, buff, NULL) !=
+ HA_CHECKSUM_STORE_SIZE)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ share->state.state.checksum+= ha_checksum_korr(buff);
+ }
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+ }
+ _ma_unpin_all_pages(info, rec->lsn);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(UNDO_KEY_INSERT)
+{
+ MARIA_HA *info;
+ MARIA_SHARE *share;
+
+ set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
+ if (!(info= get_MARIA_HA_from_UNDO_record(rec)))
+ return 0;
+ share= info->s;
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
+ {
+ const uchar *ptr= rec->header + LSN_STORE_SIZE + FILEID_STORE_SIZE;
+ uint keynr= key_nr_korr(ptr);
+ if (share->base.auto_key == (keynr + 1)) /* it's auto-increment */
+ {
+ const HA_KEYSEG *keyseg= info->s->keyinfo[keynr].seg;
+ ulonglong value;
+ char llbuf[22];
+ uchar *to;
+ tprint(tracef, " state older than record\n");
+ /* we read the record to find the auto_increment value */
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ to= log_record_buffer.str + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ KEY_NR_STORE_SIZE;
+ if (keyseg->flag & HA_SWAP_KEY)
+ {
+ /* We put key from log record to "data record" packing format... */
+ uchar reversed[MARIA_MAX_KEY_BUFF];
+ uchar *key_ptr= to;
+ uchar *key_end= key_ptr + keyseg->length;
+ to= reversed + keyseg->length;
+ do
+ {
+ *--to= *key_ptr++;
+ } while (key_ptr != key_end);
+ /* ... so that we can read it with: */
+ }
+ value= ma_retrieve_auto_increment(to, keyseg->type);
+ set_if_bigger(share->state.auto_increment, value);
+ llstr(share->state.auto_increment, llbuf);
+ tprint(tracef, " auto-inc %s\n", llbuf);
+ }
+ }
+ _ma_unpin_all_pages(info, rec->lsn);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(UNDO_KEY_DELETE)
+{
+ MARIA_HA *info;
+
+ set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
+ if (!(info= get_MARIA_HA_from_UNDO_record(rec)))
+ return 0;
+ _ma_unpin_all_pages(info, rec->lsn);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(UNDO_KEY_DELETE_WITH_ROOT)
+{
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ MARIA_SHARE *share;
+
+ set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
+ if (info == NULL)
+ return 0;
+ share= info->s;
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
+ {
+ uint key_nr;
+ my_off_t page;
+ key_nr= key_nr_korr(rec->header + LSN_STORE_SIZE + FILEID_STORE_SIZE);
+ page= page_korr(rec->header + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ KEY_NR_STORE_SIZE);
+ share->state.key_root[key_nr]= (page == IMPOSSIBLE_PAGE_NO ?
+ HA_OFFSET_ERROR :
+ page * share->block_size);
+ }
+ _ma_unpin_all_pages(info, rec->lsn);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(UNDO_BULK_INSERT)
+{
+ /*
+ If the repair finished it wrote and sync the state. If it didn't finish,
+ we are going to empty the table and that will fix the state.
+ */
+ set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(IMPORTED_TABLE)
+{
+ char *name;
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ name= (char *)log_record_buffer.str;
+ tprint(tracef, "Table '%s' was imported (auto-zerofilled) in this Maria instance\n", name);
+ return 0;
+}
+
+
+prototype_redo_exec_hook(COMMIT)
+{
+ uint16 sid= rec->short_trid;
+ TrID long_trid= all_active_trans[sid].long_trid;
+ char llbuf[22];
+ if (long_trid == 0)
+ {
+ tprint(tracef, "We don't know about transaction with short_trid %u;"
+ "it probably committed long ago, forget it\n", sid);
+ bzero(&all_active_trans[sid], sizeof(all_active_trans[sid]));
+ return 0;
+ }
+ llstr(long_trid, llbuf);
+ tprint(tracef, "Transaction long_trid %s short_trid %u committed\n",
+ llbuf, sid);
+ bzero(&all_active_trans[sid], sizeof(all_active_trans[sid]));
+#ifdef MARIA_VERSIONING
+ /*
+ if real recovery:
+ transaction was committed, move it to some separate list for later
+ purging (but don't purge now! purging may have been started before, we
+ may find REDO_PURGE records soon).
+ */
+#endif
+ return 0;
+}
+
+prototype_redo_exec_hook(CLR_END)
+{
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ MARIA_SHARE *share;
+ LSN previous_undo_lsn;
+ enum translog_record_type undone_record_type;
+ const LOG_DESC *log_desc;
+ my_bool row_entry= 0;
+ uchar *logpos;
+ DBUG_ENTER("exec_REDO_LOGREC_CLR_END");
+
+ previous_undo_lsn= lsn_korr(rec->header);
+ undone_record_type=
+ clr_type_korr(rec->header + LSN_STORE_SIZE + FILEID_STORE_SIZE);
+ log_desc= &log_record_type_descriptor[undone_record_type];
+
+ set_undo_lsn_for_active_trans(rec->short_trid, previous_undo_lsn);
+ if (info == NULL)
+ DBUG_RETURN(0);
+ share= info->s;
+ tprint(tracef, " CLR_END was about %s, undo_lsn now LSN (%lu,0x%lx)\n",
+ log_desc->name, LSN_IN_PARTS(previous_undo_lsn));
+
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ logpos= (log_record_buffer.str + LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ CLR_TYPE_STORE_SIZE);
+
+ if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0)
+ {
+ tprint(tracef, " state older than record\n");
+ switch (undone_record_type) {
+ case LOGREC_UNDO_ROW_DELETE:
+ row_entry= 1;
+ share->state.state.records++;
+ break;
+ case LOGREC_UNDO_ROW_INSERT:
+ share->state.state.records--;
+ share->state.changed|= STATE_NOT_OPTIMIZED_ROWS;
+ row_entry= 1;
+ break;
+ case LOGREC_UNDO_ROW_UPDATE:
+ row_entry= 1;
+ break;
+ case LOGREC_UNDO_KEY_INSERT:
+ case LOGREC_UNDO_KEY_DELETE:
+ break;
+ case LOGREC_UNDO_KEY_INSERT_WITH_ROOT:
+ case LOGREC_UNDO_KEY_DELETE_WITH_ROOT:
+ {
+ uint key_nr;
+ my_off_t page;
+ key_nr= key_nr_korr(logpos);
+ page= page_korr(logpos + KEY_NR_STORE_SIZE);
+ share->state.key_root[key_nr]= (page == IMPOSSIBLE_PAGE_NO ?
+ HA_OFFSET_ERROR :
+ page * share->block_size);
+ break;
+ }
+ case LOGREC_UNDO_BULK_INSERT:
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ if (row_entry && share->calc_checksum)
+ share->state.state.checksum+= ha_checksum_korr(logpos);
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+ }
+ if (row_entry)
+ tprint(tracef, " rows' count %lu\n", (ulong)share->state.state.records);
+ _ma_unpin_all_pages(info, rec->lsn);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Hock to print debug information (like MySQL query)
+*/
+
+prototype_redo_exec_hook(DEBUG_INFO)
+{
+ uchar *data;
+ enum translog_debug_info_type debug_info;
+
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record debug record");
+ return 1;
+ }
+ debug_info= (enum translog_debug_info_type) log_record_buffer.str[0];
+ data= log_record_buffer.str + 1;
+ switch (debug_info) {
+ case LOGREC_DEBUG_INFO_QUERY:
+ tprint(tracef, "Query: %s\n", (char*) data);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
+
+/**
+ In some cases we have to skip execution of an UNDO record during the UNDO
+ phase.
+*/
+
+static void skip_undo_record(LSN previous_undo_lsn, TRN *trn)
+{
+ trn->undo_lsn= previous_undo_lsn;
+ if (previous_undo_lsn == LSN_IMPOSSIBLE) /* has fully rolled back */
+ trn->first_undo_lsn= LSN_WITH_FLAGS_TO_FLAGS(trn->first_undo_lsn);
+ skipped_undo_phase++;
+}
+
+
+prototype_undo_exec_hook(UNDO_ROW_INSERT)
+{
+ my_bool error;
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ LSN previous_undo_lsn= lsn_korr(rec->header);
+ MARIA_SHARE *share;
+ const uchar *record_ptr;
+
+ if (info == NULL)
+ {
+ /*
+ Unlike for REDOs, if the table was skipped it is abnormal; we have a
+ transaction to rollback which used this table, as it is not rolled back
+ it was supposed to hold this table and so the table should still be
+ there. Skip it (user may have repaired the table with maria_chk because
+ it was so badly corrupted that a previous recovery failed) but warn.
+ */
+ skip_undo_record(previous_undo_lsn, trn);
+ return 0;
+ }
+ share= info->s;
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_OPTIMIZED_ROWS | STATE_NOT_ZEROFILLED |
+ STATE_NOT_MOVABLE);
+ record_ptr= rec->header;
+ if (share->calc_checksum)
+ {
+ /*
+ We need to read more of the record to put the checksum into the record
+ buffer used by _ma_apply_undo_row_insert().
+ If the table has no live checksum, rec->header will be enough.
+ */
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+ record_ptr= log_record_buffer.str;
+ }
+
+ info->trn= trn;
+ error= _ma_apply_undo_row_insert(info, previous_undo_lsn,
+ record_ptr + LSN_STORE_SIZE +
+ FILEID_STORE_SIZE);
+ info->trn= 0;
+ /* trn->undo_lsn is updated in an inwrite_hook when writing the CLR_END */
+ tprint(tracef, " rows' count %lu\n", (ulong)info->s->state.state.records);
+ tprint(tracef, " undo_lsn now LSN (%lu,0x%lx)\n",
+ LSN_IN_PARTS(trn->undo_lsn));
+ return error;
+}
+
+
+prototype_undo_exec_hook(UNDO_ROW_DELETE)
+{
+ my_bool error;
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ LSN previous_undo_lsn= lsn_korr(rec->header);
+ MARIA_SHARE *share;
+
+ if (info == NULL)
+ {
+ skip_undo_record(previous_undo_lsn, trn);
+ return 0;
+ }
+
+ share= info->s;
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+
+ info->trn= trn;
+ error= _ma_apply_undo_row_delete(info, previous_undo_lsn,
+ log_record_buffer.str + LSN_STORE_SIZE +
+ FILEID_STORE_SIZE,
+ rec->record_length -
+ (LSN_STORE_SIZE + FILEID_STORE_SIZE));
+ info->trn= 0;
+ tprint(tracef, " rows' count %lu\n undo_lsn now LSN (%lu,0x%lx)\n",
+ (ulong)share->state.state.records, LSN_IN_PARTS(trn->undo_lsn));
+ return error;
+}
+
+
+prototype_undo_exec_hook(UNDO_ROW_UPDATE)
+{
+ my_bool error;
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ LSN previous_undo_lsn= lsn_korr(rec->header);
+ MARIA_SHARE *share;
+
+ if (info == NULL)
+ {
+ skip_undo_record(previous_undo_lsn, trn);
+ return 0;
+ }
+
+ share= info->s;
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+
+ info->trn= trn;
+ error= _ma_apply_undo_row_update(info, previous_undo_lsn,
+ log_record_buffer.str + LSN_STORE_SIZE +
+ FILEID_STORE_SIZE,
+ rec->record_length -
+ (LSN_STORE_SIZE + FILEID_STORE_SIZE));
+ info->trn= 0;
+ tprint(tracef, " undo_lsn now LSN (%lu,0x%lx)\n",
+ LSN_IN_PARTS(trn->undo_lsn));
+ return error;
+}
+
+
+prototype_undo_exec_hook(UNDO_KEY_INSERT)
+{
+ my_bool error;
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ LSN previous_undo_lsn= lsn_korr(rec->header);
+ MARIA_SHARE *share;
+
+ if (info == NULL)
+ {
+ skip_undo_record(previous_undo_lsn, trn);
+ return 0;
+ }
+
+ share= info->s;
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+
+ info->trn= trn;
+ error= _ma_apply_undo_key_insert(info, previous_undo_lsn,
+ log_record_buffer.str + LSN_STORE_SIZE +
+ FILEID_STORE_SIZE,
+ rec->record_length - LSN_STORE_SIZE -
+ FILEID_STORE_SIZE);
+ info->trn= 0;
+ /* trn->undo_lsn is updated in an inwrite_hook when writing the CLR_END */
+ tprint(tracef, " undo_lsn now LSN (%lu,0x%lx)\n",
+ LSN_IN_PARTS(trn->undo_lsn));
+ return error;
+}
+
+
+prototype_undo_exec_hook(UNDO_KEY_DELETE)
+{
+ my_bool error;
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ LSN previous_undo_lsn= lsn_korr(rec->header);
+ MARIA_SHARE *share;
+
+ if (info == NULL)
+ {
+ skip_undo_record(previous_undo_lsn, trn);
+ return 0;
+ }
+
+ share= info->s;
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+
+ info->trn= trn;
+ error= _ma_apply_undo_key_delete(info, previous_undo_lsn,
+ log_record_buffer.str + LSN_STORE_SIZE +
+ FILEID_STORE_SIZE,
+ rec->record_length - LSN_STORE_SIZE -
+ FILEID_STORE_SIZE, FALSE);
+ info->trn= 0;
+ /* trn->undo_lsn is updated in an inwrite_hook when writing the CLR_END */
+ tprint(tracef, " undo_lsn now LSN (%lu,0x%lx)\n",
+ LSN_IN_PARTS(trn->undo_lsn));
+ return error;
+}
+
+
+prototype_undo_exec_hook(UNDO_KEY_DELETE_WITH_ROOT)
+{
+ my_bool error;
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ LSN previous_undo_lsn= lsn_korr(rec->header);
+ MARIA_SHARE *share;
+
+ if (info == NULL)
+ {
+ skip_undo_record(previous_undo_lsn, trn);
+ return 0;
+ }
+
+ share= info->s;
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+
+ enlarge_buffer(rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec->lsn, 0, rec->record_length,
+ log_record_buffer.str, NULL) !=
+ rec->record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return 1;
+ }
+
+ info->trn= trn;
+ error= _ma_apply_undo_key_delete(info, previous_undo_lsn,
+ log_record_buffer.str + LSN_STORE_SIZE +
+ FILEID_STORE_SIZE,
+ rec->record_length - LSN_STORE_SIZE -
+ FILEID_STORE_SIZE, TRUE);
+ info->trn= 0;
+ /* trn->undo_lsn is updated in an inwrite_hook when writing the CLR_END */
+ tprint(tracef, " undo_lsn now LSN (%lu,0x%lx)\n",
+ LSN_IN_PARTS(trn->undo_lsn));
+ return error;
+}
+
+
+prototype_undo_exec_hook(UNDO_BULK_INSERT)
+{
+ my_bool error;
+ MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec);
+ LSN previous_undo_lsn= lsn_korr(rec->header);
+ MARIA_SHARE *share;
+
+ if (info == NULL)
+ {
+ skip_undo_record(previous_undo_lsn, trn);
+ return 0;
+ }
+
+ share= info->s;
+ share->state.changed|= (STATE_CHANGED | STATE_NOT_ANALYZED |
+ STATE_NOT_ZEROFILLED | STATE_NOT_MOVABLE);
+
+ info->trn= trn;
+ error= _ma_apply_undo_bulk_insert(info, previous_undo_lsn);
+ info->trn= 0;
+ /* trn->undo_lsn is updated in an inwrite_hook when writing the CLR_END */
+ tprint(tracef, " undo_lsn now LSN (%lu,0x%lx)\n",
+ LSN_IN_PARTS(trn->undo_lsn));
+ return error;
+}
+
+
+static int run_redo_phase(LSN lsn, enum maria_apply_log_way apply)
+{
+ TRANSLOG_HEADER_BUFFER rec;
+ struct st_translog_scanner_data scanner;
+ int len;
+ uint i;
+
+ /* install hooks for execution */
+#define install_redo_exec_hook(R) \
+ log_record_type_descriptor[LOGREC_ ## R].record_execute_in_redo_phase= \
+ exec_REDO_LOGREC_ ## R;
+#define install_redo_exec_hook_shared(R,S) \
+ log_record_type_descriptor[LOGREC_ ## R].record_execute_in_redo_phase= \
+ exec_REDO_LOGREC_ ## S;
+#define install_undo_exec_hook(R) \
+ log_record_type_descriptor[LOGREC_ ## R].record_execute_in_undo_phase= \
+ exec_UNDO_LOGREC_ ## R;
+ install_redo_exec_hook(LONG_TRANSACTION_ID);
+ install_redo_exec_hook(CHECKPOINT);
+ install_redo_exec_hook(REDO_CREATE_TABLE);
+ install_redo_exec_hook(REDO_RENAME_TABLE);
+ install_redo_exec_hook(REDO_REPAIR_TABLE);
+ install_redo_exec_hook(REDO_DROP_TABLE);
+ install_redo_exec_hook(FILE_ID);
+ install_redo_exec_hook(INCOMPLETE_LOG);
+ install_redo_exec_hook(INCOMPLETE_GROUP);
+ install_redo_exec_hook(REDO_INSERT_ROW_HEAD);
+ install_redo_exec_hook(REDO_INSERT_ROW_TAIL);
+ install_redo_exec_hook(REDO_INSERT_ROW_BLOBS);
+ install_redo_exec_hook(REDO_PURGE_ROW_HEAD);
+ install_redo_exec_hook(REDO_PURGE_ROW_TAIL);
+ install_redo_exec_hook(REDO_FREE_HEAD_OR_TAIL);
+ install_redo_exec_hook(REDO_FREE_BLOCKS);
+ install_redo_exec_hook(REDO_DELETE_ALL);
+ install_redo_exec_hook(REDO_INDEX);
+ install_redo_exec_hook(REDO_INDEX_NEW_PAGE);
+ install_redo_exec_hook(REDO_INDEX_FREE_PAGE);
+ install_redo_exec_hook(REDO_BITMAP_NEW_PAGE);
+ install_redo_exec_hook(UNDO_ROW_INSERT);
+ install_redo_exec_hook(UNDO_ROW_DELETE);
+ install_redo_exec_hook(UNDO_ROW_UPDATE);
+ install_redo_exec_hook(UNDO_KEY_INSERT);
+ install_redo_exec_hook(UNDO_KEY_DELETE);
+ install_redo_exec_hook(UNDO_KEY_DELETE_WITH_ROOT);
+ install_redo_exec_hook(COMMIT);
+ install_redo_exec_hook(CLR_END);
+ install_undo_exec_hook(UNDO_ROW_INSERT);
+ install_undo_exec_hook(UNDO_ROW_DELETE);
+ install_undo_exec_hook(UNDO_ROW_UPDATE);
+ install_undo_exec_hook(UNDO_KEY_INSERT);
+ install_undo_exec_hook(UNDO_KEY_DELETE);
+ install_undo_exec_hook(UNDO_KEY_DELETE_WITH_ROOT);
+ /* REDO_NEW_ROW_HEAD shares entry with REDO_INSERT_ROW_HEAD */
+ install_redo_exec_hook_shared(REDO_NEW_ROW_HEAD, REDO_INSERT_ROW_HEAD);
+ /* REDO_NEW_ROW_TAIL shares entry with REDO_INSERT_ROW_TAIL */
+ install_redo_exec_hook_shared(REDO_NEW_ROW_TAIL, REDO_INSERT_ROW_TAIL);
+ install_redo_exec_hook(UNDO_BULK_INSERT);
+ install_undo_exec_hook(UNDO_BULK_INSERT);
+ install_redo_exec_hook(IMPORTED_TABLE);
+ install_redo_exec_hook(DEBUG_INFO);
+
+ current_group_end_lsn= LSN_IMPOSSIBLE;
+#ifndef DBUG_OFF
+ current_group_table= NULL;
+#endif
+
+ if (unlikely(lsn == LSN_IMPOSSIBLE || lsn == translog_get_horizon()))
+ {
+ tprint(tracef, "checkpoint address refers to the log end log or "
+ "log is empty, nothing to do.\n");
+ return 0;
+ }
+
+ len= translog_read_record_header(lsn, &rec);
+
+ if (len == RECHEADER_READ_ERROR)
+ {
+ eprint(tracef, "Failed to read header of the first record.");
+ return 1;
+ }
+ if (translog_scanner_init(lsn, 1, &scanner, 1))
+ {
+ tprint(tracef, "Scanner init failed\n");
+ return 1;
+ }
+ for (i= 1;;i++)
+ {
+ uint16 sid= rec.short_trid;
+ const LOG_DESC *log_desc= &log_record_type_descriptor[rec.type];
+ display_record_position(log_desc, &rec, i);
+ /*
+ A complete group is a set of log records with an "end mark" record
+ (e.g. a set of REDOs for an operation, terminated by an UNDO for this
+ operation); if there is no "end mark" record the group is incomplete and
+ won't be executed.
+ */
+ if ((log_desc->record_in_group == LOGREC_IS_GROUP_ITSELF) ||
+ (log_desc->record_in_group == LOGREC_LAST_IN_GROUP))
+ {
+ if (all_active_trans[sid].group_start_lsn != LSN_IMPOSSIBLE)
+ {
+ if (log_desc->record_in_group == LOGREC_IS_GROUP_ITSELF)
+ {
+ /*
+ Can happen if the transaction got a table write error, then
+ unlocked tables thus wrote a COMMIT record. Or can be an
+ INCOMPLETE_GROUP record written by a previous recovery.
+ */
+ tprint(tracef, "\nDiscarding incomplete group before this record\n");
+ all_active_trans[sid].group_start_lsn= LSN_IMPOSSIBLE;
+ }
+ else
+ {
+ struct st_translog_scanner_data scanner2;
+ TRANSLOG_HEADER_BUFFER rec2;
+ /*
+ There is a complete group for this transaction, containing more
+ than this event.
+ */
+ tprint(tracef, " ends a group:\n");
+ len=
+ translog_read_record_header(all_active_trans[sid].group_start_lsn,
+ &rec2);
+ if (len < 0) /* EOF or error */
+ {
+ tprint(tracef, "Cannot find record where it should be\n");
+ goto err;
+ }
+ if (translog_scanner_init(rec2.lsn, 1, &scanner2, 1))
+ {
+ tprint(tracef, "Scanner2 init failed\n");
+ goto err;
+ }
+ current_group_end_lsn= rec.lsn;
+ do
+ {
+ if (rec2.short_trid == sid) /* it's in our group */
+ {
+ const LOG_DESC *log_desc2= &log_record_type_descriptor[rec2.type];
+ display_record_position(log_desc2, &rec2, 0);
+ if (apply == MARIA_LOG_CHECK)
+ {
+ translog_size_t read_len;
+ enlarge_buffer(&rec2);
+ read_len=
+ translog_read_record(rec2.lsn, 0, rec2.record_length,
+ log_record_buffer.str, NULL);
+ if (read_len != rec2.record_length)
+ {
+ tprint(tracef, "Cannot read record's body: read %u of"
+ " %u bytes\n", read_len, rec2.record_length);
+ translog_destroy_scanner(&scanner2);
+ translog_free_record_header(&rec2);
+ goto err;
+ }
+ }
+ if (apply == MARIA_LOG_APPLY &&
+ display_and_apply_record(log_desc2, &rec2))
+ {
+ translog_destroy_scanner(&scanner2);
+ translog_free_record_header(&rec2);
+ goto err;
+ }
+ }
+ translog_free_record_header(&rec2);
+ len= translog_read_next_record_header(&scanner2, &rec2);
+ if (len < 0) /* EOF or error */
+ {
+ tprint(tracef, "Cannot find record where it should be\n");
+ translog_destroy_scanner(&scanner2);
+ translog_free_record_header(&rec2);
+ goto err;
+ }
+ }
+ while (rec2.lsn < rec.lsn);
+ /* group finished */
+ all_active_trans[sid].group_start_lsn= LSN_IMPOSSIBLE;
+ current_group_end_lsn= LSN_IMPOSSIBLE; /* for debugging */
+ display_record_position(log_desc, &rec, 0);
+ translog_destroy_scanner(&scanner2);
+ translog_free_record_header(&rec2);
+ }
+ }
+ if (apply == MARIA_LOG_APPLY &&
+ display_and_apply_record(log_desc, &rec))
+ goto err;
+#ifndef DBUG_OFF
+ current_group_table= NULL;
+#endif
+ }
+ else /* record does not end group */
+ {
+ /* just record the fact, can't know if can execute yet */
+ if (all_active_trans[sid].group_start_lsn == LSN_IMPOSSIBLE)
+ {
+ /* group not yet started */
+ all_active_trans[sid].group_start_lsn= rec.lsn;
+ }
+ }
+ translog_free_record_header(&rec);
+ len= translog_read_next_record_header(&scanner, &rec);
+ if (len < 0)
+ {
+ switch (len)
+ {
+ case RECHEADER_READ_EOF:
+ tprint(tracef, "EOF on the log\n");
+ break;
+ case RECHEADER_READ_ERROR:
+ tprint(tracef, "Error reading log\n");
+ goto err;
+ }
+ break;
+ }
+ }
+ translog_destroy_scanner(&scanner);
+ translog_free_record_header(&rec);
+ if (recovery_message_printed == REC_MSG_REDO)
+ {
+ fprintf(stderr, " 100%%");
+ fflush(stderr);
+ procent_printed= 1;
+ }
+ return 0;
+
+err:
+ translog_destroy_scanner(&scanner);
+ translog_free_record_header(&rec);
+ return 1;
+}
+
+
+/**
+ @brief Informs about any aborted groups or uncommitted transactions,
+ prepares for the UNDO phase if needed.
+
+ @note Observe that it may init trnman.
+*/
+static uint end_of_redo_phase(my_bool prepare_for_undo_phase)
+{
+ uint sid, uncommitted= 0;
+ char llbuf[22];
+ LSN addr;
+
+ hash_free(&all_dirty_pages);
+ /*
+ hash_free() can be called multiple times probably, but be safe if that
+ changes
+ */
+ bzero(&all_dirty_pages, sizeof(all_dirty_pages));
+ my_free(dirty_pages_pool, MYF(MY_ALLOW_ZERO_PTR));
+ dirty_pages_pool= NULL;
+
+ llstr(max_long_trid, llbuf);
+ tprint(tracef, "Maximum transaction long id seen: %s\n", llbuf);
+ llstr(max_trid_in_control_file, llbuf);
+ tprint(tracef, "Maximum transaction long id seen in control file: %s\n",
+ llbuf);
+ /*
+ If logs were deleted, or lost, trid in control file is needed to set
+ trnman's generator:
+ */
+ set_if_bigger(max_long_trid, max_trid_in_control_file);
+ if (prepare_for_undo_phase && trnman_init(max_long_trid))
+ return -1;
+
+ trns_created= TRUE;
+
+ for (sid= 0; sid <= SHORT_TRID_MAX; sid++)
+ {
+ TrID long_trid= all_active_trans[sid].long_trid;
+ LSN gslsn= all_active_trans[sid].group_start_lsn;
+ TRN *trn;
+ if (gslsn != LSN_IMPOSSIBLE)
+ {
+ tprint(tracef, "Group at LSN (%lu,0x%lx) short_trid %u incomplete\n",
+ LSN_IN_PARTS(gslsn), sid);
+ all_active_trans[sid].group_start_lsn= LSN_IMPOSSIBLE;
+ }
+ if (all_active_trans[sid].undo_lsn != LSN_IMPOSSIBLE)
+ {
+ llstr(long_trid, llbuf);
+ tprint(tracef, "Transaction long_trid %s short_trid %u uncommitted\n",
+ llbuf, sid);
+ /*
+ dummy_transaction_object serves only for DDLs, where there is never a
+ rollback or incomplete group. And unknown transactions (which have
+ long_trid==0) should have undo_lsn==LSN_IMPOSSIBLE.
+ */
+ if (long_trid ==0)
+ {
+ eprint(tracef, "Transaction with long_trid 0 should not roll back");
+ ALERT_USER();
+ return -1;
+ }
+ if (prepare_for_undo_phase)
+ {
+ if ((trn= trnman_recreate_trn_from_recovery(sid, long_trid)) == NULL)
+ return -1;
+ trn->undo_lsn= all_active_trans[sid].undo_lsn;
+ trn->first_undo_lsn= all_active_trans[sid].first_undo_lsn |
+ TRANSACTION_LOGGED_LONG_ID; /* because trn is known in log */
+ if (gslsn != LSN_IMPOSSIBLE)
+ {
+ /*
+ UNDO phase will log some records. So, a future recovery may see:
+ REDO(from incomplete group) - REDO(from rollback) - CLR_END
+ and thus execute the first REDO (finding it in "a complete
+ group"). To prevent that:
+ */
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS];
+ LSN lsn;
+ if (translog_write_record(&lsn, LOGREC_INCOMPLETE_GROUP,
+ trn, NULL, 0,
+ TRANSLOG_INTERNAL_PARTS, log_array,
+ NULL, NULL))
+ return -1;
+ }
+ }
+ uncommitted++;
+ }
+#ifdef MARIA_VERSIONING
+ /*
+ If real recovery: if transaction was committed, move it to some separate
+ list for soon purging.
+ */
+#endif
+ }
+
+ my_free(all_active_trans, MYF(MY_ALLOW_ZERO_PTR));
+ all_active_trans= NULL;
+
+ /*
+ The UNDO phase uses some normal run-time code of ROLLBACK: generates log
+ records, etc; prepare tables for that
+ */
+ addr= translog_get_horizon();
+ for (sid= 0; sid <= SHARE_ID_MAX; sid++)
+ {
+ MARIA_HA *info= all_tables[sid].info;
+ if (info != NULL)
+ {
+ prepare_table_for_close(info, addr);
+ /*
+ But we don't close it; we leave it available for the UNDO phase;
+ it's likely that the UNDO phase will need it.
+ */
+ if (prepare_for_undo_phase)
+ translog_assign_id_to_share_from_recovery(info->s, sid);
+ }
+ }
+ return uncommitted;
+}
+
+
+static int run_undo_phase(uint uncommitted)
+{
+ LSN last_undo;
+ DBUG_ENTER("run_undo_phase");
+
+ if (uncommitted > 0)
+ {
+ checkpoint_useful= TRUE;
+ if (tracef != stdout)
+ {
+ if (recovery_message_printed == REC_MSG_NONE)
+ print_preamble();
+ fprintf(stderr, "transactions to roll back:");
+ recovery_message_printed= REC_MSG_UNDO;
+ }
+ tprint(tracef, "%u transactions will be rolled back\n", uncommitted);
+ procent_printed= 1;
+ for( ; ; )
+ {
+ char llbuf[22];
+ TRN *trn;
+ if (recovery_message_printed == REC_MSG_UNDO)
+ {
+ fprintf(stderr, " %u", uncommitted);
+ fflush(stderr);
+ }
+ if ((uncommitted--) == 0)
+ break;
+ trn= trnman_get_any_trn();
+ DBUG_ASSERT(trn != NULL);
+ llstr(trn->trid, llbuf);
+ tprint(tracef, "Rolling back transaction of long id %s\n", llbuf);
+ last_undo= trn->undo_lsn + 1;
+
+ /* Execute all undo entries */
+ while (trn->undo_lsn)
+ {
+ TRANSLOG_HEADER_BUFFER rec;
+ LOG_DESC *log_desc;
+ DBUG_ASSERT(trn->undo_lsn < last_undo);
+ last_undo= trn->undo_lsn;
+
+ if (translog_read_record_header(trn->undo_lsn, &rec) ==
+ RECHEADER_READ_ERROR)
+ DBUG_RETURN(1);
+ log_desc= &log_record_type_descriptor[rec.type];
+ display_record_position(log_desc, &rec, 0);
+ if (log_desc->record_execute_in_undo_phase(&rec, trn))
+ {
+ eprint(tracef, "Got error %d when executing undo %s", my_errno,
+ log_desc->name);
+ translog_free_record_header(&rec);
+ DBUG_RETURN(1);
+ }
+ translog_free_record_header(&rec);
+ }
+
+ if (trnman_rollback_trn(trn))
+ DBUG_RETURN(1);
+ /* We could want to span a few threads (4?) instead of 1 */
+ /* In the future, we want to have this phase *online* */
+ }
+ }
+ procent_printed= 0;
+ DBUG_RETURN(0);
+}
+
+
+/**
+ In case of error in recovery, deletes all transactions from the transaction
+ manager so that this module does not assert.
+
+ @note no checkpoint should be taken as those transactions matter for the
+ next recovery (they still haven't been properly dealt with).
+*/
+
+static void delete_all_transactions()
+{
+ for( ; ; )
+ {
+ TRN *trn= trnman_get_any_trn();
+ if (trn == NULL)
+ break;
+ trn->undo_lsn= trn->first_undo_lsn= LSN_IMPOSSIBLE;
+ trnman_rollback_trn(trn); /* ignore error */
+ }
+}
+
+
+/**
+ @brief re-enables transactionality, updates is_of_horizon
+
+ @param info table
+ @param horizon address to set is_of_horizon
+*/
+
+static void prepare_table_for_close(MARIA_HA *info, TRANSLOG_ADDRESS horizon)
+{
+ MARIA_SHARE *share= info->s;
+ /*
+ In a fully-forward REDO phase (no checkpoint record),
+ state is now at least as new as the LSN of the current record. It may be
+ newer, in case we are seeing a LOGREC_FILE_ID which tells us to close a
+ table, but that table was later modified further in the log.
+ But if we parsed a checkpoint record, it may be this way in the log:
+ FILE_ID(6->t2)... FILE_ID(6->t1)... CHECKPOINT(6->t1)
+ Checkpoint parsing opened t1 with id 6; first FILE_ID above is going to
+ make t1 close; the first condition below is however false (when checkpoint
+ was taken it increased is_of_horizon) and so it works. For safety we
+ add the second condition.
+ */
+ if (cmp_translog_addr(share->state.is_of_horizon, horizon) < 0 &&
+ cmp_translog_addr(share->lsn_of_file_id, horizon) < 0)
+ {
+ share->state.is_of_horizon= horizon;
+ _ma_state_info_write_sub(share->kfile.file, &share->state,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET);
+ }
+
+ /*
+ Ensure that info->state is up to date as
+ _ma_renable_logging_for_table() is depending on this
+ */
+ *info->state= info->s->state.state;
+
+ /*
+ This leaves PAGECACHE_PLAIN_PAGE pages into the cache, while the table is
+ going to switch back to transactional. So the table will be a mix of
+ pages, which is ok as long as we don't take any checkpoints until all
+ tables get closed at the end of the UNDO phase.
+ */
+ _ma_reenable_logging_for_table(info, FALSE);
+ info->trn= NULL; /* safety */
+}
+
+
+static MARIA_HA *get_MARIA_HA_from_REDO_record(const
+ TRANSLOG_HEADER_BUFFER *rec)
+{
+ uint16 sid;
+ pgcache_page_no_t page;
+ MARIA_HA *info;
+ MARIA_SHARE *share;
+ char llbuf[22];
+ my_bool index_page_redo_entry= FALSE, page_redo_entry= FALSE;
+ LINT_INIT(page);
+
+ print_redo_phase_progress(rec->lsn);
+ sid= fileid_korr(rec->header);
+ switch (rec->type) {
+ /* not all REDO records have a page: */
+ case LOGREC_REDO_INDEX_NEW_PAGE:
+ case LOGREC_REDO_INDEX:
+ case LOGREC_REDO_INDEX_FREE_PAGE:
+ index_page_redo_entry= 1;
+ /* Fall trough*/
+ case LOGREC_REDO_INSERT_ROW_HEAD:
+ case LOGREC_REDO_INSERT_ROW_TAIL:
+ case LOGREC_REDO_PURGE_ROW_HEAD:
+ case LOGREC_REDO_PURGE_ROW_TAIL:
+ case LOGREC_REDO_NEW_ROW_HEAD:
+ case LOGREC_REDO_NEW_ROW_TAIL:
+ case LOGREC_REDO_FREE_HEAD_OR_TAIL:
+ page_redo_entry= TRUE;
+ page= page_korr(rec->header + FILEID_STORE_SIZE);
+ llstr(page, llbuf);
+ break;
+ /*
+ For REDO_FREE_BLOCKS, no need to look at dirty pages list: it does not
+ read data pages, only reads/modifies bitmap page(s) which is cheap.
+ */
+ default:
+ break;
+ }
+ tprint(tracef, " For table of short id %u", sid);
+ info= all_tables[sid].info;
+#ifndef DBUG_OFF
+ DBUG_ASSERT(current_group_table == NULL || current_group_table == info);
+ current_group_table= info;
+#endif
+ if (info == NULL)
+ {
+ tprint(tracef, ", table skipped, so skipping record\n");
+ return NULL;
+ }
+ share= info->s;
+ tprint(tracef, ", '%s'", share->open_file_name.str);
+ DBUG_ASSERT(in_redo_phase);
+ if (cmp_translog_addr(rec->lsn, share->lsn_of_file_id) <= 0)
+ {
+ /*
+ This can happen only if processing a record before the checkpoint
+ record.
+ id->name mapping is newer than REDO record: for sure the table subject
+ of the REDO has been flushed and forced (id re-assignment implies this);
+ REDO can be ignored (and must be, as we don't know what this subject
+ table was).
+ */
+ DBUG_ASSERT(cmp_translog_addr(rec->lsn, checkpoint_start) < 0);
+ tprint(tracef, ", table's LOGREC_FILE_ID has LSN (%lu,0x%lx) more recent"
+ " than record, skipping record",
+ LSN_IN_PARTS(share->lsn_of_file_id));
+ return NULL;
+ }
+ if (cmp_translog_addr(rec->lsn, share->state.skip_redo_lsn) <= 0)
+ {
+ /* probably a bulk insert repair */
+ tprint(tracef, ", has skip_redo_lsn (%lu,0x%lx) more recent than"
+ " record, skipping record\n",
+ LSN_IN_PARTS(share->state.skip_redo_lsn));
+ return NULL;
+ }
+ /* detect if an open instance of a dropped table (internal bug) */
+ DBUG_ASSERT(share->last_version != 0);
+ if (page_redo_entry)
+ {
+ /*
+ Consult dirty pages list.
+ REDO_INSERT_ROW_BLOBS will consult list by itself, as it covers several
+ pages.
+ */
+ tprint(tracef, " page %s", llbuf);
+ if (_ma_redo_not_needed_for_page(sid, rec->lsn, page,
+ index_page_redo_entry))
+ return NULL;
+ }
+ /*
+ So we are going to read the page, and if its LSN is older than the
+ record's we will modify the page
+ */
+ tprint(tracef, ", applying record\n");
+ _ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE); /* to flush state on close */
+ return info;
+}
+
+
+static MARIA_HA *get_MARIA_HA_from_UNDO_record(const
+ TRANSLOG_HEADER_BUFFER *rec)
+{
+ uint16 sid;
+ MARIA_HA *info;
+ MARIA_SHARE *share;
+
+ sid= fileid_korr(rec->header + LSN_STORE_SIZE);
+ tprint(tracef, " For table of short id %u", sid);
+ info= all_tables[sid].info;
+#ifndef DBUG_OFF
+ DBUG_ASSERT(!in_redo_phase ||
+ current_group_table == NULL || current_group_table == info);
+ current_group_table= info;
+#endif
+ if (info == NULL)
+ {
+ tprint(tracef, ", table skipped, so skipping record\n");
+ return NULL;
+ }
+ share= info->s;
+ tprint(tracef, ", '%s'", share->open_file_name.str);
+ if (cmp_translog_addr(rec->lsn, share->lsn_of_file_id) <= 0)
+ {
+ tprint(tracef, ", table's LOGREC_FILE_ID has LSN (%lu,0x%lx) more recent"
+ " than record, skipping record",
+ LSN_IN_PARTS(share->lsn_of_file_id));
+ return NULL;
+ }
+ if (in_redo_phase &&
+ cmp_translog_addr(rec->lsn, share->state.skip_redo_lsn) <= 0)
+ {
+ /* probably a bulk insert repair */
+ tprint(tracef, ", has skip_redo_lsn (%lu,0x%lx) more recent than"
+ " record, skipping record\n",
+ LSN_IN_PARTS(share->state.skip_redo_lsn));
+ return NULL;
+ }
+ DBUG_ASSERT(share->last_version != 0);
+ _ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE); /* to flush state on close */
+ tprint(tracef, ", applying record\n");
+ return info;
+}
+
+
+/**
+ @brief Parses checkpoint record.
+
+ Builds from it the dirty_pages list (a hash), opens tables and maps them to
+ their 2-byte IDs, recreates transactions (not real TRNs though).
+
+ @return LSN from where in the log the REDO phase should start
+ @retval LSN_ERROR error
+ @retval other ok
+*/
+
+static LSN parse_checkpoint_record(LSN lsn)
+{
+ ulong i;
+ ulonglong nb_dirty_pages;
+ TRANSLOG_HEADER_BUFFER rec;
+ TRANSLOG_ADDRESS start_address;
+ int len;
+ uint nb_active_transactions, nb_committed_transactions, nb_tables;
+ uchar *ptr;
+ LSN minimum_rec_lsn_of_active_transactions, minimum_rec_lsn_of_dirty_pages;
+ struct st_dirty_page *next_dirty_page_in_pool;
+
+ tprint(tracef, "Loading data from checkpoint record at LSN (%lu,0x%lx)\n",
+ LSN_IN_PARTS(lsn));
+ if ((len= translog_read_record_header(lsn, &rec)) == RECHEADER_READ_ERROR)
+ {
+ tprint(tracef, "Cannot find checkpoint record where it should be\n");
+ return LSN_ERROR;
+ }
+
+ enlarge_buffer(&rec);
+ if (log_record_buffer.str == NULL ||
+ translog_read_record(rec.lsn, 0, rec.record_length,
+ log_record_buffer.str, NULL) !=
+ rec.record_length)
+ {
+ eprint(tracef, "Failed to read record");
+ return LSN_ERROR;
+ }
+
+ ptr= log_record_buffer.str;
+ start_address= lsn_korr(ptr);
+ ptr+= LSN_STORE_SIZE;
+ tprint(tracef, "Checkpoint record has start_horizon at (%lu,0x%lx)\n",
+ LSN_IN_PARTS(start_address));
+
+ /* transactions */
+ nb_active_transactions= uint2korr(ptr);
+ ptr+= 2;
+ tprint(tracef, "%u active transactions\n", nb_active_transactions);
+ minimum_rec_lsn_of_active_transactions= lsn_korr(ptr);
+ ptr+= LSN_STORE_SIZE;
+ max_long_trid= transid_korr(ptr);
+ ptr+= TRANSID_SIZE;
+
+ /*
+ how much brain juice and discussions there was to come to writing this
+ line. It may make start_address slightly decrease (only by the time it
+ takes to write one or a few rows, roughly).
+ */
+ tprint(tracef, "Checkpoint record has min_rec_lsn of active transactions"
+ " at (%lu,0x%lx)\n",
+ LSN_IN_PARTS(minimum_rec_lsn_of_active_transactions));
+ set_if_smaller(start_address, minimum_rec_lsn_of_active_transactions);
+
+ for (i= 0; i < nb_active_transactions; i++)
+ {
+ uint16 sid= uint2korr(ptr);
+ TrID long_id;
+ LSN undo_lsn, first_undo_lsn;
+ ptr+= 2;
+ long_id= uint6korr(ptr);
+ ptr+= 6;
+ DBUG_ASSERT(sid > 0 && long_id > 0);
+ undo_lsn= lsn_korr(ptr);
+ ptr+= LSN_STORE_SIZE;
+ first_undo_lsn= lsn_korr(ptr);
+ ptr+= LSN_STORE_SIZE;
+ new_transaction(sid, long_id, undo_lsn, first_undo_lsn);
+ }
+ nb_committed_transactions= uint4korr(ptr);
+ ptr+= 4;
+ tprint(tracef, "%lu committed transactions\n",
+ (ulong)nb_committed_transactions);
+ /* no purging => committed transactions are not important */
+ ptr+= (6 + LSN_STORE_SIZE) * nb_committed_transactions;
+
+ /* tables */
+ nb_tables= uint4korr(ptr);
+ ptr+= 4;
+ tprint(tracef, "%u open tables\n", nb_tables);
+ for (i= 0; i< nb_tables; i++)
+ {
+ char name[FN_REFLEN];
+ LSN first_log_write_lsn;
+ uint name_len;
+ uint16 sid= uint2korr(ptr);
+ ptr+= 2;
+ DBUG_ASSERT(sid > 0);
+ first_log_write_lsn= lsn_korr(ptr);
+ ptr+= LSN_STORE_SIZE;
+ name_len= strlen((char *)ptr) + 1;
+ strmake(name, (char *)ptr, sizeof(name)-1);
+ ptr+= name_len;
+ if (new_table(sid, name, first_log_write_lsn))
+ return LSN_ERROR;
+ }
+
+ /* dirty pages */
+ nb_dirty_pages= uint8korr(ptr);
+
+ /* Ensure casts later will not loose significant bits. */
+ DBUG_ASSERT((nb_dirty_pages <= SIZE_T_MAX/sizeof(struct st_dirty_page)) &&
+ (nb_dirty_pages <= ULONG_MAX));
+
+ ptr+= 8;
+ tprint(tracef, "%lu dirty pages\n", (ulong) nb_dirty_pages);
+ if (hash_init(&all_dirty_pages, &my_charset_bin, (ulong)nb_dirty_pages,
+ offsetof(struct st_dirty_page, file_and_page_id),
+ sizeof(((struct st_dirty_page *)NULL)->file_and_page_id),
+ NULL, NULL, 0))
+ return LSN_ERROR;
+ dirty_pages_pool=
+ (struct st_dirty_page *)my_malloc((size_t)nb_dirty_pages *
+ sizeof(struct st_dirty_page),
+ MYF(MY_WME));
+ if (unlikely(dirty_pages_pool == NULL))
+ return LSN_ERROR;
+ next_dirty_page_in_pool= dirty_pages_pool;
+ minimum_rec_lsn_of_dirty_pages= LSN_MAX;
+ for (i= 0; i < nb_dirty_pages ; i++)
+ {
+ pgcache_page_no_t page_id;
+ LSN rec_lsn;
+ uint32 is_index;
+ uint16 table_id= uint2korr(ptr);
+ ptr+= 2;
+ is_index= ptr[0];
+ ptr++;
+ page_id= page_korr(ptr);
+ ptr+= PAGE_STORE_SIZE;
+ rec_lsn= lsn_korr(ptr);
+ ptr+= LSN_STORE_SIZE;
+ if (new_page((is_index << 16) | table_id,
+ page_id, rec_lsn, next_dirty_page_in_pool++))
+ return LSN_ERROR;
+ set_if_smaller(minimum_rec_lsn_of_dirty_pages, rec_lsn);
+ }
+ /* after that, there will be no insert/delete into the hash */
+ /*
+ sanity check on record (did we screw up with all those "ptr+=", did the
+ checkpoint write code and checkpoint read code go out of sync?).
+ */
+ if (ptr != (log_record_buffer.str + log_record_buffer.length))
+ {
+ eprint(tracef, "checkpoint record corrupted\n");
+ return LSN_ERROR;
+ }
+
+ /*
+ start_address is now from where the dirty pages list can be ignored.
+ Find LSN higher or equal to this TRANSLOG_ADDRESS, suitable for
+ translog_read_record() functions.
+ */
+ start_address= checkpoint_start=
+ translog_next_LSN(start_address, LSN_IMPOSSIBLE);
+ tprint(tracef, "Checkpoint record start_horizon now adjusted to"
+ " LSN (%lu,0x%lx)\n", LSN_IN_PARTS(start_address));
+ if (checkpoint_start == LSN_IMPOSSIBLE)
+ {
+ /*
+ There must be a problem, as our checkpoint record exists and is >= the
+ address which is stored in its first bytes, which is >= start_address.
+ */
+ return LSN_ERROR;
+ }
+ /* now, where the REDO phase should start reading log: */
+ tprint(tracef, "Checkpoint has min_rec_lsn of dirty pages at"
+ " LSN (%lu,0x%lx)\n", LSN_IN_PARTS(minimum_rec_lsn_of_dirty_pages));
+ set_if_smaller(start_address, minimum_rec_lsn_of_dirty_pages);
+ DBUG_PRINT("info",
+ ("checkpoint_start: (%lu,0x%lx) start_address: (%lu,0x%lx)",
+ LSN_IN_PARTS(checkpoint_start), LSN_IN_PARTS(start_address)));
+ return start_address;
+}
+
+
+static int new_page(uint32 fileid, pgcache_page_no_t pageid, LSN rec_lsn,
+ struct st_dirty_page *dirty_page)
+{
+ /* serves as hash key */
+ dirty_page->file_and_page_id= (((uint64)fileid) << 40) | pageid;
+ dirty_page->rec_lsn= rec_lsn;
+ return my_hash_insert(&all_dirty_pages, (uchar *)dirty_page);
+}
+
+
+static int close_all_tables(void)
+{
+ int error= 0;
+ uint count= 0;
+ LIST *list_element, *next_open;
+ MARIA_HA *info;
+ TRANSLOG_ADDRESS addr;
+ DBUG_ENTER("close_all_tables");
+
+ pthread_mutex_lock(&THR_LOCK_maria);
+ if (maria_open_list == NULL)
+ goto end;
+ tprint(tracef, "Closing all tables\n");
+ if (tracef != stdout)
+ {
+ if (recovery_message_printed == REC_MSG_NONE)
+ print_preamble();
+ for (count= 0, list_element= maria_open_list ;
+ list_element ; count++, (list_element= list_element->next))
+ ;
+ fprintf(stderr, "tables to flush:");
+ recovery_message_printed= REC_MSG_FLUSH;
+ }
+ /*
+ Since the end of end_of_redo_phase(), we may have written new records
+ (if UNDO phase ran) and thus the state is newer than at
+ end_of_redo_phase(), we need to bump is_of_horizon again.
+ */
+ addr= translog_get_horizon();
+ for (list_element= maria_open_list ; ; list_element= next_open)
+ {
+ if (recovery_message_printed == REC_MSG_FLUSH)
+ {
+ fprintf(stderr, " %u", count--);
+ fflush(stderr);
+ }
+ if (list_element == NULL)
+ break;
+ next_open= list_element->next;
+ info= (MARIA_HA*)list_element->data;
+ pthread_mutex_unlock(&THR_LOCK_maria); /* ok, UNDO phase not online yet */
+ /*
+ Tables which we see here are exactly those which were open at time of
+ crash. They might have open_count>0 as Checkpoint maybe flushed their
+ state while they were used. As Recovery corrected them, don't alarm the
+ user, don't ask for a table check:
+ */
+ info->s->state.open_count= 0;
+ prepare_table_for_close(info, addr);
+ error|= maria_close(info);
+ pthread_mutex_lock(&THR_LOCK_maria);
+ }
+end:
+ pthread_mutex_unlock(&THR_LOCK_maria);
+ DBUG_RETURN(error);
+}
+
+
+/**
+ @brief Close all table instances with a certain name which are present in
+ all_tables.
+
+ @param name Name of table
+ @param addr Log address passed to prepare_table_for_close()
+*/
+
+static my_bool close_one_table(const char *name, TRANSLOG_ADDRESS addr)
+{
+ my_bool res= 0;
+ /* There are no other threads using the tables, so we don't need any locks */
+ struct st_table_for_recovery *internal_table, *end;
+ for (internal_table= all_tables, end= internal_table + SHARE_ID_MAX + 1;
+ internal_table < end ;
+ internal_table++)
+ {
+ MARIA_HA *info= internal_table->info;
+ if ((info != NULL) && !strcmp(info->s->open_file_name.str, name))
+ {
+ prepare_table_for_close(info, addr);
+ if (maria_close(info))
+ res= 1;
+ internal_table->info= NULL;
+ }
+ }
+ return res;
+}
+
+
+/**
+ Temporarily disables logging for this table.
+
+ If that makes the log incomplete, writes a LOGREC_INCOMPLETE_LOG to the log
+ to warn log readers.
+
+ @param info table
+ @param log_incomplete if that disabling makes the log incomplete
+
+ @note for example in the REDO phase we disable logging but that does not
+ make the log incomplete.
+*/
+
+void _ma_tmp_disable_logging_for_table(MARIA_HA *info,
+ my_bool log_incomplete)
+{
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_tmp_disable_logging_for_table");
+ if (log_incomplete)
+ {
+ uchar log_data[FILEID_STORE_SIZE];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
+ LSN lsn;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ translog_write_record(&lsn, LOGREC_INCOMPLETE_LOG,
+ &dummy_transaction_object, info,
+ (translog_size_t) sizeof(log_data),
+ TRANSLOG_INTERNAL_PARTS + 1, log_array,
+ log_data, NULL);
+ }
+
+ /* if we disabled before writing the record, record wouldn't reach log */
+ share->now_transactional= FALSE;
+
+ /*
+ Reset state pointers. This is needed as in ALTER table we may do
+ commit fllowed by _ma_renable_logging_for_table and then
+ info->state may point to a state that was deleted by
+ _ma_trnman_end_trans_hook()
+ */
+ share->state.common= *info->state;
+ info->state= &share->state.common;
+ info->switched_transactional= TRUE;
+
+ /*
+ Some code in ma_blockrec.c assumes a trn even if !now_transactional but in
+ this case it only reads trn->rec_lsn, which has to be LSN_IMPOSSIBLE and
+ should be now. info->trn may be NULL in maria_chk.
+ */
+ if (info->trn == NULL)
+ info->trn= &dummy_transaction_object;
+ DBUG_ASSERT(info->trn->rec_lsn == LSN_IMPOSSIBLE);
+ share->page_type= PAGECACHE_PLAIN_PAGE;
+ /* Functions below will pick up now_transactional and change callbacks */
+ _ma_set_data_pagecache_callbacks(&info->dfile, share);
+ _ma_set_index_pagecache_callbacks(&share->kfile, share);
+ _ma_bitmap_set_pagecache_callbacks(&share->bitmap.file, share);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Re-enables logging for a table which had it temporarily disabled.
+
+ Only the thread which disabled logging is allowed to reenable it. Indeed,
+ re-enabling logging affects all open instances, one must have exclusive
+ access to the table to do that. In practice, the one which disables has
+ such access.
+
+ @param info table
+ @param flush_pages if function needs to flush pages first
+*/
+
+my_bool _ma_reenable_logging_for_table(MARIA_HA *info, my_bool flush_pages)
+{
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_reenable_logging_for_table");
+
+ if (share->now_transactional == share->base.born_transactional ||
+ !info->switched_transactional)
+ DBUG_RETURN(0);
+ info->switched_transactional= FALSE;
+
+ if ((share->now_transactional= share->base.born_transactional))
+ {
+ share->page_type= PAGECACHE_LSN_PAGE;
+
+ /*
+ Copy state information that where updated while the table was used
+ in not transactional mode
+ */
+ _ma_copy_nontrans_state_information(info);
+ _ma_reset_history(info->s);
+
+ if (flush_pages)
+ {
+ /*
+ We are going to change callbacks; if a page is flushed at this moment
+ this can cause race conditions, that's one reason to flush pages
+ now. Other reasons: a checkpoint could be running and miss pages; the
+ pages have type PAGECACHE_PLAIN_PAGE which should not remain. As
+ there are no REDOs for pages, them, bitmaps and the state also have to
+ be flushed and synced.
+ */
+ if (_ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_RELEASE, FLUSH_RELEASE) ||
+ _ma_state_info_write(share,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_LOCK) ||
+ _ma_sync_table_files(info))
+ DBUG_RETURN(1);
+ }
+ else if (!maria_in_recovery)
+ {
+ /*
+ Except in Recovery, we mustn't leave dirty pages (see comments above).
+ Note that this does not verify that the state was flushed, but hey.
+ */
+ pagecache_file_no_dirty_page(share->pagecache, &info->dfile);
+ pagecache_file_no_dirty_page(share->pagecache, &share->kfile);
+ }
+ _ma_set_data_pagecache_callbacks(&info->dfile, share);
+ _ma_set_index_pagecache_callbacks(&share->kfile, share);
+ _ma_bitmap_set_pagecache_callbacks(&share->bitmap.file, share);
+ /*
+ info->trn was not changed in the disable/enable combo, so that it's
+ still usable in this kind of combination:
+ external_lock;
+ start_bulk_insert; # table is empty, disables logging
+ end_bulk_insert; # enables logging
+ start_bulk_insert; # table is not empty, logging stays
+ # so rows insertion needs the real trn.
+ as happens during row-based replication on the slave.
+ */
+ }
+ DBUG_RETURN(0);
+}
+
+
+static void print_redo_phase_progress(TRANSLOG_ADDRESS addr)
+{
+ static uint end_logno= FILENO_IMPOSSIBLE, percentage_printed= 0;
+ static ulong end_offset;
+ static ulonglong initial_remainder= ~(ulonglong) 0;
+
+ uint cur_logno;
+ ulong cur_offset;
+ ulonglong local_remainder;
+ uint percentage_done;
+
+ if (tracef == stdout)
+ return;
+ if (recovery_message_printed == REC_MSG_NONE)
+ {
+ print_preamble();
+ fprintf(stderr, "recovered pages: 0%%");
+ fflush(stderr);
+ procent_printed= 1;
+ recovery_message_printed= REC_MSG_REDO;
+ }
+ if (end_logno == FILENO_IMPOSSIBLE)
+ {
+ LSN end_addr= translog_get_horizon();
+ end_logno= LSN_FILE_NO(end_addr);
+ end_offset= LSN_OFFSET(end_addr);
+ }
+ cur_logno= LSN_FILE_NO(addr);
+ cur_offset= LSN_OFFSET(addr);
+ local_remainder= (cur_logno == end_logno) ? (end_offset - cur_offset) :
+ (((longlong)log_file_size) - cur_offset +
+ max(end_logno - cur_logno - 1, 0) * ((longlong)log_file_size) +
+ end_offset);
+ if (initial_remainder == (ulonglong)(-1))
+ initial_remainder= local_remainder;
+ percentage_done= (uint) ((initial_remainder - local_remainder) * ULL(100) /
+ initial_remainder);
+ if ((percentage_done - percentage_printed) >= 10)
+ {
+ percentage_printed= percentage_done;
+ fprintf(stderr, " %u%%", percentage_done);
+ fflush(stderr);
+ procent_printed= 1;
+ }
+}
+
+
+#ifdef MARIA_EXTERNAL_LOCKING
+#error Marias Checkpoint and Recovery are really not ready for it
+#endif
+
+/*
+Recovery of the state : how it works
+=====================================
+
+Here we ignore Checkpoints for a start.
+
+The state (MARIA_HA::MARIA_SHARE::MARIA_STATE_INFO) is updated in
+memory frequently (at least at every row write/update/delete) but goes
+to disk at few moments: maria_close() when closing the last open
+instance, and a few rare places like CHECK/REPAIR/ALTER
+(non-transactional tables also do it at maria_lock_database() but we
+needn't cover them here).
+
+In case of crash, state on disk is likely to be older than what it was
+in memory, the REDO phase needs to recreate the state as it was in
+memory at the time of crash. When we say Recovery here we will always
+mean "REDO phase".
+
+For example MARIA_STATUS_INFO::records (count of records). It is updated at
+the end of every row write/update/delete/delete_all. When Recovery sees the
+sign of such row operation (UNDO or REDO), it may need to update the records'
+count if that count does not reflect that operation (is older). How to know
+the age of the state compared to the log record: every time the state
+goes to disk at runtime, its member "is_of_horizon" is updated to the
+current end-of-log horizon. So Recovery just needs to compare is_of_horizon
+and the record's LSN to know if it should modify "records".
+
+Other operations like ALTER TABLE DISABLE KEYS update the state but
+don't write log records, thus the REDO phase cannot repeat their
+effect on the state in case of crash. But we make them sync the state
+as soon as they have finished. This reduces the window for a problem.
+
+It looks like only one thread at a time updates the state in memory or
+on disk. We assume that the upper level (normally MySQL) has protection
+against issuing HA_EXTRA_(FORCE_REOPEN|PREPARE_FOR_RENAME) so that these
+are not issued while there are any running transactions on the given table.
+If this is not done, we may write a corrupted state to disk.
+
+With checkpoints
+================
+
+Checkpoint module needs to read the state in memory and write it to
+disk. This may happen while some other thread is modifying the state
+in memory or on disk. Checkpoint thus may be reading changing data, it
+needs a mutex to not have it corrupted, and concurrent modifiers of
+the state need that mutex too for the same reason.
+"records" is modified for every row write/update/delete, we don't want
+to add a mutex lock/unlock there. So we re-use the mutex lock/unlock
+which is already present in these moments, namely the log's mutex which is
+taken when UNDO_ROW_INSERT|UPDATE|DELETE is written: we update "records" in
+under-log-mutex hooks when writing these records (thus "records" is
+not updated at the end of maria_write/update/delete() anymore).
+Thus Checkpoint takes the log's lock and can read "records" from
+memory an write it to disk and release log's lock.
+We however want to avoid having the disk write under the log's
+lock. So it has to be under another mutex, natural choice is
+intern_lock (as Checkpoint needs it anyway to read MARIA_SHARE::kfile,
+and as maria_close() takes it too). All state writes to disk are
+changed to be protected with intern_lock.
+So Checkpoint takes intern_lock, log's lock, reads "records" from
+memory, releases log's lock, updates is_of_horizon and writes "records" to
+disk, release intern_lock.
+In practice, not only "records" needs to be written but the full
+state. So, Checkpoint reads the full state from memory. Some other
+thread may at this moment be modifying in memory some pieces of the
+state which are not protected by the lock's log (see ma_extra.c
+HA_EXTRA_NO_KEYS), and Checkpoint would be reading a corrupted state
+from memory; to guard against that we extend the intern_lock-zone to
+changes done to the state in memory by HA_EXTRA_NO_KEYS et al, and
+also any change made in memory to create_rename_lsn/state_is_of_horizon.
+Last, we don't want in Checkpoint to do
+ log lock; read state from memory; release log lock;
+for each table, it may hold the log's lock too much in total.
+So, we instead do
+ log lock; read N states from memory; release log lock;
+Thus, the sequence above happens outside of any intern_lock.
+But this re-introduces the problem that some other thread may be changing the
+state in memory and on disk under intern_lock, without log's lock, like
+HA_EXTRA_NO_KEYS, while we read the N states. However, when Checkpoint later
+comes to handling the table under intern_lock, which is serialized with
+HA_EXTRA_NO_KEYS, it can see that is_of_horizon is higher then when the state
+was read from memory under log's lock, and thus can decide to not flush the
+obsolete state it has, knowing that the other thread flushed a more recent
+state already. If on the other hand is_of_horizon is not higher, the read
+state is current and can be flushed. So we have a per-table sequence:
+ lock intern_lock; test if is_of_horizon is higher than when we read the state
+ under log's lock; if no then flush the read state to disk.
+*/
+
+/* some comments and pseudo-code which we keep for later */
+#if 0
+ /*
+ MikaelR suggests: support checkpoints during REDO phase too: do checkpoint
+ after a certain amount of log records have been executed. This helps
+ against repeated crashes. Those checkpoints could not be user-requested
+ (as engine is not communicating during the REDO phase), so they would be
+ automatic: this changes the original assumption that we don't write to the
+ log while in the REDO phase, but why not. How often should we checkpoint?
+ */
+
+ /*
+ We want to have two steps:
+ engine->recover_with_max_memory();
+ next_engine->recover_with_max_memory();
+ engine->init_with_normal_memory();
+ next_engine->init_with_normal_memory();
+ So: in recover_with_max_memory() allocate a giant page cache, do REDO
+ phase, then all page cache is flushed and emptied and freed (only retain
+ small structures like TM): take full checkpoint, which is useful if
+ next engine crashes in its recovery the next second.
+ Destroy all shares (maria_close()), then at init_with_normal_memory() we
+ do this:
+ */
+
+ /**** UNDO PHASE *****/
+
+ /*
+ Launch one or more threads to do the background rollback. Don't wait for
+ them to complete their rollback (background rollback; for debugging, we
+ can have an option which waits). Set a counter (total_of_rollback_threads)
+ to the number of threads to lauch.
+
+ Note that InnoDB's rollback-in-background works as long as InnoDB is the
+ last engine to recover, otherwise MySQL will refuse new connections until
+ the last engine has recovered so it's not "background" from the user's
+ point of view. InnoDB is near top of sys_table_types so all others
+ (e.g. BDB) recover after it... So it's really "online rollback" only if
+ InnoDB is the only engine.
+ */
+
+ /* wake up delete/update handler */
+ /* tell the TM that it can now accept new transactions */
+
+ /*
+ mark that checkpoint requests are now allowed.
+ */
+#endif
diff --git a/storage/maria/ma_recovery.h b/storage/maria/ma_recovery.h
new file mode 100644
index 00000000000..aa8fa7ecae9
--- /dev/null
+++ b/storage/maria/ma_recovery.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2006,2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ WL#3072 Maria recovery
+ First version written by Guilhem Bichot on 2006-04-27.
+*/
+
+/* This is the interface of this module. */
+
+/* Performs recovery of the engine at start */
+
+C_MODE_START
+enum maria_apply_log_way
+{ MARIA_LOG_APPLY, MARIA_LOG_DISPLAY_HEADER, MARIA_LOG_CHECK };
+int maria_recovery_from_log(void);
+int maria_apply_log(LSN lsn, enum maria_apply_log_way apply,
+ FILE *trace_file,
+ my_bool execute_undo_phase, my_bool skip_DDLs,
+ my_bool take_checkpoints, uint *warnings_count);
+C_MODE_END
diff --git a/storage/maria/ma_recovery_util.c b/storage/maria/ma_recovery_util.c
new file mode 100644
index 00000000000..a45a990472e
--- /dev/null
+++ b/storage/maria/ma_recovery_util.c
@@ -0,0 +1,138 @@
+/* Copyright (C) 2006,2007,2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Q: Why isn't ma_recovery_util.c simply moved to ma_recovery.c ?
+
+ A: ma_recovery.c, because it invokes objects from ma_check.c (like
+ maria_chk_init()) causes the following problem:
+ if a source file a.c of a program invokes a function defined in
+ ma_recovery.c, then a.o depends on ma_recovery.o which depends on
+ ma_check.o: linker thus brings in ma_check.o. That brings in the
+ dependencies of ma_check.o which are definitions of _ma_check_print_info()
+ etc; if a.o does not define them then the ones of ha_maria.o are used
+ i.e. ha_maria.o is linked into the program, and this brings in dependencies
+ of ha_maria.o on mysqld.o into the program's linking which thus fails, as
+ the program is not linked with mysqld.o.
+ Thus, while several functions defined in ma_recovery.c could be useful to
+ other files, they cannot be used by them.
+ So we are going to gradually move a great share of ma_recovery.c's exported
+ functions into the present file, to isolate the problematic components and
+ avoid the problem.
+*/
+
+#include "maria_def.h"
+
+HASH all_dirty_pages;
+struct st_dirty_page /* used only in the REDO phase */
+{
+ uint64 file_and_page_id;
+ LSN rec_lsn;
+};
+/*
+ LSN after which dirty pages list does not apply. Can be slightly before
+ when ma_checkpoint_execute() started.
+*/
+LSN checkpoint_start= LSN_IMPOSSIBLE;
+
+/** @todo looks like duplicate of recovery_message_printed */
+my_bool procent_printed;
+FILE *tracef; /**< trace file for debugging */
+
+
+/** @brief Prints to a trace file if it is not NULL */
+void tprint(FILE *trace_file __attribute__ ((unused)),
+ const char *format __attribute__ ((unused)), ...)
+{
+ va_list args;
+ va_start(args, format);
+ DBUG_PRINT("info", ("%s", format));
+ if (trace_file != NULL)
+ {
+ if (procent_printed)
+ {
+ procent_printed= 0;
+ fputc('\n', trace_file);
+ }
+ vfprintf(trace_file, format, args);
+ }
+ va_end(args);
+}
+
+
+void eprint(FILE *trace_file __attribute__ ((unused)),
+ const char *format __attribute__ ((unused)), ...)
+{
+ va_list args;
+ va_start(args, format);
+ DBUG_PRINT("error", ("%s", format));
+ if (!trace_file)
+ trace_file= stderr;
+
+ if (procent_printed)
+ {
+ /* In silent mode, print on another line than the 0% 10% 20% line */
+ procent_printed= 0;
+ fputc('\n', trace_file);
+ }
+ vfprintf(trace_file , format, args);
+ fputc('\n', trace_file);
+ if (trace_file != stderr)
+ {
+ va_start(args, format);
+ my_printv_error(HA_ERR_INITIALIZATION, format, MYF(0), args);
+ }
+ va_end(args);
+ fflush(trace_file);
+}
+
+
+/**
+ Tells if the dirty pages list found in checkpoint record allows to ignore a
+ REDO for a certain page.
+
+ @param shortid short id of the table
+ @param lsn REDO record's LSN
+ @param page page number
+ @param index TRUE if index page, FALSE if data page
+*/
+
+my_bool _ma_redo_not_needed_for_page(uint16 shortid, LSN lsn,
+ pgcache_page_no_t page,
+ my_bool index)
+{
+ if (cmp_translog_addr(lsn, checkpoint_start) < 0)
+ {
+ /*
+ 64-bit key is formed like this:
+ Most significant byte: 0 if data page, 1 if index page
+ Next 2 bytes: table's short id
+ Next 5 bytes: page number
+ */
+ uint64 file_and_page_id=
+ (((uint64)((index << 16) | shortid)) << 40) | page;
+ struct st_dirty_page *dirty_page= (struct st_dirty_page *)
+ hash_search(&all_dirty_pages,
+ (uchar *)&file_and_page_id, sizeof(file_and_page_id));
+ DBUG_PRINT("info", ("in dirty pages list: %d", dirty_page != NULL));
+ if ((dirty_page == NULL) ||
+ cmp_translog_addr(lsn, dirty_page->rec_lsn) < 0)
+ {
+ tprint(tracef, ", ignoring because of dirty_pages list\n");
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/storage/maria/ma_recovery_util.h b/storage/maria/ma_recovery_util.h
new file mode 100644
index 00000000000..a35fea84fe9
--- /dev/null
+++ b/storage/maria/ma_recovery_util.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 2006,2007,2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+struct st_dirty_page /* used only in the REDO phase */
+{
+ uint64 file_and_page_id;
+ LSN rec_lsn;
+};
+extern HASH all_dirty_pages;
+/*
+ LSN after which dirty pages list does not apply. Can be slightly before
+ when ma_checkpoint_execute() started.
+*/
+extern LSN checkpoint_start;
+extern my_bool procent_printed;
+extern FILE *tracef;
+
+
+my_bool _ma_redo_not_needed_for_page(uint16 shortid, LSN lsn,
+ pgcache_page_no_t page,
+ my_bool index);
+void tprint(FILE *trace_file, const char *format, ...)
+ ATTRIBUTE_FORMAT(printf, 2, 3);
+void eprint(FILE *trace_file, const char *format, ...)
+ ATTRIBUTE_FORMAT(printf, 2, 3);
diff --git a/storage/maria/ma_rename.c b/storage/maria/ma_rename.c
new file mode 100644
index 00000000000..380f3da3c46
--- /dev/null
+++ b/storage/maria/ma_rename.c
@@ -0,0 +1,135 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Rename a table
+*/
+
+#include "ma_fulltext.h"
+#include "trnman_public.h"
+
+/**
+ @brief renames a table
+
+ @param old_name current name of table
+ @param new_name table should be renamed to this name
+
+ @return Operation status
+ @retval 0 OK
+ @retval !=0 Error
+*/
+
+int maria_rename(const char *old_name, const char *new_name)
+{
+ char from[FN_REFLEN],to[FN_REFLEN];
+ int data_file_rename_error;
+#ifdef USE_RAID
+ uint raid_type=0,raid_chunks=0;
+#endif
+ MARIA_HA *info;
+ MARIA_SHARE *share;
+ myf sync_dir;
+ DBUG_ENTER("maria_rename");
+
+#ifdef EXTRA_DEBUG
+ _ma_check_table_is_closed(old_name,"rename old_table");
+ _ma_check_table_is_closed(new_name,"rename new table2");
+#endif
+ /** @todo LOCK take X-lock on table */
+ if (!(info= maria_open(old_name, O_RDWR, HA_OPEN_FOR_REPAIR)))
+ DBUG_RETURN(my_errno);
+ share= info->s;
+#ifdef USE_RAID
+ raid_type = share->base.raid_type;
+ raid_chunks = share->base.raid_chunks;
+#endif
+
+ /*
+ the renaming of an internal table to the final table (like in ALTER TABLE)
+ is the moment when this table receives its correct create_rename_lsn and
+ this is important; make sure transactionality has been re-enabled.
+ */
+ DBUG_ASSERT(share->now_transactional == share->base.born_transactional);
+ sync_dir= (share->now_transactional && !share->temporary &&
+ !maria_in_recovery) ? MY_SYNC_DIR : 0;
+ if (sync_dir)
+ {
+ LSN lsn;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ uint old_name_len= strlen(old_name)+1, new_name_len= strlen(new_name)+1;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (uchar*)old_name;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= old_name_len;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (uchar*)new_name;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= new_name_len;
+ /*
+ For this record to be of any use for Recovery, we need the upper
+ MySQL layer to be crash-safe, which it is not now (that would require
+ work using the ddl_log of sql/sql_table.cc); when it is, we should
+ reconsider the moment of writing this log record (before or after op,
+ under THR_LOCK_maria or not...), how to use it in Recovery.
+ For now it can serve to apply logs to a backup so we sync it.
+ */
+ if (unlikely(translog_write_record(&lsn, LOGREC_REDO_RENAME_TABLE,
+ &dummy_transaction_object, NULL,
+ old_name_len + new_name_len,
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL) ||
+ translog_flush(lsn)))
+ {
+ maria_close(info);
+ DBUG_RETURN(1);
+ }
+ /*
+ store LSN into file, needed for Recovery to not be confused if a
+ RENAME happened (applying REDOs to the wrong table).
+ */
+ if (_ma_update_state_lsns(share, lsn, share->state.create_trid, TRUE,
+ TRUE))
+ {
+ maria_close(info);
+ DBUG_RETURN(1);
+ }
+ }
+
+ maria_close(info);
+
+ fn_format(from,old_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ fn_format(to,new_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ if (my_rename_with_symlink(from, to, MYF(MY_WME | sync_dir)))
+ DBUG_RETURN(my_errno);
+ fn_format(from,old_name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ fn_format(to,new_name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+#ifdef USE_RAID
+ if (raid_type)
+ data_file_rename_error= my_raid_rename(from, to, raid_chunks,
+ MYF(MY_WME | sync_dir));
+ else
+#endif
+ data_file_rename_error=
+ my_rename_with_symlink(from, to, MYF(MY_WME | sync_dir));
+ if (data_file_rename_error)
+ {
+ /*
+ now we have a renamed index file and a non-renamed data file, try to
+ undo the rename of the index file.
+ */
+ data_file_rename_error= my_errno;
+ fn_format(from, old_name, "", MARIA_NAME_IEXT, MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT));
+ fn_format(to, new_name, "", MARIA_NAME_IEXT, MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT));
+ my_rename_with_symlink(to, from, MYF(MY_WME | sync_dir));
+ }
+ DBUG_RETURN(data_file_rename_error);
+
+}
diff --git a/storage/maria/ma_rfirst.c b/storage/maria/ma_rfirst.c
new file mode 100644
index 00000000000..226aaa551f0
--- /dev/null
+++ b/storage/maria/ma_rfirst.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+
+ /* Read first row through a specfic key */
+
+int maria_rfirst(MARIA_HA *info, uchar *buf, int inx)
+{
+ DBUG_ENTER("maria_rfirst");
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ info->update|= HA_STATE_PREV_FOUND;
+ DBUG_RETURN(maria_rnext(info,buf,inx));
+} /* maria_rfirst */
diff --git a/storage/maria/ma_rkey.c b/storage/maria/ma_rkey.c
new file mode 100644
index 00000000000..9e529aca666
--- /dev/null
+++ b/storage/maria/ma_rkey.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Read record based on a key */
+
+#include "maria_def.h"
+#include "ma_rt_index.h"
+
+/**
+ Read a record using key
+
+ @note
+ Ordinary search_flag is 0 ; Give error if no record with key
+*/
+
+int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
+ key_part_map keypart_map, enum ha_rkey_function search_flag)
+{
+ uchar *key_buff;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo;
+ HA_KEYSEG *last_used_keyseg;
+ uint32 nextflag;
+ MARIA_KEY key;
+ DBUG_ENTER("maria_rkey");
+ DBUG_PRINT("enter", ("base: 0x%lx buf: 0x%lx inx: %d search_flag: %d",
+ (long) info, (long) buf, inx, search_flag));
+
+ if ((inx = _ma_check_index(info,inx)) < 0)
+ DBUG_RETURN(my_errno);
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ info->last_key_func= search_flag;
+ keyinfo= share->keyinfo + inx;
+
+ key_buff= info->lastkey_buff+info->s->base.max_key_length;
+
+ if (info->once_flags & USE_PACKED_KEYS)
+ {
+ info->once_flags&= ~USE_PACKED_KEYS; /* Reset flag */
+ /*
+ key is already packed!; This happens when we are using a MERGE TABLE
+ In this key 'key_part_map' is the length of the key !
+ */
+ bmove(key_buff, key_data, keypart_map);
+ key.data= key_buff;
+ key.keyinfo= keyinfo;
+ key.data_length= keypart_map;
+ key.ref_length= 0;
+ key.flag= 0;
+
+ last_used_keyseg= keyinfo->seg + info->last_used_keyseg;
+ }
+ else
+ {
+ DBUG_ASSERT(keypart_map);
+ /* Save the packed key for later use in the second buffer of lastkey. */
+ _ma_pack_key(info, &key, inx, key_buff, key_data,
+ keypart_map, &last_used_keyseg);
+ /* Save packed_key_length for use by the MERGE engine. */
+ info->pack_key_length= key.data_length;
+ info->last_used_keyseg= (uint16) (last_used_keyseg -
+ keyinfo->seg);
+ DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, &key););
+ }
+
+ if (fast_ma_readinfo(info))
+ goto err;
+ if (share->lock_key_trees)
+ rw_rdlock(&keyinfo->root_lock);
+
+ nextflag= maria_read_vec[search_flag] | key.flag;
+
+ switch (keyinfo->key_alg) {
+#ifdef HAVE_RTREE_KEYS
+ case HA_KEY_ALG_RTREE:
+ if (maria_rtree_find_first(info, &key, nextflag) < 0)
+ {
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ my_errno= HA_ERR_CRASHED;
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ }
+ break;
+#endif
+ case HA_KEY_ALG_BTREE:
+ default:
+ if (!_ma_search(info, &key, nextflag, info->s->state.key_root[inx]))
+ {
+ MARIA_KEY lastkey;
+ lastkey.keyinfo= keyinfo;
+ lastkey.data= info->lastkey_buff;
+ /*
+ Found a key, but it might not be usable. We cannot use rows that
+ are inserted by other threads after we got our table lock
+ ("concurrent inserts"). The record may not even be present yet.
+ Keys are inserted into the index(es) before the record is
+ inserted into the data file.
+ */
+ if ((*share->row_is_visible)(info))
+ break;
+
+ /* The key references a concurrently inserted record. */
+ if (search_flag == HA_READ_KEY_EXACT &&
+ last_used_keyseg == keyinfo->seg + keyinfo->keysegs)
+ {
+ /* Simply ignore the key if it matches exactly. (Bug #29838) */
+ my_errno= HA_ERR_KEY_NOT_FOUND;
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ break;
+ }
+
+ do
+ {
+ uint not_used[2];
+ /*
+ Skip rows that are inserted by other threads since we got
+ a lock. Note that this can only happen if we are not
+ searching after a full length exact key, because the keys
+ are sorted according to position.
+ */
+ lastkey.data_length= info->last_key.data_length;
+ lastkey.ref_length= info->last_key.ref_length;
+ lastkey.flag= info->last_key.flag;
+ if (_ma_search_next(info, &lastkey, maria_readnext_vec[search_flag],
+ info->s->state.key_root[inx]))
+ break; /* purecov: inspected */
+ /*
+ Check that the found key does still match the search.
+ _ma_search_next() delivers the next key regardless of its
+ value.
+ */
+ if (!(nextflag & (SEARCH_BIGGER | SEARCH_SMALLER)) &&
+ ha_key_cmp(keyinfo->seg, info->last_key.data, key.data,
+ key.data_length, SEARCH_FIND, not_used))
+ {
+ /* purecov: begin inspected */
+ my_errno= HA_ERR_KEY_NOT_FOUND;
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ break;
+ /* purecov: end */
+ }
+ } while (!(*share->row_is_visible)(info));
+ }
+ }
+ if (share->lock_key_trees)
+ rw_unlock(&keyinfo->root_lock);
+
+ if (info->cur_row.lastpos == HA_OFFSET_ERROR)
+ {
+ fast_ma_writeinfo(info);
+ goto err;
+ }
+
+ /* Calculate length of the found key; Used by maria_rnext_same */
+ if ((keyinfo->flag & HA_VAR_LENGTH_KEY))
+ info->last_rkey_length= _ma_keylength_part(keyinfo, info->lastkey_buff,
+ last_used_keyseg);
+ else
+ info->last_rkey_length= key.data_length;
+
+ /* Check if we don't want to have record back, only error message */
+ if (!buf)
+ {
+ fast_ma_writeinfo(info);
+ DBUG_RETURN(0);
+ }
+ if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+
+ info->cur_row.lastpos= HA_OFFSET_ERROR; /* Didn't find row */
+
+err:
+ /* Store last used key as a base for read next */
+ memcpy(info->last_key.data, key_buff, key.data_length);
+ info->last_key.data_length= key.data_length;
+ info->last_key.ref_length= info->s->base.rec_reflength;
+ info->last_key.flag= 0;
+ /* Create key with rowid 0 */
+ bzero((char*) info->last_key.data + info->last_key.data_length,
+ info->s->base.rec_reflength);
+
+ if (search_flag == HA_READ_AFTER_KEY)
+ info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */
+ DBUG_RETURN(my_errno);
+} /* _ma_rkey */
diff --git a/storage/maria/ma_rlast.c b/storage/maria/ma_rlast.c
new file mode 100644
index 00000000000..a9a470d37d9
--- /dev/null
+++ b/storage/maria/ma_rlast.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+
+ /* Read last row with the same key as the previous read. */
+
+int maria_rlast(MARIA_HA *info, uchar *buf, int inx)
+{
+ DBUG_ENTER("maria_rlast");
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ info->update|= HA_STATE_NEXT_FOUND;
+ DBUG_RETURN(maria_rprev(info,buf,inx));
+} /* maria_rlast */
diff --git a/storage/maria/ma_rnext.c b/storage/maria/ma_rnext.c
new file mode 100644
index 00000000000..be960eccfe0
--- /dev/null
+++ b/storage/maria/ma_rnext.c
@@ -0,0 +1,125 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+
+#include "ma_rt_index.h"
+
+ /*
+ Read next row with the same key as previous read
+ One may have done a write, update or delete of the previous row.
+ NOTE! Even if one changes the previous row, the next read is done
+ based on the position of the last used key!
+ */
+
+int maria_rnext(MARIA_HA *info, uchar *buf, int inx)
+{
+ int error,changed;
+ uint flag;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo;
+ DBUG_ENTER("maria_rnext");
+
+ if ((inx = _ma_check_index(info,inx)) < 0)
+ DBUG_RETURN(my_errno);
+ flag=SEARCH_BIGGER; /* Read next */
+ if (info->cur_row.lastpos == HA_OFFSET_ERROR &&
+ info->update & HA_STATE_PREV_FOUND)
+ flag=0; /* Read first */
+
+ if (fast_ma_readinfo(info))
+ DBUG_RETURN(my_errno);
+ keyinfo= share->keyinfo + inx;
+ if (share->lock_key_trees)
+ rw_rdlock(&keyinfo->root_lock);
+ changed= _ma_test_if_changed(info);
+ if (!flag)
+ {
+ switch (keyinfo->key_alg){
+#ifdef HAVE_RTREE_KEYS
+ case HA_KEY_ALG_RTREE:
+ error=maria_rtree_get_first(info, inx,
+ info->last_key.data_length +
+ info->last_key.ref_length);
+
+ break;
+#endif
+ case HA_KEY_ALG_BTREE:
+ default:
+ error= _ma_search_first(info, keyinfo, share->state.key_root[inx]);
+ break;
+ }
+ }
+ else
+ {
+ switch (keyinfo->key_alg) {
+#ifdef HAVE_RTREE_KEYS
+ case HA_KEY_ALG_RTREE:
+ /*
+ Note that rtree doesn't support that the table
+ may be changed since last call, so we do need
+ to skip rows inserted by other threads like in btree
+ */
+ error= maria_rtree_get_next(info, inx, info->last_key.data_length +
+ info->last_key.ref_length);
+ break;
+#endif
+ case HA_KEY_ALG_BTREE:
+ default:
+ if (!changed)
+ error= _ma_search_next(info, &info->last_key,
+ flag | info->last_key.flag,
+ share->state.key_root[inx]);
+ else
+ error= _ma_search(info, &info->last_key, flag | info->last_key.flag,
+ share->state.key_root[inx]);
+ }
+ }
+
+ if (!error)
+ {
+ while (!(*share->row_is_visible)(info))
+ {
+ /* Skip rows inserted by other threads since we got a lock */
+ if ((error= _ma_search_next(info, &info->last_key,
+ SEARCH_BIGGER,
+ share->state.key_root[inx])))
+ break;
+ }
+ }
+ if (share->lock_key_trees)
+ rw_unlock(&keyinfo->root_lock);
+
+ /* Don't clear if database-changed */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ info->update|= HA_STATE_NEXT_FOUND;
+
+ if (error)
+ {
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ }
+ else if (!buf)
+ {
+ DBUG_RETURN(info->cur_row.lastpos == HA_OFFSET_ERROR ? my_errno : 0);
+ }
+ else if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("error",("Got error: %d, errno: %d",error, my_errno));
+ DBUG_RETURN(my_errno);
+} /* maria_rnext */
diff --git a/storage/maria/ma_rnext_same.c b/storage/maria/ma_rnext_same.c
new file mode 100644
index 00000000000..d6d115c7f70
--- /dev/null
+++ b/storage/maria/ma_rnext_same.c
@@ -0,0 +1,108 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "ma_rt_index.h"
+
+/*
+ Read next row with the same key as previous read, but abort if
+ the key changes.
+ One may have done a write, update or delete of the previous row.
+
+ NOTE! Even if one changes the previous row, the next read is done
+ based on the position of the last used key!
+*/
+
+int maria_rnext_same(MARIA_HA *info, uchar *buf)
+{
+ int error;
+ uint inx,not_used[2];
+ MARIA_KEYDEF *keyinfo;
+ DBUG_ENTER("maria_rnext_same");
+
+ if ((int) (inx= info->lastinx) < 0 ||
+ info->cur_row.lastpos == HA_OFFSET_ERROR)
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+ if (fast_ma_readinfo(info))
+ DBUG_RETURN(my_errno);
+
+ keyinfo= info->s->keyinfo+inx;
+ if (info->s->lock_key_trees)
+ rw_rdlock(&keyinfo->root_lock);
+
+ switch (keyinfo->key_alg) {
+#ifdef HAVE_RTREE_KEYS
+ case HA_KEY_ALG_RTREE:
+ if ((error=maria_rtree_find_next(info,inx,
+ maria_read_vec[info->last_key_func])))
+ {
+ error=1;
+ my_errno=HA_ERR_END_OF_FILE;
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ break;
+ }
+ break;
+#endif
+ case HA_KEY_ALG_BTREE:
+ default:
+ if (!(info->update & HA_STATE_RNEXT_SAME))
+ {
+ /* First rnext_same; Store old key */
+ memcpy(info->lastkey_buff2, info->last_key.data,
+ info->last_rkey_length);
+ }
+ for (;;)
+ {
+ if ((error= _ma_search_next(info, &info->last_key,
+ SEARCH_BIGGER,
+ info->s->state.key_root[inx])))
+ break;
+ if (ha_key_cmp(keyinfo->seg, (uchar*) info->last_key.data,
+ (uchar*) info->lastkey_buff2,
+ info->last_rkey_length, SEARCH_FIND,
+ not_used))
+ {
+ error=1;
+ my_errno=HA_ERR_END_OF_FILE;
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ break;
+ }
+ /* Skip rows that are inserted by other threads since we got a lock */
+ if ((info->s->row_is_visible)(info))
+ break;
+ }
+ }
+ if (info->s->lock_key_trees)
+ rw_unlock(&keyinfo->root_lock);
+ /* Don't clear if database-changed */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ info->update|= HA_STATE_NEXT_FOUND | HA_STATE_RNEXT_SAME;
+
+ if (error)
+ {
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ }
+ else if (!buf)
+ {
+ DBUG_RETURN(info->cur_row.lastpos == HA_OFFSET_ERROR ? my_errno : 0);
+ }
+ else if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(my_errno);
+} /* maria_rnext_same */
diff --git a/storage/maria/ma_rprev.c b/storage/maria/ma_rprev.c
new file mode 100644
index 00000000000..b9f46d7c405
--- /dev/null
+++ b/storage/maria/ma_rprev.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+
+ /*
+ Read previous row with the same key as previous read
+ One may have done a write, update or delete of the previous row.
+ NOTE! Even if one changes the previous row, the next read is done
+ based on the position of the last used key!
+ */
+
+int maria_rprev(MARIA_HA *info, uchar *buf, int inx)
+{
+ int error,changed;
+ register uint flag;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo;
+ DBUG_ENTER("maria_rprev");
+
+ if ((inx = _ma_check_index(info,inx)) < 0)
+ DBUG_RETURN(my_errno);
+ flag=SEARCH_SMALLER; /* Read previous */
+ if (info->cur_row.lastpos == HA_OFFSET_ERROR &&
+ info->update & HA_STATE_NEXT_FOUND)
+ flag=0; /* Read last */
+
+ if (fast_ma_readinfo(info))
+ DBUG_RETURN(my_errno);
+ keyinfo= share->keyinfo + inx;
+ changed= _ma_test_if_changed(info);
+ if (share->lock_key_trees)
+ rw_rdlock(&keyinfo->root_lock);
+ if (!flag)
+ error= _ma_search_last(info, keyinfo, share->state.key_root[inx]);
+ else if (!changed)
+ error= _ma_search_next(info, &info->last_key,
+ flag | info->last_key.flag,
+ share->state.key_root[inx]);
+ else
+ error= _ma_search(info, &info->last_key, flag | info->last_key.flag,
+ share->state.key_root[inx]);
+
+ if (!error)
+ {
+ while (!(*share->row_is_visible)(info))
+ {
+ /* Skip rows that are inserted by other threads since we got a lock */
+ if ((error= _ma_search_next(info, &info->last_key,
+ SEARCH_SMALLER,
+ share->state.key_root[inx])))
+ break;
+ }
+ }
+ if (share->lock_key_trees)
+ rw_unlock(&keyinfo->root_lock);
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ info->update|= HA_STATE_PREV_FOUND;
+ if (error)
+ {
+ if (my_errno == HA_ERR_KEY_NOT_FOUND)
+ my_errno=HA_ERR_END_OF_FILE;
+ }
+ else if (!buf)
+ {
+ DBUG_RETURN(info->cur_row.lastpos == HA_OFFSET_ERROR ? my_errno : 0);
+ }
+ else if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(my_errno);
+} /* maria_rprev */
diff --git a/storage/maria/ma_rrnd.c b/storage/maria/ma_rrnd.c
new file mode 100644
index 00000000000..24c4bfdd467
--- /dev/null
+++ b/storage/maria/ma_rrnd.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Read a record with random-access. The position to the record must
+ get by MARIA_HA. The next record can be read with pos= MARIA_POS_ERROR */
+
+
+#include "maria_def.h"
+
+/*
+ Read a row based on position.
+
+ RETURN
+ 0 Ok.
+ HA_ERR_RECORD_DELETED Record is deleted.
+ HA_ERR_END_OF_FILE EOF.
+*/
+
+int maria_rrnd(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
+{
+ DBUG_ENTER("maria_rrnd");
+
+ DBUG_ASSERT(filepos != HA_OFFSET_ERROR);
+
+ /* Init all but update-flag */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+
+ info->cur_row.lastpos= filepos; /* Remember for update */
+ DBUG_RETURN((*info->s->read_record)(info, buf, filepos));
+}
diff --git a/storage/maria/ma_rsame.c b/storage/maria/ma_rsame.c
new file mode 100644
index 00000000000..4bdbfd526ba
--- /dev/null
+++ b/storage/maria/ma_rsame.c
@@ -0,0 +1,78 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+
+/**
+ Find current row with read on position or read on key
+
+ @notes
+ If inx >= 0 find record using key
+
+ @warning
+ This function is not row version safe.
+ This is not crtical as this function is not used by MySQL
+
+ @return
+ @retval 0 Ok
+ @retval HA_ERR_KEY_NOT_FOUND Row is deleted
+ @retval HA_ERR_END_OF_FILE End of file
+*/
+
+
+int maria_rsame(MARIA_HA *info, uchar *record, int inx)
+{
+ DBUG_ENTER("maria_rsame");
+
+ if (inx != -1 && ! maria_is_key_active(info->s->state.key_map, inx))
+ {
+ DBUG_PRINT("error", ("wrong index usage"));
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+ }
+ if (info->cur_row.lastpos == HA_OFFSET_ERROR ||
+ info->update & HA_STATE_DELETED)
+ {
+ DBUG_PRINT("error", ("no current record"));
+ DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND); /* No current record */
+ }
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ /* Read row from data file */
+ if (fast_ma_readinfo(info))
+ DBUG_RETURN(my_errno);
+
+ if (inx >= 0)
+ {
+ MARIA_KEYDEF *keyinfo= info->s->keyinfo + inx;
+ info->lastinx= inx;
+ (*keyinfo->make_key)(info, &info->last_key, (uint) inx,
+ info->lastkey_buff, record,
+ info->cur_row.lastpos,
+ info->cur_row.trid);
+ if (info->s->lock_key_trees)
+ rw_rdlock(&keyinfo->root_lock);
+ VOID(_ma_search(info, &info->last_key, SEARCH_SAME,
+ info->s->state.key_root[inx]));
+ if (info->s->lock_key_trees)
+ rw_unlock(&keyinfo->root_lock);
+ }
+
+ if (!(*info->read_record)(info, record, info->cur_row.lastpos))
+ DBUG_RETURN(0);
+ if (my_errno == HA_ERR_RECORD_DELETED)
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_PRINT("error", ("my_errno: %d", my_errno));
+ DBUG_RETURN(my_errno);
+} /* maria_rsame */
diff --git a/storage/maria/ma_rsamepos.c b/storage/maria/ma_rsamepos.c
new file mode 100644
index 00000000000..d2099e7b116
--- /dev/null
+++ b/storage/maria/ma_rsamepos.c
@@ -0,0 +1,63 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* read record through position and fix key-position */
+/* As maria_rsame but supply a position */
+
+#include "maria_def.h"
+
+
+/*
+ Read row based on postion
+
+ @param inx If inx >= 0 postion the given index on found row
+
+ @return
+ @retval 0 Ok
+ @retval HA_ERR_KEY_NOT_FOUND Row is deleted
+ @retval HA_ERR_END_OF_FILE End of file
+*/
+
+int maria_rsame_with_pos(MARIA_HA *info, uchar *record, int inx,
+ MARIA_RECORD_POS filepos)
+{
+ DBUG_ENTER("maria_rsame_with_pos");
+ DBUG_PRINT("enter",("index: %d filepos: %ld", inx, (long) filepos));
+
+ if (inx < -1 ||
+ (inx >= 0 && ! maria_is_key_active(info->s->state.key_map, inx)))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_WRONG_INDEX);
+ }
+
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ if ((*info->s->read_record)(info, record, filepos))
+ {
+ if (my_errno == HA_ERR_RECORD_DELETED)
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(my_errno);
+ }
+ info->cur_row.lastpos= filepos;
+ info->lastinx= inx;
+ if (inx >= 0)
+ {
+ (*info->s->keyinfo[inx].make_key)(info, &info->last_key, (uint) inx,
+ info->lastkey_buff,
+ record, info->cur_row.lastpos,
+ info->cur_row.trid);
+ info->update|=HA_STATE_KEY_CHANGED; /* Don't use indexposition */
+ }
+ DBUG_RETURN(0);
+} /* maria_rsame_pos */
diff --git a/storage/maria/ma_rt_index.c b/storage/maria/ma_rt_index.c
new file mode 100644
index 00000000000..15202c335b2
--- /dev/null
+++ b/storage/maria/ma_rt_index.c
@@ -0,0 +1,1352 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin & MySQL Finland AB
+ & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+
+#ifdef HAVE_RTREE_KEYS
+
+#include "ma_rt_index.h"
+#include "ma_rt_key.h"
+#include "ma_rt_mbr.h"
+
+#define REINSERT_BUFFER_INC 10
+#define PICK_BY_AREA
+/*#define PICK_BY_PERIMETER*/
+
+typedef struct st_page_level
+{
+ uint level;
+ my_off_t offs;
+} stPageLevel;
+
+typedef struct st_page_list
+{
+ ulong n_pages;
+ ulong m_pages;
+ stPageLevel *pages;
+} stPageList;
+
+
+/*
+ Find next key in r-tree according to search_flag recursively
+
+ NOTES
+ Used in maria_rtree_find_first() and maria_rtree_find_next()
+
+ RETURN
+ -1 Error
+ 0 Found
+ 1 Not found
+*/
+
+static int maria_rtree_find_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ uint32 search_flag,
+ uint nod_cmp_flag, my_off_t page, int level)
+{
+ MARIA_SHARE *share= info->s;
+ uint nod_flag;
+ int res;
+ uchar *page_buf, *k, *last;
+ int key_data_length;
+ uint *saved_key= (uint*) (info->maria_rtree_recursion_state) + level;
+
+ if (!(page_buf= (uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ return -1;
+ }
+ if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, page_buf, 0, 0))
+ goto err1;
+ nod_flag= _ma_test_if_nod(share, page_buf);
+
+ key_data_length= keyinfo->keylength - share->base.rec_reflength;
+
+ if (info->maria_rtree_recursion_depth >= level)
+ {
+ k= page_buf + *saved_key;
+ }
+ else
+ {
+ k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag);
+ }
+ last= rt_PAGE_END(share, page_buf);
+
+ for (; k < last; k= rt_PAGE_NEXT_KEY(share, k, key_data_length, nod_flag))
+ {
+ if (nod_flag)
+ {
+ /* this is an internal node in the tree */
+ if (!(res= maria_rtree_key_cmp(keyinfo->seg,
+ info->first_mbr_key, k,
+ info->last_rkey_length, nod_cmp_flag)))
+ {
+ switch ((res= maria_rtree_find_req(info, keyinfo, search_flag,
+ nod_cmp_flag,
+ _ma_kpos(nod_flag, k),
+ level + 1)))
+ {
+ case 0: /* found - exit from recursion */
+ *saved_key= k - page_buf;
+ goto ok;
+ case 1: /* not found - continue searching */
+ info->maria_rtree_recursion_depth= level;
+ break;
+ default: /* error */
+ case -1:
+ goto err1;
+ }
+ }
+ }
+ else
+ {
+ /* this is a leaf */
+ if (!maria_rtree_key_cmp(keyinfo->seg, info->first_mbr_key,
+ k, info->last_rkey_length, search_flag))
+ {
+ uchar *after_key= rt_PAGE_NEXT_KEY(share, k, key_data_length, 0);
+ MARIA_KEY tmp_key;
+
+ /*
+ We don't need to set all MARIA_KEY elements here as
+ _ma_row_pos_from_key() only uses a few of them.
+ */
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= k;
+ tmp_key.data_length= key_data_length;
+
+ info->cur_row.lastpos= _ma_row_pos_from_key(&tmp_key);
+ info->last_key.keyinfo= keyinfo;
+ info->last_key.data_length= key_data_length;
+ info->last_key.ref_length= share->base.rec_reflength;
+ info->last_key.flag= 0;
+ memcpy(info->last_key.data, k,
+ info->last_key.data_length + info->last_key.ref_length);
+ info->maria_rtree_recursion_depth= level;
+ *saved_key= last - page_buf;
+
+ if (after_key < last)
+ {
+ uchar *keyread_buff= info->keyread_buff;
+ info->int_keypos= keyread_buff;
+ info->int_maxpos= keyread_buff + (last - after_key);
+ memcpy(keyread_buff, after_key, last - after_key);
+ info->keyread_buff_used= 0;
+ }
+ else
+ {
+ info->keyread_buff_used= 1;
+ }
+
+ res= 0;
+ goto ok;
+ }
+ }
+ }
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ my_errno= HA_ERR_KEY_NOT_FOUND;
+ res= 1;
+
+ok:
+ my_afree((uchar*)page_buf);
+ return res;
+
+err1:
+ my_afree((uchar*)page_buf);
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ return -1;
+}
+
+
+/*
+ Find first key in r-tree according to search_flag condition
+
+ SYNOPSIS
+ maria_rtree_find_first()
+ info Handler to MARIA file
+ key Key to search for
+ search_flag Bitmap of flags how to do the search
+
+ RETURN
+ -1 Error
+ 0 Found
+ 1 Not found
+*/
+
+int maria_rtree_find_first(MARIA_HA *info, MARIA_KEY *key, uint32 search_flag)
+{
+ my_off_t root;
+ uint nod_cmp_flag;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+
+ if ((root= info->s->state.key_root[keyinfo->key_nr]) == HA_OFFSET_ERROR)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ return -1;
+ }
+
+ /*
+ Save searched key, include data pointer.
+ The data pointer is required if the search_flag contains MBR_DATA.
+ (minimum bounding rectangle)
+ */
+ memcpy(info->first_mbr_key, key->data, key->data_length + key->ref_length);
+ info->last_rkey_length= key->data_length;
+
+ info->maria_rtree_recursion_depth= -1;
+ info->keyread_buff_used= 1;
+
+ nod_cmp_flag= ((search_flag & (MBR_EQUAL | MBR_WITHIN)) ?
+ MBR_WITHIN : MBR_INTERSECT);
+ return maria_rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root,
+ 0);
+}
+
+
+/*
+ Find next key in r-tree according to search_flag condition
+
+ SYNOPSIS
+ maria_rtree_find_next()
+ info Handler to MARIA file
+ uint keynr Key number to use
+ search_flag Bitmap of flags how to do the search
+
+ RETURN
+ -1 Error
+ 0 Found
+ 1 Not found
+*/
+
+int maria_rtree_find_next(MARIA_HA *info, uint keynr, uint32 search_flag)
+{
+ my_off_t root;
+ uint32 nod_cmp_flag;
+ MARIA_KEYDEF *keyinfo= info->s->keyinfo + keynr;
+ DBUG_ASSERT(info->last_key.keyinfo == keyinfo);
+
+ if (info->update & HA_STATE_DELETED)
+ return maria_rtree_find_first(info, &info->last_key, search_flag);
+
+ if (!info->keyread_buff_used)
+ {
+ uchar *key= info->int_keypos;
+
+ while (key < info->int_maxpos)
+ {
+ if (!maria_rtree_key_cmp(keyinfo->seg,
+ info->first_mbr_key, key,
+ info->last_rkey_length, search_flag))
+ {
+ uchar *after_key= key + keyinfo->keylength;
+ MARIA_KEY tmp_key;
+
+ /*
+ We don't need to set all MARIA_KEY elements here as
+ _ma_row_pos_from_key only uses a few of them.
+ */
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= key;
+ tmp_key.data_length= keyinfo->keylength - info->s->base.rec_reflength;
+
+ info->cur_row.lastpos= _ma_row_pos_from_key(&tmp_key);
+ memcpy(info->last_key.data, key, info->last_key.data_length);
+
+ if (after_key < info->int_maxpos)
+ info->int_keypos= after_key;
+ else
+ info->keyread_buff_used= 1;
+ return 0;
+ }
+ key+= keyinfo->keylength;
+ }
+ }
+ if ((root= info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ return -1;
+ }
+
+ nod_cmp_flag= (((search_flag & (MBR_EQUAL | MBR_WITHIN)) ?
+ MBR_WITHIN : MBR_INTERSECT));
+ return maria_rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root,
+ 0);
+}
+
+
+/*
+ Get next key in r-tree recursively
+
+ NOTES
+ Used in maria_rtree_get_first() and maria_rtree_get_next()
+
+ RETURN
+ -1 Error
+ 0 Found
+ 1 Not found
+*/
+
+static int maria_rtree_get_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ uint key_length, my_off_t page, int level)
+{
+ MARIA_SHARE *share= info->s;
+ uchar *page_buf, *last, *k;
+ uint nod_flag, key_data_length;
+ int res;
+ uint *saved_key= (uint*) (info->maria_rtree_recursion_state) + level;
+
+ if (!(page_buf= (uchar*) my_alloca((uint) keyinfo->block_length)))
+ return -1;
+ if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, page_buf, 0, 0))
+ goto err1;
+ nod_flag= _ma_test_if_nod(share, page_buf);
+
+ key_data_length= keyinfo->keylength - share->base.rec_reflength;
+
+ if (info->maria_rtree_recursion_depth >= level)
+ {
+ k= page_buf + *saved_key;
+ if (!nod_flag)
+ {
+ /* Only leaf pages contain data references. */
+ /* Need to check next key with data reference. */
+ k= rt_PAGE_NEXT_KEY(share, k, key_data_length, nod_flag);
+ }
+ }
+ else
+ {
+ k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag);
+ }
+ last= rt_PAGE_END(share, page_buf);
+
+ for (; k < last; k= rt_PAGE_NEXT_KEY(share, k, key_data_length, nod_flag))
+ {
+ if (nod_flag)
+ {
+ /* this is an internal node in the tree */
+ switch ((res= maria_rtree_get_req(info, keyinfo, key_length,
+ _ma_kpos(nod_flag, k), level + 1)))
+ {
+ case 0: /* found - exit from recursion */
+ *saved_key= k - page_buf;
+ goto ok;
+ case 1: /* not found - continue searching */
+ info->maria_rtree_recursion_depth= level;
+ break;
+ default:
+ case -1: /* error */
+ goto err1;
+ }
+ }
+ else
+ {
+ /* this is a leaf */
+ uchar *after_key= rt_PAGE_NEXT_KEY(share, k, key_data_length, 0);
+ MARIA_KEY tmp_key;
+
+ /*
+ We don't need to set all MARIA_KEY elements here as
+ _ma_row_pos_from_key() only uses a few of them.
+ */
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= k;
+ tmp_key.data_length= key_data_length;
+
+ info->cur_row.lastpos= _ma_row_pos_from_key(&tmp_key);
+ info->last_key.data_length= key_data_length;
+ info->last_key.ref_length= share->base.rec_reflength;
+
+ memcpy(info->last_key.data, k,
+ info->last_key.data_length + info->last_key.ref_length);
+
+ info->maria_rtree_recursion_depth= level;
+ *saved_key= k - page_buf;
+
+ if (after_key < last)
+ {
+ uchar *keyread_buff= info->keyread_buff;
+ info->last_rtree_keypos= saved_key;
+ memcpy(keyread_buff, page_buf, keyinfo->block_length);
+ info->int_maxpos= rt_PAGE_END(share, keyread_buff);
+ info->keyread_buff_used= 0;
+ }
+ else
+ {
+ info->keyread_buff_used= 1;
+ }
+
+ res= 0;
+ goto ok;
+ }
+ }
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ my_errno= HA_ERR_KEY_NOT_FOUND;
+ res= 1;
+
+ok:
+ my_afree((uchar*)page_buf);
+ return res;
+
+err1:
+ my_afree((uchar*)page_buf);
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ return -1;
+}
+
+
+/*
+ Get first key in r-tree
+
+ RETURN
+ -1 Error
+ 0 Found
+ 1 Not found
+*/
+
+int maria_rtree_get_first(MARIA_HA *info, uint keynr, uint key_length)
+{
+ my_off_t root;
+ MARIA_KEYDEF *keyinfo= info->s->keyinfo + keynr;
+
+ if ((root= info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ return -1;
+ }
+
+ info->maria_rtree_recursion_depth= -1;
+ info->keyread_buff_used= 1;
+
+ return maria_rtree_get_req(info, keyinfo, key_length, root, 0);
+}
+
+
+/*
+ Get next key in r-tree
+
+ RETURN
+ -1 Error
+ 0 Found
+ 1 Not found
+*/
+
+int maria_rtree_get_next(MARIA_HA *info, uint keynr, uint key_length)
+{
+ my_off_t root;
+ MARIA_KEYDEF *keyinfo= info->s->keyinfo + keynr;
+ uchar *keyread_buff= info->keyread_buff;
+
+ if (!info->keyread_buff_used)
+ {
+ uint key_data_length= keyinfo->keylength - info->s->base.rec_reflength;
+ /* rt_PAGE_NEXT_KEY(*info->last_rtree_keypos) */
+ uchar *key= keyread_buff + *info->last_rtree_keypos + keyinfo->keylength;
+ /* rt_PAGE_NEXT_KEY(key) */
+ uchar *after_key= key + keyinfo->keylength;
+ MARIA_KEY tmp_key;
+
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= key;
+ tmp_key.data_length= key_data_length;
+ tmp_key.ref_length= info->s->base.rec_reflength;
+ tmp_key.flag= 0;
+
+ info->cur_row.lastpos= _ma_row_pos_from_key(&tmp_key);
+ _ma_copy_key(&info->last_key, &tmp_key);
+
+ *info->last_rtree_keypos= (uint) (key - keyread_buff);
+ if (after_key >= info->int_maxpos)
+ {
+ info->keyread_buff_used= 1;
+ }
+
+ return 0;
+ }
+ else
+ {
+ if ((root= info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ return -1;
+ }
+
+ return maria_rtree_get_req(info, &keyinfo[keynr], key_length, root, 0);
+ }
+}
+
+
+/*
+ Choose non-leaf better key for insertion
+
+ Returns a pointer inside the page_buf buffer.
+*/
+#ifdef PICK_BY_PERIMETER
+static const uchar *maria_rtree_pick_key(const MARIA_HA *info,
+ const MARIA_KEY *key,
+ const uchar *page_buf,
+ uint nod_flag)
+{
+ double increase;
+ double best_incr;
+ double perimeter;
+ double best_perimeter;
+ uchar *best_key= NULL;
+ uchar *k= rt_PAGE_FIRST_KEY(page_buf, nod_flag);
+ uchar *last= rt_PAGE_END(info, page_buf);
+
+ LINT_INIT(best_perimeter);
+ LINT_INIT(best_key);
+ LINT_INIT(best_incr);
+
+ for (; k < last; k= rt_PAGE_NEXT_KEY(k, key->data_length, nod_flag))
+ {
+ if ((increase= maria_rtree_perimeter_increase(keyinfo->seg, k, key,
+ &perimeter)) == -1)
+ return NULL;
+ if ((increase < best_incr)||
+ (increase == best_incr && perimeter < best_perimeter))
+ {
+ best_key= k;
+ best_perimeter= perimeter;
+ best_incr= increase;
+ }
+ }
+ return best_key;
+}
+
+#endif /*PICK_BY_PERIMETER*/
+
+#ifdef PICK_BY_AREA
+static const uchar *maria_rtree_pick_key(const MARIA_HA *info,
+ const MARIA_KEY *key,
+ const uchar *page_buf,
+ uint nod_flag)
+{
+ MARIA_SHARE *share= info->s;
+ double increase;
+ double best_incr= DBL_MAX;
+ double area;
+ double best_area;
+ const uchar *best_key= NULL;
+ const uchar *k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag);
+ const uchar *last= rt_PAGE_END(share, page_buf);
+
+ LINT_INIT(best_area);
+
+ for (; k < last;
+ k= rt_PAGE_NEXT_KEY(share, k, key->data_length, nod_flag))
+ {
+ /* The following is safe as -1.0 is an exact number */
+ if ((increase= maria_rtree_area_increase(key->keyinfo->seg, k, key->data,
+ key->data_length +
+ key->ref_length,
+ &area)) == -1.0)
+ return NULL;
+ /* The following should be safe, even if we compare doubles */
+ if (!best_key || increase < best_incr ||
+ ((increase == best_incr) && (area < best_area)))
+ {
+ best_key= k;
+ best_area= area;
+ best_incr= increase;
+ }
+ }
+ return best_key;
+}
+
+#endif /*PICK_BY_AREA*/
+
+/*
+ Go down and insert key into tree
+
+ RETURN
+ -1 Error
+ 0 Child was not split
+ 1 Child was split
+*/
+
+static int maria_rtree_insert_req(MARIA_HA *info, MARIA_KEY *key,
+ my_off_t page, my_off_t *new_page,
+ int ins_level, int level)
+{
+ uint nod_flag, page_link_idx;
+ uint key_length= key->data_length;
+ int res;
+ uchar *page_buf, *k;
+ MARIA_PINNED_PAGE *page_link;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("maria_rtree_insert_req");
+
+ if (!(page_buf= (uchar*) my_alloca((uint) keyinfo->block_length +
+ MARIA_MAX_KEY_BUFF)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, page_buf, 0, &page_link))
+ goto err1;
+ page_link_idx= page_link_to_idx(info);
+ nod_flag= _ma_test_if_nod(share, page_buf);
+ DBUG_PRINT("rtree", ("page: %lu level: %d ins_level: %d nod_flag: %u",
+ (ulong) page, level, ins_level, nod_flag));
+
+ if ((ins_level == -1 && nod_flag) || /* key: go down to leaf */
+ (ins_level > -1 && ins_level > level)) /* branch: go down to ins_level */
+ {
+ if (!(k= (uchar *)maria_rtree_pick_key(info, key, page_buf, nod_flag)))
+ goto err1;
+ /* k is now a pointer inside the page_buf buffer */
+ switch ((res= maria_rtree_insert_req(info, key,
+ _ma_kpos(nod_flag, k), new_page,
+ ins_level, level + 1)))
+ {
+ case 0: /* child was not split, most common case */
+ {
+ maria_rtree_combine_rect(keyinfo->seg, k, key->data, k, key_length);
+ if (share->now_transactional &&
+ _ma_log_change(info, page, page_buf, k, key_length))
+ goto err1;
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, page_buf))
+ goto err1;
+ goto ok;
+ }
+ case 1: /* child was split */
+ {
+ /* Set new_key to point to a free buffer area */
+ uchar *new_key_buff= page_buf + keyinfo->block_length + nod_flag;
+ MARIA_KEY new_key;
+ MARIA_KEY k_key;
+
+ DBUG_ASSERT(nod_flag);
+ k_key.keyinfo= new_key.keyinfo= keyinfo;
+ new_key.data= new_key_buff;
+ k_key.data= k;
+ k_key.data_length= new_key.data_length= key->data_length;
+ k_key.ref_length= new_key.ref_length= key->ref_length;
+ k_key.flag= new_key.flag= 0; /* Safety */
+
+ /* set proper MBR for key */
+ if (maria_rtree_set_key_mbr(info, &k_key, _ma_kpos(nod_flag, k)))
+ goto err1;
+ if (share->now_transactional &&
+ _ma_log_change(info, page, page_buf, k, key_length))
+ goto err1;
+ /* add new key for new page */
+ _ma_kpointer(info, new_key_buff - nod_flag, *new_page);
+ if (maria_rtree_set_key_mbr(info, &new_key, *new_page))
+ goto err1;
+ res= maria_rtree_add_key(info, &new_key, page_buf, page, new_page);
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, page_buf))
+ goto err1;
+ goto ok;
+ }
+ default:
+ case -1: /* error */
+ {
+ goto err1;
+ }
+ }
+ }
+ else
+ {
+ res= maria_rtree_add_key(info, key, page_buf, page, new_page);
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, page, PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, page_buf))
+ goto err1;
+ }
+
+ok:
+ my_afree(page_buf);
+ DBUG_RETURN(res);
+
+err1:
+ res= -1; /* purecov: inspected */
+ goto ok; /* purecov: inspected */
+}
+
+
+/**
+ Insert key into the tree
+
+ @param info table
+ @param key KEY to insert
+ @param ins_level at which level key insertion should start
+ @param root put new key_root there
+
+ @return Operation result
+ @retval -1 Error
+ @retval 0 Root was not split
+ @retval 1 Root was split
+*/
+
+int maria_rtree_insert_level(MARIA_HA *info, MARIA_KEY *key, int ins_level,
+ my_off_t *root)
+{
+ my_off_t old_root;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ int res;
+ my_off_t new_page;
+ MARIA_PINNED_PAGE *page_link;
+ enum pagecache_page_lock write_lock;
+ DBUG_ENTER("maria_rtree_insert_level");
+
+ if ((old_root= share->state.key_root[keyinfo->key_nr]) == HA_OFFSET_ERROR)
+ {
+ MARIA_PINNED_PAGE tmp_page_link;
+ page_link= &tmp_page_link;
+ if ((old_root= _ma_new(info, DFLT_INIT_HITS, &page_link)) ==
+ HA_OFFSET_ERROR)
+ DBUG_RETURN(-1);
+ write_lock= page_link->write_lock;
+ info->keyread_buff_used= 1;
+ bzero(info->buff, share->block_size);
+ _ma_store_keynr(share, info->buff, keyinfo->key_nr);
+ _ma_store_page_used(share, info->buff, share->keypage_header);
+
+ if (share->now_transactional &&
+ _ma_log_new(info, old_root, info->buff, share->keypage_header,
+ keyinfo->key_nr, 1))
+ DBUG_RETURN(1);
+
+ res= maria_rtree_add_key(info, key, info->buff, old_root, NULL);
+ if (_ma_write_keypage(info, keyinfo, old_root, write_lock,
+ DFLT_INIT_HITS, info->buff))
+ DBUG_RETURN(1);
+ *root= old_root;
+ DBUG_RETURN(res);
+ }
+
+ switch ((res= maria_rtree_insert_req(info, key, old_root, &new_page,
+ ins_level, 0)))
+ {
+ case 0: /* root was not split */
+ {
+ break;
+ }
+ case 1: /* root was split, grow a new root; very rare */
+ {
+ uchar *new_root_buf, *new_key_buff;
+ my_off_t new_root;
+ uint nod_flag= share->base.key_reflength;
+ MARIA_PINNED_PAGE tmp_page_link;
+ MARIA_KEY new_key;
+ page_link= &tmp_page_link;
+
+ DBUG_PRINT("rtree", ("root was split, grow a new root"));
+ if (!(new_root_buf= (uchar*) my_alloca((uint) keyinfo->block_length +
+ MARIA_MAX_KEY_BUFF)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+
+ bzero(new_root_buf, share->block_size);
+ if (nod_flag)
+ _ma_store_keypage_flag(share, new_root_buf, KEYPAGE_FLAG_ISNOD);
+ _ma_store_keynr(share, new_root_buf, keyinfo->key_nr);
+ _ma_store_page_used(share, new_root_buf, share->keypage_header);
+ if ((new_root= _ma_new(info, DFLT_INIT_HITS, &page_link)) ==
+ HA_OFFSET_ERROR)
+ goto err1;
+ write_lock= page_link->write_lock;
+
+ if (share->now_transactional &&
+ _ma_log_new(info, new_root, new_root_buf, share->keypage_header,
+ keyinfo->key_nr, 1))
+ goto err1;
+
+ /* Point to some free space */
+ new_key_buff= new_root_buf + keyinfo->block_length + nod_flag;
+ new_key.keyinfo= keyinfo;
+ new_key.data= new_key_buff;
+ new_key.data_length= key->data_length;
+ new_key.ref_length= key->ref_length;
+ new_key.flag= 0;
+
+ _ma_kpointer(info, new_key_buff - nod_flag, old_root);
+ if (maria_rtree_set_key_mbr(info, &new_key, old_root))
+ goto err1;
+ if (maria_rtree_add_key(info, &new_key, new_root_buf, new_root, NULL)
+ == -1)
+ goto err1;
+ _ma_kpointer(info, new_key_buff - nod_flag, new_page);
+ if (maria_rtree_set_key_mbr(info, &new_key, new_page))
+ goto err1;
+ if (maria_rtree_add_key(info, &new_key, new_root_buf, new_root, NULL)
+ == -1)
+ goto err1;
+ if (_ma_write_keypage(info, keyinfo, new_root, write_lock,
+ DFLT_INIT_HITS, new_root_buf))
+ goto err1;
+ *root= new_root;
+ DBUG_PRINT("rtree", ("new root page: %lu level: %d nod_flag: %u",
+ (ulong) new_root, 0,
+ _ma_test_if_nod(share, new_root_buf)));
+
+ my_afree((uchar*)new_root_buf);
+ break;
+err1:
+ my_afree((uchar*)new_root_buf);
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ default:
+ case -1: /* error */
+ {
+ DBUG_ASSERT(0);
+ break;
+ }
+ }
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Insert key into the tree - interface function
+
+ RETURN
+ 1 Error
+ 0 OK
+*/
+
+my_bool maria_rtree_insert(MARIA_HA *info, MARIA_KEY *key)
+{
+ int res;
+ MARIA_SHARE *share= info->s;
+ my_off_t *root, new_root;
+ LSN lsn= LSN_IMPOSSIBLE;
+ DBUG_ENTER("maria_rtree_insert");
+
+ if (!key)
+ DBUG_RETURN(1); /* _ma_sp_make_key failed */
+
+ root= &share->state.key_root[key->keyinfo->key_nr];
+ new_root= *root;
+
+ if ((res= (maria_rtree_insert_level(info, key, -1, &new_root) == -1)))
+ goto err;
+ if (share->now_transactional)
+ res= _ma_write_undo_key_insert(info, key, root, new_root, &lsn);
+ else
+ {
+ *root= new_root;
+ _ma_fast_unlock_key_del(info);
+ }
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+err:
+ DBUG_RETURN(res != 0);
+}
+
+
+/*
+ Fill reinsert page buffer
+
+ RETURN
+ -1 Error
+ 0 OK
+*/
+
+static int maria_rtree_fill_reinsert_list(stPageList *ReinsertList,
+ my_off_t page, int level)
+{
+ DBUG_ENTER("maria_rtree_fill_reinsert_list");
+ DBUG_PRINT("rtree", ("page: %lu level: %d", (ulong) page, level));
+ if (ReinsertList->n_pages == ReinsertList->m_pages)
+ {
+ ReinsertList->m_pages += REINSERT_BUFFER_INC;
+ if (!(ReinsertList->pages= (stPageLevel*)my_realloc((uchar*)ReinsertList->pages,
+ ReinsertList->m_pages * sizeof(stPageLevel), MYF(MY_ALLOW_ZERO_PTR))))
+ goto err1;
+ }
+ /* save page to ReinsertList */
+ ReinsertList->pages[ReinsertList->n_pages].offs= page;
+ ReinsertList->pages[ReinsertList->n_pages].level= level;
+ ReinsertList->n_pages++;
+ DBUG_RETURN(0);
+
+err1:
+ DBUG_RETURN(-1); /* purecov: inspected */
+}
+
+
+/*
+ Go down and delete key from the tree
+
+ RETURN
+ -1 Error
+ 0 Deleted
+ 1 Not found
+ 2 Empty leaf
+*/
+
+static int maria_rtree_delete_req(MARIA_HA *info, const MARIA_KEY *key,
+ my_off_t page, uint *page_size,
+ stPageList *ReinsertList, int level)
+{
+ ulong i;
+ uint nod_flag, page_link_idx;
+ int res;
+ uchar *page_buf, *last, *k;
+ MARIA_PINNED_PAGE *page_link;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("maria_rtree_delete_req");
+
+ if (!(page_buf= (uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, page_buf, 0, &page_link))
+ goto err1;
+ page_link_idx= page_link_to_idx(info);
+ nod_flag= _ma_test_if_nod(share, page_buf);
+ DBUG_PRINT("rtree", ("page: %lu level: %d nod_flag: %u",
+ (ulong) page, level, nod_flag));
+
+ k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag);
+ last= rt_PAGE_END(share, page_buf);
+
+ for (i= 0;
+ k < last;
+ k= rt_PAGE_NEXT_KEY(share, k, key->data_length, nod_flag), i++)
+ {
+ if (nod_flag)
+ {
+ /* not leaf */
+ if (!maria_rtree_key_cmp(keyinfo->seg, key->data, k, key->data_length,
+ MBR_WITHIN))
+ {
+ switch ((res= maria_rtree_delete_req(info, key,
+ _ma_kpos(nod_flag, k),
+ page_size, ReinsertList,
+ level + 1)))
+ {
+ case 0: /* deleted */
+ {
+ /* test page filling */
+ if (*page_size + key->data_length >=
+ rt_PAGE_MIN_SIZE(keyinfo->block_length))
+ {
+ /* OK */
+ /* Calculate a new key value (MBR) for the shrinked block. */
+ MARIA_KEY tmp_key;
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= k;
+ tmp_key.data_length= key->data_length;
+ tmp_key.ref_length= key->ref_length;
+ tmp_key.flag= 0; /* Safety */
+
+ if (maria_rtree_set_key_mbr(info, &tmp_key,
+ _ma_kpos(nod_flag, k)))
+ goto err1;
+ if (share->now_transactional &&
+ _ma_log_change(info, page, page_buf, k, key->data_length))
+ goto err1;
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, page_buf))
+ goto err1;
+ }
+ else
+ {
+ /*
+ Too small: delete key & add it descendant to reinsert list.
+ Store position and level of the block so that it can be
+ accessed later for inserting the remaining keys.
+ */
+ DBUG_PRINT("rtree", ("too small. move block to reinsert list"));
+ if (maria_rtree_fill_reinsert_list(ReinsertList,
+ _ma_kpos(nod_flag, k),
+ level + 1))
+ goto err1;
+ /*
+ Delete the key that references the block. This makes the
+ block disappear from the index. Hence we need to insert
+ its remaining keys later. Note: if the block is a branch
+ block, we do not only remove this block, but the whole
+ subtree. So we need to re-insert its keys on the same
+ level later to reintegrate the subtrees.
+ */
+ if (maria_rtree_delete_key(info, page_buf, k, key->data_length,
+ nod_flag, page))
+ goto err1;
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, page_buf))
+ goto err1;
+ *page_size= _ma_get_page_used(share, page_buf);
+ }
+
+ goto ok;
+ }
+ case 1: /* not found - continue searching */
+ {
+ break;
+ }
+ case 2: /* vacuous case: last key in the leaf */
+ {
+ if (maria_rtree_delete_key(info, page_buf, k, key->data_length,
+ nod_flag, page))
+ goto err1;
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, page_buf))
+ goto err1;
+ *page_size= _ma_get_page_used(share, page_buf);
+ res= 0;
+ goto ok;
+ }
+ default: /* error */
+ case -1:
+ {
+ goto err1;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* leaf */
+ if (!maria_rtree_key_cmp(keyinfo->seg, key->data, k, key->data_length,
+ MBR_EQUAL | MBR_DATA))
+ {
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+
+ if (maria_rtree_delete_key(info, page_buf, k, key->data_length,
+ nod_flag, page))
+ goto err1;
+ *page_size= _ma_get_page_used(share, page_buf);
+ if (*page_size == info->s->keypage_header)
+ {
+ /* last key in the leaf */
+ res= 2;
+ if (_ma_dispose(info, page, 0))
+ goto err1;
+ }
+ else
+ {
+ res= 0;
+ if (_ma_write_keypage(info, keyinfo, page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, page_buf))
+ goto err1;
+ }
+ goto ok;
+ }
+ }
+ }
+ res= 1;
+
+ok:
+ my_afree((uchar*)page_buf);
+ DBUG_RETURN(res);
+
+err1:
+ my_afree((uchar*)page_buf);
+ DBUG_RETURN(-1); /* purecov: inspected */
+}
+
+
+/*
+ Delete key - interface function
+
+ RETURN
+ -1 Error
+ 0 Deleted
+*/
+
+int maria_rtree_delete(MARIA_HA *info, MARIA_KEY *key)
+{
+ MARIA_SHARE *share= info->s;
+ my_off_t new_root= share->state.key_root[key->keyinfo->key_nr];
+ int res;
+ LSN lsn= LSN_IMPOSSIBLE;
+ DBUG_ENTER("maria_rtree_delete");
+
+ if ((res= maria_rtree_real_delete(info, key, &new_root)))
+ goto err;
+
+ if (share->now_transactional)
+ res= _ma_write_undo_key_delete(info, key, new_root, &lsn);
+ else
+ share->state.key_root[key->keyinfo->key_nr]= new_root;
+
+err:
+ _ma_fast_unlock_key_del(info);
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+ DBUG_RETURN(res);
+}
+
+
+int maria_rtree_real_delete(MARIA_HA *info, MARIA_KEY *key,
+ my_off_t *root)
+{
+ int res;
+ uint page_size, page_link_idx;
+ stPageList ReinsertList;
+ my_off_t old_root;
+ MARIA_PINNED_PAGE *page_link, *root_page_link;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ uint key_data_length= key->data_length;
+ DBUG_ENTER("maria_rtree_real_delete");
+
+ if ((old_root= share->state.key_root[keyinfo->key_nr]) ==
+ HA_OFFSET_ERROR)
+ {
+ my_errno= HA_ERR_END_OF_FILE;
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ DBUG_PRINT("rtree", ("starting deletion at root page: %lu",
+ (ulong) old_root));
+
+ ReinsertList.pages= NULL;
+ ReinsertList.n_pages= 0;
+ ReinsertList.m_pages= 0;
+
+ switch (maria_rtree_delete_req(info, key, old_root, &page_size,
+ &ReinsertList, 0)) {
+ case 2: /* empty */
+ {
+ *root= HA_OFFSET_ERROR;
+ res= 0;
+ goto err;
+ }
+ case 0: /* deleted */
+ {
+ uint nod_flag;
+ ulong i;
+ MARIA_KEY tmp_key;
+ tmp_key.keyinfo= key->keyinfo;
+ tmp_key.data_length= key->data_length;
+ tmp_key.ref_length= key->ref_length;
+ tmp_key.flag= 0; /* Safety */
+
+ for (i= 0; i < ReinsertList.n_pages; ++i)
+ {
+ uchar *page_buf, *k, *last;
+
+ if (!(page_buf= (uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ goto err1;
+ }
+ if (!_ma_fetch_keypage(info, keyinfo, ReinsertList.pages[i].offs,
+ PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, page_buf, 0, &page_link))
+ goto err1;
+ page_link_idx= page_link_to_idx(info);
+ nod_flag= _ma_test_if_nod(share, page_buf);
+ DBUG_PRINT("rtree", ("reinserting keys from "
+ "page: %lu level: %d nod_flag: %u",
+ (ulong) ReinsertList.pages[i].offs,
+ ReinsertList.pages[i].level, nod_flag));
+
+ k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag);
+ last= rt_PAGE_END(share, page_buf);
+ for (; k < last; k= rt_PAGE_NEXT_KEY(share, k, key_data_length,
+ nod_flag))
+ {
+ tmp_key.data= k;
+ if ((res=
+ maria_rtree_insert_level(info, &tmp_key,
+ ReinsertList.pages[i].level,
+ root)) == -1)
+ {
+ my_afree(page_buf);
+ goto err1;
+ }
+ if (res)
+ {
+ ulong j;
+ DBUG_PRINT("rtree", ("root has been split, adjust levels"));
+ for (j= i; j < ReinsertList.n_pages; j++)
+ {
+ ReinsertList.pages[j].level++;
+ DBUG_PRINT("rtree", ("keys from page: %lu now level: %d",
+ (ulong) ReinsertList.pages[i].offs,
+ ReinsertList.pages[i].level));
+ }
+ }
+ }
+ res= 0;
+ my_afree(page_buf);
+ page_link_from_idx(info, page_link_idx)->changed= 1;
+ if (_ma_dispose(info, ReinsertList.pages[i].offs, 0))
+ goto err1;
+ }
+ if (ReinsertList.pages)
+ my_free((uchar*) ReinsertList.pages, MYF(0));
+
+ /* check for redundant root (not leaf, 1 child) and eliminate */
+ if ((old_root= *root) == HA_OFFSET_ERROR)
+ goto err1;
+ if (!_ma_fetch_keypage(info, keyinfo, old_root,
+ PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, info->buff, 0, &root_page_link))
+ goto err1;
+ nod_flag= _ma_test_if_nod(share, info->buff);
+ page_size= _ma_get_page_used(share, info->buff);
+ if (nod_flag && (page_size == share->keypage_header + key_data_length +
+ nod_flag))
+ {
+ *root= _ma_kpos(nod_flag,
+ rt_PAGE_FIRST_KEY(share, info->buff, nod_flag));
+ root_page_link->changed= 1;
+ if (_ma_dispose(info, old_root, 0))
+ goto err1;
+ }
+ info->update= HA_STATE_DELETED;
+ res= 0;
+ goto err;
+
+err1:
+ res= -1;
+ goto err; /* purecov: inspected */
+ }
+ case 1: /* not found */
+ {
+ my_errno= HA_ERR_KEY_NOT_FOUND;
+ res= -1;
+ goto err; /* purecov: inspected */
+ }
+ default:
+ case -1: /* error */
+ res= -1;
+ goto err; /* purecov: inspected */
+ }
+err:
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Estimate number of suitable keys in the tree
+
+ RETURN
+ estimated value
+*/
+
+ha_rows maria_rtree_estimate(MARIA_HA *info, MARIA_KEY *key, uint32 flag)
+{
+ my_off_t root;
+ uint i= 0;
+ uint nod_flag, key_data_length;
+ uchar *page_buf, *k, *last;
+ double area= 0;
+ ha_rows res= 0;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+
+ if (flag & MBR_DISJOINT)
+ return info->state->records;
+
+ if ((root= share->state.key_root[key->keyinfo->key_nr]) == HA_OFFSET_ERROR)
+ return HA_POS_ERROR;
+ if (!(page_buf= (uchar*) my_alloca((uint) keyinfo->block_length)))
+ return HA_POS_ERROR;
+ if (!_ma_fetch_keypage(info, keyinfo, root, PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, page_buf, 0, 0))
+ goto err1;
+ nod_flag= _ma_test_if_nod(share, page_buf);
+
+ key_data_length= key->data_length;
+
+ k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag);
+ last= rt_PAGE_END(share, page_buf);
+
+ for (; k < last; k= rt_PAGE_NEXT_KEY(share, k, key_data_length,
+ nod_flag), i++)
+ {
+ if (nod_flag)
+ {
+ double k_area= maria_rtree_rect_volume(keyinfo->seg, k, key_data_length);
+
+ /* The following should be safe, even if we compare doubles */
+ if (k_area == 0)
+ {
+ if (flag & (MBR_CONTAIN | MBR_INTERSECT))
+ {
+ area += 1;
+ }
+ else if (flag & (MBR_WITHIN | MBR_EQUAL))
+ {
+ if (!maria_rtree_key_cmp(keyinfo->seg, key->data, k, key_data_length,
+ MBR_WITHIN))
+ area += 1;
+ }
+ else
+ goto err1;
+ }
+ else
+ {
+ if (flag & (MBR_CONTAIN | MBR_INTERSECT))
+ {
+ area+= maria_rtree_overlapping_area(keyinfo->seg, key->data, k,
+ key_data_length) / k_area;
+ }
+ else if (flag & (MBR_WITHIN | MBR_EQUAL))
+ {
+ if (!maria_rtree_key_cmp(keyinfo->seg, key->data, k, key_data_length,
+ MBR_WITHIN))
+ area+= (maria_rtree_rect_volume(keyinfo->seg, key->data,
+ key_data_length) / k_area);
+ }
+ else
+ goto err1;
+ }
+ }
+ else
+ {
+ if (!maria_rtree_key_cmp(keyinfo->seg, key->data, k, key_data_length,
+ flag))
+ ++res;
+ }
+ }
+ if (nod_flag)
+ {
+ if (i)
+ res= (ha_rows) (area / i * info->state->records);
+ else
+ res= HA_POS_ERROR;
+ }
+
+ my_afree((uchar*)page_buf);
+ return res;
+
+err1:
+ my_afree(page_buf);
+ return HA_POS_ERROR;
+}
+
+#endif /*HAVE_RTREE_KEYS*/
diff --git a/storage/maria/ma_rt_index.h b/storage/maria/ma_rt_index.h
new file mode 100644
index 00000000000..8705128e226
--- /dev/null
+++ b/storage/maria/ma_rt_index.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin & MySQL Finland AB
+ & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _rt_index_h
+#define _rt_index_h
+
+#ifdef HAVE_RTREE_KEYS
+
+#define rt_PAGE_FIRST_KEY(share, page, nod_flag) (page + share->keypage_header + nod_flag)
+#define rt_PAGE_NEXT_KEY(share, key, key_length, nod_flag) (key + key_length +\
+ (nod_flag ? nod_flag : share->base.rec_reflength))
+#define rt_PAGE_END(share, page) (page + _ma_get_page_used(share, page))
+
+#define rt_PAGE_MIN_SIZE(block_length) ((uint)(block_length - KEYPAGE_CHECKSUM_SIZE) / 3)
+
+my_bool maria_rtree_insert(MARIA_HA *info, MARIA_KEY *key);
+int maria_rtree_delete(MARIA_HA *info, MARIA_KEY *key);
+int maria_rtree_insert_level(MARIA_HA *info, MARIA_KEY *key,
+ int ins_level, my_off_t *root);
+int maria_rtree_real_delete(MARIA_HA *info, MARIA_KEY *key, my_off_t *root);
+int maria_rtree_find_first(MARIA_HA *info, MARIA_KEY *key, uint search_flag);
+int maria_rtree_find_next(MARIA_HA *info, uint keynr, uint32 search_flag);
+
+int maria_rtree_get_first(MARIA_HA *info, uint keynr, uint key_length);
+int maria_rtree_get_next(MARIA_HA *info, uint keynr, uint key_length);
+
+ha_rows maria_rtree_estimate(MARIA_HA *info, MARIA_KEY *key, uint32 flag);
+
+int maria_rtree_split_page(MARIA_HA *info, const MARIA_KEY *key,
+ my_off_t page_offs, uchar *page,
+ my_off_t *new_page_offs);
+/**
+ When you obtain a MARIA_PINNED_PAGE* link (by calling
+ _ma_fetch_keypage()/_ma_new()/etc), it is valid only until the next call to
+ those functions on this MARIA_HA*, because that next call may cause a
+ realloc of the pinned_pages DYNAMIC_ARRAY, causing the first link to become
+ wrong. The _index_ in the array is however invariant, so in these situations
+ you should save the index immediately and use it to later obtain an
+ up-to-date link.
+*/
+#define page_link_to_idx(INFO) ((INFO)->pinned_pages.elements - 1)
+#define page_link_from_idx(INFO, IDX) \
+ dynamic_element(&(INFO)->pinned_pages, (IDX), MARIA_PINNED_PAGE *)
+
+#endif /*HAVE_RTREE_KEYS*/
+#endif /* _rt_index_h */
diff --git a/storage/maria/ma_rt_key.c b/storage/maria/ma_rt_key.c
new file mode 100644
index 00000000000..bf70d2ba798
--- /dev/null
+++ b/storage/maria/ma_rt_key.c
@@ -0,0 +1,121 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+
+#ifdef HAVE_RTREE_KEYS
+#include "ma_rt_index.h"
+#include "ma_rt_key.h"
+#include "ma_rt_mbr.h"
+
+/*
+ Add key to the page
+
+ RESULT VALUES
+ -1 Error
+ 0 Not split
+ 1 Split
+*/
+
+int maria_rtree_add_key(MARIA_HA *info, const MARIA_KEY *key,
+ uchar *page_buf, my_off_t page, my_off_t *new_page)
+{
+ MARIA_SHARE *share= info->s;
+ uint page_size= _ma_get_page_used(share, page_buf);
+ uint nod_flag= _ma_test_if_nod(share, page_buf);
+ uchar *key_pos= rt_PAGE_END(share, page_buf);
+ uint tot_key_length= key->data_length + key->ref_length + nod_flag;
+ DBUG_ENTER("maria_rtree_add_key");
+
+ if (page_size + tot_key_length <=
+ (uint)(key->keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE))
+ {
+ /* split won't be necessary */
+ if (nod_flag)
+ {
+ DBUG_ASSERT(_ma_kpos(nod_flag, key->data) <
+ info->state->key_file_length);
+ /* We don't store reference to row on nod pages for rtree index */
+ tot_key_length-= key->ref_length;
+ }
+ /* save key */
+ memcpy(key_pos, key->data - nod_flag, tot_key_length);
+ page_size+= tot_key_length;
+ _ma_store_page_used(share, page_buf, page_size);
+ if (share->now_transactional &&
+ _ma_log_add(info, page, page_buf, key_pos - page_buf,
+ key_pos, tot_key_length, tot_key_length, 0))
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(maria_rtree_split_page(info, key, page, page_buf, new_page)
+ ? -1 : 1);
+}
+
+
+/*
+ Delete key from the page
+
+ Notes
+ key_length is only the data part of the key
+*/
+
+int maria_rtree_delete_key(MARIA_HA *info, uchar *page_buf, uchar *key,
+ uint key_length, uint nod_flag, my_off_t page)
+{
+ MARIA_SHARE *share= info->s;
+ uint16 page_size= _ma_get_page_used(share, page_buf);
+ uint key_length_with_nod_flag;
+ uchar *key_start;
+
+ key_start= key - nod_flag;
+ if (!nod_flag)
+ key_length+= share->base.rec_reflength;
+
+ memmove(key_start, key + key_length, page_size - key_length -
+ (key - page_buf));
+ key_length_with_nod_flag= key_length + nod_flag;
+ page_size-= key_length_with_nod_flag;
+ _ma_store_page_used(share, page_buf, page_size);
+ if (share->now_transactional &&
+ _ma_log_delete(info, page, page_buf, key_start, 0,
+ key_length_with_nod_flag))
+
+ return -1;
+ return 0;
+}
+
+
+/*
+ Calculate and store key MBR into *key.
+*/
+
+int maria_rtree_set_key_mbr(MARIA_HA *info, MARIA_KEY *key,
+ my_off_t child_page)
+{
+ DBUG_ENTER("maria_rtree_set_key_mbr");
+ if (!_ma_fetch_keypage(info, key->keyinfo, child_page,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, info->buff, 0, 0))
+ DBUG_RETURN(-1);
+
+ DBUG_RETURN(maria_rtree_page_mbr(info, key->keyinfo->seg,
+ info->buff, key->data,
+ key->data_length));
+}
+
+#endif /*HAVE_RTREE_KEYS*/
diff --git a/storage/maria/ma_rt_key.h b/storage/maria/ma_rt_key.h
new file mode 100644
index 00000000000..5e24ac51b93
--- /dev/null
+++ b/storage/maria/ma_rt_key.h
@@ -0,0 +1,32 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin & MySQL Finland AB
+ & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Ramil Kalimullin, who has a shared copyright to this code */
+
+#ifndef _rt_key_h
+#define _rt_key_h
+
+#ifdef HAVE_RTREE_KEYS
+
+int maria_rtree_add_key(MARIA_HA *info, const MARIA_KEY *key, uchar *page_buf,
+ my_off_t page, my_off_t *new_page);
+int maria_rtree_delete_key(MARIA_HA *info, uchar *page_buf, uchar *key,
+ uint key_length, uint nod_flag, my_off_t page);
+int maria_rtree_set_key_mbr(MARIA_HA *info, MARIA_KEY *key,
+ my_off_t child_page);
+
+#endif /*HAVE_RTREE_KEYS*/
+#endif /* _rt_key_h */
diff --git a/storage/maria/ma_rt_mbr.c b/storage/maria/ma_rt_mbr.c
new file mode 100644
index 00000000000..9a5e60e36e7
--- /dev/null
+++ b/storage/maria/ma_rt_mbr.c
@@ -0,0 +1,817 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin & MySQL Finland AB
+ & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+
+#ifdef HAVE_RTREE_KEYS
+
+#include "ma_rt_index.h"
+#include "ma_rt_mbr.h"
+
+#define INTERSECT_CMP(amin, amax, bmin, bmax) ((amin > bmax) || (bmin > amax))
+#define CONTAIN_CMP(amin, amax, bmin, bmax) ((bmin > amin) || (bmax < amax))
+#define WITHIN_CMP(amin, amax, bmin, bmax) ((amin > bmin) || (amax < bmax))
+#define DISJOINT_CMP(amin, amax, bmin, bmax) ((amin <= bmax) && (bmin <= amax))
+#define EQUAL_CMP(amin, amax, bmin, bmax) ((amin != bmin) || (amax != bmax))
+
+#define FCMP(A, B) ((int)(A) - (int)(B))
+#define p_inc(A, B, X) {A += X; B += X;}
+
+#define RT_CMP(nextflag) \
+ if (nextflag & MBR_INTERSECT) \
+ { \
+ if (INTERSECT_CMP(amin, amax, bmin, bmax)) \
+ return 1; \
+ } \
+ else if (nextflag & MBR_CONTAIN) \
+ { \
+ if (CONTAIN_CMP(amin, amax, bmin, bmax)) \
+ return 1; \
+ } \
+ else if (nextflag & MBR_WITHIN) \
+ { \
+ if (WITHIN_CMP(amin, amax, bmin, bmax)) \
+ return 1; \
+ } \
+ else if (nextflag & MBR_EQUAL) \
+ { \
+ if (EQUAL_CMP(amin, amax, bmin, bmax)) \
+ return 1; \
+ } \
+ else if (nextflag & MBR_DISJOINT) \
+ { \
+ if (DISJOINT_CMP(amin, amax, bmin, bmax)) \
+ return 1; \
+ }\
+ else /* if unknown comparison operator */ \
+ { \
+ DBUG_ASSERT(0); \
+ }
+
+#define RT_CMP_KORR(type, korr_func, len, nextflag) \
+{ \
+ type amin, amax, bmin, bmax; \
+ amin= korr_func(a); \
+ bmin= korr_func(b); \
+ amax= korr_func(a+len); \
+ bmax= korr_func(b+len); \
+ RT_CMP(nextflag); \
+}
+
+#define RT_CMP_GET(type, get_func, len, nextflag) \
+{ \
+ type amin, amax, bmin, bmax; \
+ get_func(amin, a); \
+ get_func(bmin, b); \
+ get_func(amax, a+len); \
+ get_func(bmax, b+len); \
+ RT_CMP(nextflag); \
+}
+
+/*
+ Compares two keys a and b depending on nextflag
+ nextflag can contain these flags:
+ MBR_INTERSECT(a,b) a overlaps b
+ MBR_CONTAIN(a,b) a contains b
+ MBR_DISJOINT(a,b) a disjoint b
+ MBR_WITHIN(a,b) a within b
+ MBR_EQUAL(a,b) All coordinates of MBRs are equal
+ MBR_DATA(a,b) Data reference is the same
+ Returns 0 on success.
+*/
+
+int maria_rtree_key_cmp(HA_KEYSEG *keyseg, const uchar *b, const uchar *a,
+ uint key_length, uint32 nextflag)
+{
+ for (; (int) key_length > 0; keyseg += 2 )
+ {
+ uint32 keyseg_length;
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_CMP_KORR(int8, mi_sint1korr, 1, nextflag);
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_CMP_KORR(uint8, mi_uint1korr, 1, nextflag);
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_CMP_KORR(int16, mi_sint2korr, 2, nextflag);
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_CMP_KORR(uint16, mi_uint2korr, 2, nextflag);
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_CMP_KORR(int32, mi_sint3korr, 3, nextflag);
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_CMP_KORR(uint32, mi_uint3korr, 3, nextflag);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_CMP_KORR(int32, mi_sint4korr, 4, nextflag);
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_CMP_KORR(uint32, mi_uint4korr, 4, nextflag);
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_CMP_KORR(longlong, mi_sint8korr, 8, nextflag)
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_CMP_KORR(ulonglong, mi_uint8korr, 8, nextflag)
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ /* The following should be safe, even if we compare doubles */
+ RT_CMP_GET(float, mi_float4get, 4, nextflag);
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_CMP_GET(double, mi_float8get, 8, nextflag);
+ break;
+ case HA_KEYTYPE_END:
+ goto end;
+ default:
+ return 1;
+ }
+ keyseg_length= keyseg->length * 2;
+ key_length-= keyseg_length;
+ a+= keyseg_length;
+ b+= keyseg_length;
+ }
+
+end:
+ if (nextflag & MBR_DATA)
+ {
+ const uchar *end= a + keyseg->length;
+ do
+ {
+ if (*a++ != *b++)
+ return FCMP(a[-1], b[-1]);
+ } while (a != end);
+ }
+ return 0;
+}
+
+#define RT_VOL_KORR(type, korr_func, len, cast) \
+{ \
+ type amin, amax; \
+ amin= korr_func(a); \
+ amax= korr_func(a+len); \
+ res *= (cast(amax) - cast(amin)); \
+}
+
+#define RT_VOL_GET(type, get_func, len, cast) \
+{ \
+ type amin, amax; \
+ get_func(amin, a); \
+ get_func(amax, a+len); \
+ res *= (cast(amax) - cast(amin)); \
+}
+
+/*
+ Calculates rectangle volume
+*/
+double maria_rtree_rect_volume(HA_KEYSEG *keyseg, uchar *a, uint key_length)
+{
+ double res= 1;
+ for (; (int)key_length > 0; keyseg += 2)
+ {
+ uint32 keyseg_length;
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_VOL_KORR(int8, mi_sint1korr, 1, (double));
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_VOL_KORR(uint8, mi_uint1korr, 1, (double));
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_VOL_KORR(int16, mi_sint2korr, 2, (double));
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_VOL_KORR(uint16, mi_uint2korr, 2, (double));
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_VOL_KORR(int32, mi_sint3korr, 3, (double));
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_VOL_KORR(uint32, mi_uint3korr, 3, (double));
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_VOL_KORR(int32, mi_sint4korr, 4, (double));
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_VOL_KORR(uint32, mi_uint4korr, 4, (double));
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_VOL_KORR(longlong, mi_sint8korr, 8, (double));
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_VOL_KORR(longlong, mi_sint8korr, 8, ulonglong2double);
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ RT_VOL_GET(float, mi_float4get, 4, (double));
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_VOL_GET(double, mi_float8get, 8, (double));
+ break;
+ case HA_KEYTYPE_END:
+ key_length= 0;
+ break;
+ default:
+ return -1;
+ }
+ keyseg_length= keyseg->length * 2;
+ key_length-= keyseg_length;
+ a+= keyseg_length;
+ }
+ return res;
+}
+
+#define RT_D_MBR_KORR(type, korr_func, len, cast) \
+{ \
+ type amin, amax; \
+ amin= korr_func(a); \
+ amax= korr_func(a+len); \
+ *res++= cast(amin); \
+ *res++= cast(amax); \
+}
+
+#define RT_D_MBR_GET(type, get_func, len, cast) \
+{ \
+ type amin, amax; \
+ get_func(amin, a); \
+ get_func(amax, a+len); \
+ *res++= cast(amin); \
+ *res++= cast(amax); \
+}
+
+
+/*
+ Creates an MBR as an array of doubles.
+ Fills *res.
+*/
+
+int maria_rtree_d_mbr(const HA_KEYSEG *keyseg, const uchar *a,
+ uint key_length, double *res)
+{
+ for (; (int)key_length > 0; keyseg += 2)
+ {
+ uint32 keyseg_length;
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_D_MBR_KORR(int8, mi_sint1korr, 1, (double));
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_D_MBR_KORR(uint8, mi_uint1korr, 1, (double));
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_D_MBR_KORR(int16, mi_sint2korr, 2, (double));
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_D_MBR_KORR(uint16, mi_uint2korr, 2, (double));
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_D_MBR_KORR(int32, mi_sint3korr, 3, (double));
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_D_MBR_KORR(uint32, mi_uint3korr, 3, (double));
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_D_MBR_KORR(int32, mi_sint4korr, 4, (double));
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_D_MBR_KORR(uint32, mi_uint4korr, 4, (double));
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_D_MBR_KORR(longlong, mi_sint8korr, 8, (double));
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_D_MBR_KORR(longlong, mi_sint8korr, 8, ulonglong2double);
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ RT_D_MBR_GET(float, mi_float4get, 4, (double));
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_D_MBR_GET(double, mi_float8get, 8, (double));
+ break;
+ case HA_KEYTYPE_END:
+ key_length= 0;
+ break;
+ default:
+ return 1;
+ }
+ keyseg_length= keyseg->length * 2;
+ key_length-= keyseg_length;
+ a+= keyseg_length;
+ }
+ return 0;
+}
+
+#define RT_COMB_KORR(type, korr_func, store_func, len) \
+{ \
+ type amin, amax, bmin, bmax; \
+ amin= korr_func(a); \
+ bmin= korr_func(b); \
+ amax= korr_func(a+len); \
+ bmax= korr_func(b+len); \
+ amin= min(amin, bmin); \
+ amax= max(amax, bmax); \
+ store_func(c, amin); \
+ store_func(c+len, amax); \
+}
+
+#define RT_COMB_GET(type, get_func, store_func, len) \
+{ \
+ type amin, amax, bmin, bmax; \
+ get_func(amin, a); \
+ get_func(bmin, b); \
+ get_func(amax, a+len); \
+ get_func(bmax, b+len); \
+ amin= min(amin, bmin); \
+ amax= max(amax, bmax); \
+ store_func(c, amin); \
+ store_func(c+len, amax); \
+}
+
+/*
+ Creates common minimal bounding rectungle
+ for two input rectagnles a and b
+ Result is written to c
+*/
+
+int maria_rtree_combine_rect(const HA_KEYSEG *keyseg, const uchar* a,
+ const uchar* b, uchar* c,
+ uint key_length)
+{
+ for ( ; (int) key_length > 0 ; keyseg += 2)
+ {
+ uint32 keyseg_length;
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_COMB_KORR(int8, mi_sint1korr, mi_int1store, 1);
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_COMB_KORR(uint8, mi_uint1korr, mi_int1store, 1);
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_COMB_KORR(int16, mi_sint2korr, mi_int2store, 2);
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_COMB_KORR(uint16, mi_uint2korr, mi_int2store, 2);
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_COMB_KORR(int32, mi_sint3korr, mi_int3store, 3);
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_COMB_KORR(uint32, mi_uint3korr, mi_int3store, 3);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_COMB_KORR(int32, mi_sint4korr, mi_int4store, 4);
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_COMB_KORR(uint32, mi_uint4korr, mi_int4store, 4);
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_COMB_KORR(longlong, mi_sint8korr, mi_int8store, 8);
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_COMB_KORR(ulonglong, mi_uint8korr, mi_int8store, 8);
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ RT_COMB_GET(float, mi_float4get, mi_float4store, 4);
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_COMB_GET(double, mi_float8get, mi_float8store, 8);
+ break;
+ case HA_KEYTYPE_END:
+ return 0;
+ default:
+ return 1;
+ }
+ keyseg_length= keyseg->length * 2;
+ key_length-= keyseg_length;
+ a+= keyseg_length;
+ b+= keyseg_length;
+ c+= keyseg_length;
+ }
+ return 0;
+}
+
+
+#define RT_OVL_AREA_KORR(type, korr_func, len) \
+{ \
+ type amin, amax, bmin, bmax; \
+ amin= korr_func(a); \
+ bmin= korr_func(b); \
+ amax= korr_func(a+len); \
+ bmax= korr_func(b+len); \
+ amin= max(amin, bmin); \
+ amax= min(amax, bmax); \
+ if (amin >= amax) \
+ return 0; \
+ res *= amax - amin; \
+}
+
+#define RT_OVL_AREA_GET(type, get_func, len) \
+{ \
+ type amin, amax, bmin, bmax; \
+ get_func(amin, a); \
+ get_func(bmin, b); \
+ get_func(amax, a+len); \
+ get_func(bmax, b+len); \
+ amin= max(amin, bmin); \
+ amax= min(amax, bmax); \
+ if (amin >= amax) \
+ return 0; \
+ res *= amax - amin; \
+}
+
+/*
+Calculates overlapping area of two MBRs a & b
+*/
+double maria_rtree_overlapping_area(HA_KEYSEG *keyseg, uchar* a, uchar* b,
+ uint key_length)
+{
+ double res= 1;
+ for (; (int) key_length > 0 ; keyseg += 2)
+ {
+ uint32 keyseg_length;
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_OVL_AREA_KORR(int8, mi_sint1korr, 1);
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_OVL_AREA_KORR(uint8, mi_uint1korr, 1);
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_OVL_AREA_KORR(int16, mi_sint2korr, 2);
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_OVL_AREA_KORR(uint16, mi_uint2korr, 2);
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_OVL_AREA_KORR(int32, mi_sint3korr, 3);
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_OVL_AREA_KORR(uint32, mi_uint3korr, 3);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_OVL_AREA_KORR(int32, mi_sint4korr, 4);
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_OVL_AREA_KORR(uint32, mi_uint4korr, 4);
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_OVL_AREA_KORR(longlong, mi_sint8korr, 8);
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_OVL_AREA_KORR(longlong, mi_sint8korr, 8);
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ RT_OVL_AREA_GET(float, mi_float4get, 4);
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_OVL_AREA_GET(double, mi_float8get, 8);
+ break;
+ case HA_KEYTYPE_END:
+ return res;
+ default:
+ return -1;
+ }
+ keyseg_length= keyseg->length * 2;
+ key_length-= keyseg_length;
+ a+= keyseg_length;
+ b+= keyseg_length;
+ }
+ return res;
+}
+
+#define RT_AREA_INC_KORR(type, korr_func, len) \
+{ \
+ type amin, amax, bmin, bmax; \
+ amin= korr_func(a); \
+ bmin= korr_func(b); \
+ amax= korr_func(a+len); \
+ bmax= korr_func(b+len); \
+ a_area *= (((double)amax) - ((double)amin)); \
+ loc_ab_area *= ((double)max(amax, bmax) - (double)min(amin, bmin)); \
+}
+
+#define RT_AREA_INC_GET(type, get_func, len)\
+{\
+ type amin, amax, bmin, bmax; \
+ get_func(amin, a); \
+ get_func(bmin, b); \
+ get_func(amax, a+len); \
+ get_func(bmax, b+len); \
+ a_area *= (((double)amax) - ((double)amin)); \
+ loc_ab_area *= ((double)max(amax, bmax) - (double)min(amin, bmin)); \
+}
+
+/*
+ Calculates MBR_AREA(a+b) - MBR_AREA(a)
+ Fills *ab_area.
+ Note: when 'a' and 'b' objects are far from each other,
+ the area increase can be really big, so this function
+ can return 'inf' as a result.
+*/
+
+double maria_rtree_area_increase(const HA_KEYSEG *keyseg, const uchar *a,
+ const uchar *b,
+ uint key_length, double *ab_area)
+{
+ double a_area= 1.0;
+ double loc_ab_area= 1.0;
+
+ *ab_area= 1.0;
+ for (; (int)key_length > 0; keyseg += 2)
+ {
+ uint32 keyseg_length;
+
+ if (keyseg->null_bit) /* Handle NULL part */
+ return -1;
+
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_AREA_INC_KORR(int8, mi_sint1korr, 1);
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_AREA_INC_KORR(uint8, mi_uint1korr, 1);
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_AREA_INC_KORR(int16, mi_sint2korr, 2);
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_AREA_INC_KORR(uint16, mi_uint2korr, 2);
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_AREA_INC_KORR(int32, mi_sint3korr, 3);
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_AREA_INC_KORR(int32, mi_uint3korr, 3);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_AREA_INC_KORR(int32, mi_sint4korr, 4);
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_AREA_INC_KORR(uint32, mi_uint4korr, 4);
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_AREA_INC_KORR(longlong, mi_sint8korr, 8);
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_AREA_INC_KORR(longlong, mi_sint8korr, 8);
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ RT_AREA_INC_GET(float, mi_float4get, 4);
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_AREA_INC_GET(double, mi_float8get, 8);
+ break;
+ case HA_KEYTYPE_END:
+ goto safe_end;
+ default:
+ return -1;
+ }
+ keyseg_length= keyseg->length * 2;
+ key_length-= keyseg_length;
+ a+= keyseg_length;
+ b+= keyseg_length;
+ }
+safe_end:
+ *ab_area= loc_ab_area;
+ return loc_ab_area - a_area;
+}
+
+#define RT_PERIM_INC_KORR(type, korr_func, len) \
+{ \
+ type amin, amax, bmin, bmax; \
+ amin= korr_func(a); \
+ bmin= korr_func(b); \
+ amax= korr_func(a+len); \
+ bmax= korr_func(b+len); \
+ a_perim+= (((double)amax) - ((double)amin)); \
+ *ab_perim+= ((double)max(amax, bmax) - (double)min(amin, bmin)); \
+}
+
+#define RT_PERIM_INC_GET(type, get_func, len)\
+{\
+ type amin, amax, bmin, bmax; \
+ get_func(amin, a); \
+ get_func(bmin, b); \
+ get_func(amax, a+len); \
+ get_func(bmax, b+len); \
+ a_perim+= (((double)amax) - ((double)amin)); \
+ *ab_perim+= ((double)max(amax, bmax) - (double)min(amin, bmin)); \
+}
+
+/*
+Calculates MBR_PERIMETER(a+b) - MBR_PERIMETER(a)
+*/
+double maria_rtree_perimeter_increase(HA_KEYSEG *keyseg, uchar* a, uchar* b,
+ uint key_length, double *ab_perim)
+{
+ double a_perim= 0.0;
+
+ *ab_perim= 0.0;
+ for (; (int)key_length > 0; keyseg += 2)
+ {
+ uint32 keyseg_length;
+
+ if (keyseg->null_bit) /* Handle NULL part */
+ return -1;
+
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_PERIM_INC_KORR(int8, mi_sint1korr, 1);
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_PERIM_INC_KORR(uint8, mi_uint1korr, 1);
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_PERIM_INC_KORR(int16, mi_sint2korr, 2);
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_PERIM_INC_KORR(uint16, mi_uint2korr, 2);
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_PERIM_INC_KORR(int32, mi_sint3korr, 3);
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_PERIM_INC_KORR(int32, mi_uint3korr, 3);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_PERIM_INC_KORR(int32, mi_sint4korr, 4);
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_PERIM_INC_KORR(uint32, mi_uint4korr, 4);
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_PERIM_INC_KORR(longlong, mi_sint8korr, 8);
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_PERIM_INC_KORR(longlong, mi_sint8korr, 8);
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ RT_PERIM_INC_GET(float, mi_float4get, 4);
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_PERIM_INC_GET(double, mi_float8get, 8);
+ break;
+ case HA_KEYTYPE_END:
+ return *ab_perim - a_perim;
+ default:
+ return -1;
+ }
+ keyseg_length= keyseg->length * 2;
+ key_length-= keyseg_length;
+ a+= keyseg_length;
+ b+= keyseg_length;
+ }
+ return *ab_perim - a_perim;
+}
+
+
+#define RT_PAGE_MBR_KORR(share, type, korr_func, store_func, len, to) \
+{ \
+ type amin, amax, bmin, bmax; \
+ amin= korr_func(k + inc); \
+ amax= korr_func(k + inc + len); \
+ k= rt_PAGE_NEXT_KEY(share, k, k_len, nod_flag); \
+ for (; k < last; k= rt_PAGE_NEXT_KEY(share, k, k_len, nod_flag)) \
+{ \
+ bmin= korr_func(k + inc); \
+ bmax= korr_func(k + inc + len); \
+ if (amin > bmin) \
+ amin= bmin; \
+ if (amax < bmax) \
+ amax= bmax; \
+} \
+ store_func(to, amin); \
+ to+= len; \
+ store_func(to, amax); \
+ to += len; \
+ inc += 2 * len; \
+}
+
+#define RT_PAGE_MBR_GET(share, type, get_func, store_func, len, to) \
+{ \
+ type amin, amax, bmin, bmax; \
+ get_func(amin, k + inc); \
+ get_func(amax, k + inc + len); \
+ k= rt_PAGE_NEXT_KEY(share, k, k_len, nod_flag); \
+ for (; k < last; k= rt_PAGE_NEXT_KEY(share, k, k_len, nod_flag)) \
+{ \
+ get_func(bmin, k + inc); \
+ get_func(bmax, k + inc + len); \
+ if (amin > bmin) \
+ amin= bmin; \
+ if (amax < bmax) \
+ amax= bmax; \
+} \
+ store_func(to, amin); \
+ to+= len; \
+ store_func(to, amax); \
+ to+= len; \
+ inc += 2 * len; \
+}
+
+/*
+ Calculates key page total MBR= MBR(key1) + MBR(key2) + ...
+ Stores into *to.
+*/
+int maria_rtree_page_mbr(const MARIA_HA *info, const HA_KEYSEG *keyseg,
+ const uchar *page_buf,
+ uchar *to, uint key_length)
+{
+ MARIA_SHARE *share= info->s;
+ uint inc= 0;
+ uint k_len= key_length;
+ uint nod_flag= _ma_test_if_nod(share, page_buf);
+ const uchar *k;
+ const uchar *last= rt_PAGE_END(share, page_buf);
+
+ for (; (int)key_length > 0; keyseg += 2)
+ {
+ key_length -= keyseg->length * 2;
+
+ /* Handle NULL part */
+ if (keyseg->null_bit)
+ {
+ return 1;
+ }
+
+ k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag);
+
+ switch ((enum ha_base_keytype) keyseg->type) {
+ case HA_KEYTYPE_INT8:
+ RT_PAGE_MBR_KORR(share, int8, mi_sint1korr, mi_int1store, 1, to);
+ break;
+ case HA_KEYTYPE_BINARY:
+ RT_PAGE_MBR_KORR(share, uint8, mi_uint1korr, mi_int1store, 1, to);
+ break;
+ case HA_KEYTYPE_SHORT_INT:
+ RT_PAGE_MBR_KORR(share, int16, mi_sint2korr, mi_int2store, 2, to);
+ break;
+ case HA_KEYTYPE_USHORT_INT:
+ RT_PAGE_MBR_KORR(share, uint16, mi_uint2korr, mi_int2store, 2, to);
+ break;
+ case HA_KEYTYPE_INT24:
+ RT_PAGE_MBR_KORR(share, int32, mi_sint3korr, mi_int3store, 3, to);
+ break;
+ case HA_KEYTYPE_UINT24:
+ RT_PAGE_MBR_KORR(share, uint32, mi_uint3korr, mi_int3store, 3, to);
+ break;
+ case HA_KEYTYPE_LONG_INT:
+ RT_PAGE_MBR_KORR(share, int32, mi_sint4korr, mi_int4store, 4, to);
+ break;
+ case HA_KEYTYPE_ULONG_INT:
+ RT_PAGE_MBR_KORR(share, uint32, mi_uint4korr, mi_int4store, 4, to);
+ break;
+#ifdef HAVE_LONG_LONG
+ case HA_KEYTYPE_LONGLONG:
+ RT_PAGE_MBR_KORR(share, longlong, mi_sint8korr, mi_int8store, 8, to);
+ break;
+ case HA_KEYTYPE_ULONGLONG:
+ RT_PAGE_MBR_KORR(share, ulonglong, mi_uint8korr, mi_int8store, 8, to);
+ break;
+#endif
+ case HA_KEYTYPE_FLOAT:
+ RT_PAGE_MBR_GET(share, float, mi_float4get, mi_float4store, 4, to);
+ break;
+ case HA_KEYTYPE_DOUBLE:
+ RT_PAGE_MBR_GET(share, double, mi_float8get, mi_float8store, 8, to);
+ break;
+ case HA_KEYTYPE_END:
+ return 0;
+ default:
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#endif /*HAVE_RTREE_KEYS*/
diff --git a/storage/maria/ma_rt_mbr.h b/storage/maria/ma_rt_mbr.h
new file mode 100644
index 00000000000..11988868317
--- /dev/null
+++ b/storage/maria/ma_rt_mbr.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin & MySQL Finland AB
+ & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _rt_mbr_h
+#define _rt_mbr_h
+
+#ifdef HAVE_RTREE_KEYS
+
+int maria_rtree_key_cmp(HA_KEYSEG *keyseg, const uchar *a, const uchar *b,
+ uint key_length, uint32 nextflag);
+int maria_rtree_combine_rect(const HA_KEYSEG *keyseg,
+ const uchar *, const uchar *, uchar*,
+ uint key_length);
+double maria_rtree_rect_volume(HA_KEYSEG *keyseg, uchar*, uint key_length);
+int maria_rtree_d_mbr(const HA_KEYSEG *keyseg, const uchar *a,
+ uint key_length, double *res);
+double maria_rtree_overlapping_area(HA_KEYSEG *keyseg, uchar *a, uchar *b,
+ uint key_length);
+double maria_rtree_area_increase(const HA_KEYSEG *keyseg, const uchar *a,
+ const uchar *b,
+ uint key_length, double *ab_area);
+double maria_rtree_perimeter_increase(HA_KEYSEG *keyseg, uchar* a, uchar* b,
+ uint key_length, double *ab_perim);
+int maria_rtree_page_mbr(const MARIA_HA *info, const HA_KEYSEG *keyseg,
+ const uchar *page_buf,
+ uchar* c, uint key_length);
+#endif /*HAVE_RTREE_KEYS*/
+#endif /* _rt_mbr_h */
diff --git a/storage/maria/ma_rt_split.c b/storage/maria/ma_rt_split.c
new file mode 100644
index 00000000000..f2a64c55251
--- /dev/null
+++ b/storage/maria/ma_rt_split.c
@@ -0,0 +1,563 @@
+/* Copyright (C) 2006 MySQL AB & Alexey Botchkov & MySQL Finland AB
+ & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+
+#ifdef HAVE_RTREE_KEYS
+
+#include "ma_rt_index.h"
+#include "ma_rt_key.h"
+#include "ma_rt_mbr.h"
+
+typedef struct
+{
+ double square;
+ int n_node;
+ const uchar *key;
+ double *coords;
+} SplitStruct;
+
+inline static double *reserve_coords(double **d_buffer, int n_dim)
+{
+ double *coords= *d_buffer;
+ (*d_buffer)+= n_dim * 2;
+ return coords;
+}
+
+static void mbr_join(double *a, const double *b, int n_dim)
+{
+ double *end= a + n_dim * 2;
+ do
+ {
+ if (a[0] > b[0])
+ a[0]= b[0];
+
+ if (a[1] < b[1])
+ a[1]= b[1];
+
+ a+= 2;
+ b+= 2;
+ } while (a != end);
+}
+
+/*
+Counts the square of mbr which is a join of a and b
+*/
+static double mbr_join_square(const double *a, const double *b, int n_dim)
+{
+ const double *end= a + n_dim * 2;
+ double square= 1.0;
+ do
+ {
+ square *=
+ ((a[1] < b[1]) ? b[1] : a[1]) - ((a[0] > b[0]) ? b[0] : a[0]);
+
+ a+= 2;
+ b+= 2;
+ } while (a != end);
+
+ return square;
+}
+
+static double count_square(const double *a, int n_dim)
+{
+ const double *end= a + n_dim * 2;
+ double square= 1.0;
+ do
+ {
+ square *= a[1] - a[0];
+ a+= 2;
+ } while (a != end);
+ return square;
+}
+
+inline static void copy_coords(double *dst, const double *src, int n_dim)
+{
+ memcpy(dst, src, sizeof(double) * (n_dim * 2));
+}
+
+/**
+ Select two nodes to collect group upon.
+
+ Note that such function uses 'double' arithmetic so may behave differently
+ on different platforms/builds. There are others in this file.
+*/
+static void pick_seeds(SplitStruct *node, int n_entries,
+ SplitStruct **seed_a, SplitStruct **seed_b, int n_dim)
+{
+ SplitStruct *cur1;
+ SplitStruct *lim1= node + (n_entries - 1);
+ SplitStruct *cur2;
+ SplitStruct *lim2= node + n_entries;
+
+ double max_d= -DBL_MAX;
+ double d;
+
+ for (cur1= node; cur1 < lim1; cur1++)
+ {
+ for (cur2=cur1 + 1; cur2 < lim2; cur2++)
+ {
+
+ d= mbr_join_square(cur1->coords, cur2->coords, n_dim) - cur1->square -
+ cur2->square;
+ if (d > max_d)
+ {
+ max_d= d;
+ *seed_a= cur1;
+ *seed_b= cur2;
+ }
+ }
+ }
+}
+
+/*
+Select next node and group where to add
+*/
+static void pick_next(SplitStruct *node, int n_entries, double *g1, double *g2,
+ SplitStruct **choice, int *n_group, int n_dim)
+{
+ SplitStruct *cur= node;
+ SplitStruct *end= node + n_entries;
+
+ double max_diff= -DBL_MAX;
+
+ for (; cur < end; cur++)
+ {
+ double diff;
+ double abs_diff;
+
+ if (cur->n_node)
+ {
+ continue;
+ }
+
+ diff= mbr_join_square(g1, cur->coords, n_dim) -
+ mbr_join_square(g2, cur->coords, n_dim);
+
+ abs_diff= fabs(diff);
+ if (abs_diff > max_diff)
+ {
+ max_diff= abs_diff;
+ *n_group= 1 + (diff > 0);
+ *choice= cur;
+ }
+ }
+}
+
+/*
+Mark not-in-group entries as n_group
+*/
+static void mark_all_entries(SplitStruct *node, int n_entries, int n_group)
+{
+ SplitStruct *cur= node;
+ SplitStruct *end= node + n_entries;
+
+ for (; cur < end; cur++)
+ {
+ if (cur->n_node)
+ {
+ continue;
+ }
+ cur->n_node= n_group;
+ }
+}
+
+static int split_maria_rtree_node(SplitStruct *node, int n_entries,
+ int all_size, /* Total key's size */
+ int key_size,
+ int min_size, /* Minimal group size */
+ int size1, int size2 /* initial group sizes */,
+ double **d_buffer, int n_dim)
+{
+ SplitStruct *cur;
+ SplitStruct *a;
+ SplitStruct *b;
+ double *g1= reserve_coords(d_buffer, n_dim);
+ double *g2= reserve_coords(d_buffer, n_dim);
+ SplitStruct *next;
+ int next_node;
+ int i;
+ SplitStruct *end= node + n_entries;
+ LINT_INIT(a);
+ LINT_INIT(b);
+ LINT_INIT(next);
+ LINT_INIT(next_node);
+
+ if (all_size < min_size * 2)
+ {
+ return 1;
+ }
+
+ cur= node;
+ for (; cur < end; cur++)
+ {
+ cur->square= count_square(cur->coords, n_dim);
+ cur->n_node= 0;
+ }
+
+ pick_seeds(node, n_entries, &a, &b, n_dim);
+ a->n_node= 1;
+ b->n_node= 2;
+
+
+ copy_coords(g1, a->coords, n_dim);
+ size1+= key_size;
+ copy_coords(g2, b->coords, n_dim);
+ size2+= key_size;
+
+
+ for (i=n_entries - 2; i>0; --i)
+ {
+ if (all_size - (size2 + key_size) < min_size) /* Can't write into group 2 */
+ {
+ mark_all_entries(node, n_entries, 1);
+ break;
+ }
+
+ if (all_size - (size1 + key_size) < min_size) /* Can't write into group 1 */
+ {
+ mark_all_entries(node, n_entries, 2);
+ break;
+ }
+
+ pick_next(node, n_entries, g1, g2, &next, &next_node, n_dim);
+ if (next_node == 1)
+ {
+ size1+= key_size;
+ mbr_join(g1, next->coords, n_dim);
+ }
+ else
+ {
+ size2+= key_size;
+ mbr_join(g2, next->coords, n_dim);
+ }
+ next->n_node= next_node;
+ }
+
+ return 0;
+}
+
+
+/**
+ Logs key reorganization done in a split page (new page is logged elsewhere).
+
+ The effect of a split on the split page is three changes:
+ - some piece of the page move to different places inside this page (we are
+ not interested here in the pieces which move to the new page)
+ - the key is inserted into the page or not (could be in the new page)
+ - page is shrunk
+ All this is uniquely determined by a few parameters:
+ - the key (starting at 'key-nod_flag', for 'full_length' bytes
+ (maria_rtree_split_page() seems to depend on its parameters key&key_length
+ but in fact it reads more (to the left: nod_flag, and to the right:
+ full_length)
+ - the binary content of the page
+ - some variables in the share
+ - double arithmetic, which is unpredictable from machine to machine and
+ from build to build (see pick_seeds() above: it has a comparison between
+ double-s 'if (d > max_d)' so the comparison can go differently from machine
+ to machine or build to build, it has happened in real life).
+ If one day we use precision-math instead of double-math, in GIS, then the
+ last parameter would become constant accross machines and builds and we
+ could some cheap logging: just log the few parameters above.
+ Until then, we log the list of memcpy() operations (fortunately, we often do
+ not have to log the source bytes, as they can be found in the page before
+ applying the REDO; the only source bytes to log are the key), the key if it
+ was inserted into this page, and the shrinking.
+
+ @param info table
+ @param page page's offset in the file
+ @param buff content of the page (post-split)
+ @param key_with_nod_flag pointer to key-nod_flag
+ @param full_length length of (key + (nod_flag (if node) or rowid (if
+ leaf)))
+ @param log_internal_copy encoded list of mempcy() operations done on
+ split page, having their source in the page
+ @param log_internal_copy_length length of above list, in bytes
+ @param log_key_copy operation describing the key's copy, or NULL if the
+ inserted key was not put into the page (was put in
+ new page, so does not have to be logged here)
+ @param length_diff by how much the page has shrunk during split
+*/
+
+static my_bool _ma_log_rt_split(MARIA_HA *info,
+ my_off_t page,
+ const uchar *buff __attribute__((unused)),
+ const uchar *key_with_nod_flag,
+ uint full_length,
+ const uchar *log_internal_copy,
+ uint log_internal_copy_length,
+ const uchar *log_key_copy,
+ uint length_diff)
+{
+ MARIA_SHARE *share= info->s;
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 1 + 2 + 1 + 2 + 2 + 7],
+ *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 5];
+ uint translog_parts, extra_length= 0;
+ DBUG_ENTER("_ma_log_rt_split");
+ DBUG_PRINT("enter", ("page: %lu", (ulong) page));
+
+ DBUG_ASSERT(share->now_transactional);
+ page/= share->block_size;
+ page_store(log_data + FILEID_STORE_SIZE, page);
+ log_pos= log_data+ FILEID_STORE_SIZE + PAGE_STORE_SIZE;
+ log_pos[0]= KEY_OP_DEL_SUFFIX;
+ log_pos++;
+ DBUG_ASSERT((int)length_diff > 0);
+ int2store(log_pos, length_diff);
+ log_pos+= 2;
+ log_pos[0]= KEY_OP_MULTI_COPY;
+ log_pos++;
+ int2store(log_pos, full_length);
+ log_pos+= 2;
+ int2store(log_pos, log_internal_copy_length);
+ log_pos+= 2;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data) - 7;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= log_internal_copy;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= log_internal_copy_length;
+ translog_parts= 2;
+ if (log_key_copy != NULL) /* need to store key into record */
+ {
+ log_array[TRANSLOG_INTERNAL_PARTS + 2].str= log_key_copy;
+ log_array[TRANSLOG_INTERNAL_PARTS + 2].length= 1 + 2 + 1 + 2;
+ log_array[TRANSLOG_INTERNAL_PARTS + 3].str= key_with_nod_flag;
+ log_array[TRANSLOG_INTERNAL_PARTS + 3].length= full_length;
+ extra_length= 1 + 2 + 1 + 2 + full_length;
+ translog_parts+= 2;
+ }
+
+#ifdef EXTRA_DEBUG_KEY_CHANGES
+ {
+ int page_length= _ma_get_page_used(share, buff);
+ ha_checksum crc;
+ uchar *check_start= log_pos;
+ crc= my_checksum(0, buff + LSN_STORE_SIZE, page_length - LSN_STORE_SIZE);
+ log_pos[0]= KEY_OP_CHECK;
+ log_pos++;
+ int2store(log_pos, page_length);
+ log_pos+= 2;
+ int4store(log_pos, crc);
+ log_pos+= 4;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= check_start;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= 7;
+ translog_parts++;
+ }
+#endif
+
+ if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t) ((log_pos - log_data) +
+ log_internal_copy_length +
+ extra_length),
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+/**
+ 0 ok; the created page is put into page cache; the shortened one is not (up
+ to the caller to do it)
+ 1 or -1: error.
+ If new_page_offs==NULL, won't create new page (for redo phase).
+*/
+
+int maria_rtree_split_page(MARIA_HA *info, const MARIA_KEY *key,
+ my_off_t page_offs, uchar *page,
+ my_off_t *new_page_offs)
+{
+ MARIA_SHARE *share= info->s;
+ const my_bool transactional= share->now_transactional;
+ int n1, n2; /* Number of items in groups */
+ SplitStruct *task;
+ SplitStruct *cur;
+ SplitStruct *stop;
+ double *coord_buf;
+ double *next_coord;
+ double *old_coord;
+ int n_dim;
+ uchar *source_cur, *cur1, *cur2;
+ uchar *new_page, *log_internal_copy, *log_internal_copy_ptr,
+ *log_key_copy= NULL;
+ int err_code= 0;
+ uint nod_flag= _ma_test_if_nod(share, page);
+ uint org_length= _ma_get_page_used(share, page), new_length;
+ uint full_length= key->data_length + (nod_flag ? nod_flag :
+ key->ref_length);
+ uint key_data_length= key->data_length;
+ int max_keys= ((org_length - share->keypage_header) / (full_length));
+ MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("maria_rtree_split_page");
+ DBUG_PRINT("rtree", ("splitting block"));
+
+ n_dim= keyinfo->keysegs / 2;
+
+ if (!(coord_buf= (double*) my_alloca(n_dim * 2 * sizeof(double) *
+ (max_keys + 1 + 4) +
+ sizeof(SplitStruct) * (max_keys + 1))))
+ DBUG_RETURN(-1); /* purecov: inspected */
+
+ task= (SplitStruct *)(coord_buf + n_dim * 2 * (max_keys + 1 + 4));
+
+ next_coord= coord_buf;
+
+ stop= task + max_keys;
+ source_cur= rt_PAGE_FIRST_KEY(share, page, nod_flag);
+
+ for (cur= task;
+ cur < stop;
+ cur++, source_cur= rt_PAGE_NEXT_KEY(share, source_cur, key_data_length,
+ nod_flag))
+ {
+ cur->coords= reserve_coords(&next_coord, n_dim);
+ cur->key= source_cur;
+ maria_rtree_d_mbr(keyinfo->seg, source_cur, key_data_length, cur->coords);
+ }
+
+ cur->coords= reserve_coords(&next_coord, n_dim);
+ maria_rtree_d_mbr(keyinfo->seg, key->data, key_data_length, cur->coords);
+ cur->key= key->data;
+
+ old_coord= next_coord;
+
+ if (split_maria_rtree_node(task, max_keys + 1,
+ _ma_get_page_used(share, page) + full_length + 2,
+ full_length,
+ rt_PAGE_MIN_SIZE(keyinfo->block_length),
+ 2, 2, &next_coord, n_dim))
+ {
+ err_code= 1;
+ goto split_err;
+ }
+
+ /* Allocate buffer for new page and piece of log record */
+ if (!(new_page= (uchar*) my_alloca((uint)keyinfo->block_length +
+ (transactional ?
+ (max_keys * (2 + 2) +
+ 1 + 2 + 1 + 2) : 0))))
+ {
+ err_code= -1;
+ goto split_err;
+ }
+ log_internal_copy= log_internal_copy_ptr= new_page + keyinfo->block_length;
+ bzero(new_page, share->block_size);
+
+ stop= task + (max_keys + 1);
+ cur1= rt_PAGE_FIRST_KEY(share, page, nod_flag);
+ cur2= rt_PAGE_FIRST_KEY(share, new_page, nod_flag);
+
+ n1= n2= 0;
+ for (cur= task; cur < stop; cur++)
+ {
+ uchar *to;
+ const uchar *cur_key= cur->key;
+ my_bool log_this_change;
+ DBUG_ASSERT(log_key_copy == NULL);
+ if (cur->n_node == 1)
+ {
+ to= cur1;
+ cur1= rt_PAGE_NEXT_KEY(share, cur1, key_data_length, nod_flag);
+ n1++;
+ log_this_change= transactional;
+ }
+ else
+ {
+ to= cur2;
+ cur2= rt_PAGE_NEXT_KEY(share, cur2, key_data_length, nod_flag);
+ n2++;
+ log_this_change= FALSE;
+ }
+ if (to != cur_key)
+ {
+ uchar *to_with_nod_flag= to - nod_flag;
+ const uchar *cur_key_with_nod_flag= cur_key - nod_flag;
+ memcpy(to_with_nod_flag, cur_key_with_nod_flag, full_length);
+ if (log_this_change)
+ {
+ uint to_with_nod_flag_offs= to_with_nod_flag - page;
+ if (likely(cur_key != key->data))
+ {
+ /* this memcpy() is internal to the page (source in the page) */
+ uint cur_key_with_nod_flag_offs= cur_key_with_nod_flag - page;
+ int2store(log_internal_copy_ptr, to_with_nod_flag_offs);
+ log_internal_copy_ptr+= 2;
+ int2store(log_internal_copy_ptr, cur_key_with_nod_flag_offs);
+ log_internal_copy_ptr+= 2;
+ }
+ else
+ {
+ /* last iteration, and this involves *key: source is external */
+ log_key_copy= log_internal_copy_ptr;
+ log_key_copy[0]= KEY_OP_OFFSET;
+ int2store(log_key_copy + 1, to_with_nod_flag_offs);
+ log_key_copy[3]= KEY_OP_CHANGE;
+ int2store(log_key_copy + 4, full_length);
+ /* _ma_log_rt_split() will store *key, right after */
+ }
+ }
+ }
+ }
+ { /* verify that above loop didn't touch header bytes */
+ uint i;
+ for (i= 0; i < share->keypage_header; i++)
+ DBUG_ASSERT(new_page[i]==0);
+ }
+
+ if (nod_flag)
+ _ma_store_keypage_flag(share, new_page, KEYPAGE_FLAG_ISNOD);
+ _ma_store_keynr(share, new_page, keyinfo->key_nr);
+ _ma_store_page_used(share, new_page, share->keypage_header +
+ n2 * full_length);
+ new_length= share->keypage_header + n1 * full_length;
+ _ma_store_page_used(share, page, new_length);
+
+ if ((*new_page_offs= _ma_new(info, DFLT_INIT_HITS, &page_link)) ==
+ HA_OFFSET_ERROR)
+ err_code= -1;
+ else
+ {
+ if (transactional &&
+ ( /* log change to split page */
+ _ma_log_rt_split(info, page_offs, page, key->data - nod_flag,
+ full_length, log_internal_copy,
+ log_internal_copy_ptr - log_internal_copy,
+ log_key_copy, org_length - new_length) ||
+ /* and to new page */
+ _ma_log_new(info, *new_page_offs, new_page,
+ share->keypage_header + n2 * full_length,
+ keyinfo->key_nr, 0)))
+ err_code= -1;
+ if ( _ma_write_keypage(info, keyinfo, *new_page_offs,
+ page_link->write_lock,
+ DFLT_INIT_HITS, new_page))
+ err_code= -1;
+ }
+ DBUG_PRINT("rtree", ("split new block: %lu", (ulong) *new_page_offs));
+
+ my_afree(new_page);
+
+split_err:
+ my_afree(coord_buf);
+ DBUG_RETURN(err_code);
+}
+
+#endif /*HAVE_RTREE_KEYS*/
diff --git a/storage/maria/ma_rt_test.c b/storage/maria/ma_rt_test.c
new file mode 100644
index 00000000000..af54e6b27be
--- /dev/null
+++ b/storage/maria/ma_rt_test.c
@@ -0,0 +1,692 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Testing of the basic functions of a MARIA rtree table */
+/* Written by Alex Barkov who has a shared copyright to this code */
+
+
+#include "maria_def.h"
+#include "ma_control_file.h"
+#include "ma_loghandler.h"
+#include "ma_checkpoint.h"
+#include "trnman.h"
+#include <my_getopt.h>
+
+#ifdef HAVE_RTREE_KEYS
+
+#include "ma_rt_index.h"
+
+#define MAX_REC_LENGTH 1024
+#define ndims 2
+#define KEYALG HA_KEY_ALG_RTREE
+
+static int read_with_pos(MARIA_HA * file);
+static void create_record(uchar *record,uint rownr);
+static void create_record1(uchar *record,uint rownr);
+static void print_record(uchar * record,my_off_t offs,const char * tail);
+static int run_test(const char *filename);
+static void get_options(int argc, char *argv[]);
+static void usage();
+
+static double rt_data[]=
+{
+ /*1*/ 0,10,0,10,
+ /*2*/ 5,15,0,10,
+ /*3*/ 0,10,5,15,
+ /*4*/ 10,20,10,20,
+ /*5*/ 0,10,0,10,
+ /*6*/ 5,15,0,10,
+ /*7*/ 0,10,5,15,
+ /*8*/ 10,20,10,20,
+ /*9*/ 0,10,0,10,
+ /*10*/ 5,15,0,10,
+ /*11*/ 0,10,5,15,
+ /*12*/ 10,20,10,20,
+ /*13*/ 0,10,0,10,
+ /*14*/ 5,15,0,10,
+ /*15*/ 0,10,5,15,
+ /*16*/ 10,20,10,20,
+ /*17*/ 5,15,0,10,
+ /*18*/ 0,10,5,15,
+ /*19*/ 10,20,10,20,
+ /*20*/ 0,10,0,10,
+
+ /*1*/ 100,110,0,10,
+ /*2*/ 105,115,0,10,
+ /*3*/ 100,110,5,15,
+ /*4*/ 110,120,10,20,
+ /*5*/ 100,110,0,10,
+ /*6*/ 105,115,0,10,
+ /*7*/ 100,110,5,15,
+ /*8*/ 110,120,10,20,
+ /*9*/ 100,110,0,10,
+ /*10*/ 105,115,0,10,
+ /*11*/ 100,110,5,15,
+ /*12*/ 110,120,10,20,
+ /*13*/ 100,110,0,10,
+ /*14*/ 105,115,0,10,
+ /*15*/ 100,110,5,15,
+ /*16*/ 110,120,10,20,
+ /*17*/ 105,115,0,10,
+ /*18*/ 100,110,5,15,
+ /*19*/ 110,120,10,20,
+ /*20*/ 100,110,0,10,
+ -1
+};
+
+static int testflag, checkpoint, create_flag;
+static my_bool silent, transactional, die_in_middle_of_transaction,
+ opt_versioning;
+static enum data_file_type record_type= DYNAMIC_RECORD;
+
+int main(int argc, char *argv[])
+{
+ MY_INIT(argv[0]);
+ get_options(argc, argv);
+ maria_data_root= (char *)".";
+ /* Maria requires that we always have a page cache */
+ if (maria_init() ||
+ (init_pagecache(maria_pagecache, maria_block_size * 16, 0, 0,
+ maria_block_size, MY_WME) == 0) ||
+ ma_control_file_open(TRUE, TRUE) ||
+ (init_pagecache(maria_log_pagecache,
+ TRANSLOG_PAGECACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, MY_WME) == 0) ||
+ translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
+ 0, 0, maria_log_pagecache,
+ TRANSLOG_DEFAULT_FLAGS, 0) ||
+ (transactional && (trnman_init(0) || ma_checkpoint_init(0))))
+ {
+ fprintf(stderr, "Error in initialization\n");
+ exit(1);
+ }
+
+ exit(run_test("rt_test"));
+}
+
+
+static int run_test(const char *filename)
+{
+ MARIA_HA *file;
+ MARIA_UNIQUEDEF uniquedef;
+ MARIA_CREATE_INFO create_info;
+ MARIA_COLUMNDEF recinfo[20];
+ MARIA_KEYDEF keyinfo[20];
+ HA_KEYSEG keyseg[20];
+ key_range range;
+
+ int opt_unique=0;
+ int key_type=HA_KEYTYPE_DOUBLE;
+ int key_length=8;
+ int null_fields=0;
+ int nrecords=sizeof(rt_data)/(sizeof(double)*4);/* 40 */
+ int rec_length=0;
+ int uniques=0;
+ int i, max_i;
+ int error;
+ int row_count=0;
+ uchar record[MAX_REC_LENGTH];
+ uchar read_record[MAX_REC_LENGTH];
+ int upd= 10;
+ ha_rows hrows;
+
+ bzero(&uniquedef, sizeof(uniquedef));
+ bzero(&create_info, sizeof(create_info));
+ bzero(recinfo, sizeof(recinfo));
+ bzero(keyinfo, sizeof(keyinfo));
+ bzero(keyseg, sizeof(keyseg));
+
+ /* Define a column for NULLs and DEL markers*/
+
+ recinfo[0].type=FIELD_NORMAL;
+ recinfo[0].length=1; /* For NULL bits */
+ rec_length=1;
+
+ /* Define 2*ndims columns for coordinates*/
+
+ for (i=1; i<=2*ndims ;i++)
+ {
+ recinfo[i].type=FIELD_NORMAL;
+ recinfo[i].length=key_length;
+ rec_length+=key_length;
+ }
+
+ /* Define a key with 2*ndims segments */
+
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=2*ndims;
+ keyinfo[0].flag=0;
+ keyinfo[0].key_alg=KEYALG;
+
+ for (i=0; i<2*ndims; i++)
+ {
+ keyinfo[0].seg[i].type= key_type;
+ keyinfo[0].seg[i].flag=0; /* Things like HA_REVERSE_SORT */
+ keyinfo[0].seg[i].start= (key_length*i)+1;
+ keyinfo[0].seg[i].length=key_length;
+ keyinfo[0].seg[i].null_bit= null_fields ? 2 : 0;
+ keyinfo[0].seg[i].null_pos=0;
+ keyinfo[0].seg[i].language=default_charset_info->number;
+ }
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+
+ create_info.max_rows=10000000;
+ create_info.transactional= transactional;
+
+ if (maria_create(filename,
+ record_type,
+ 1, /* keys */
+ keyinfo,
+ 1+2*ndims+opt_unique, /* columns */
+ recinfo,uniques,&uniquedef,&create_info,create_flag))
+ goto err;
+
+ if (!silent)
+ printf("- Open isam-file\n");
+
+ if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ maria_begin(file);
+ if (opt_versioning)
+ maria_versioning(file, 1);
+ if (testflag == 1)
+ goto end;
+ if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ for (i=0; i<nrecords; i++ )
+ {
+ create_record(record,i);
+ error=maria_write(file,record);
+ print_record(record,maria_position(file),"\n");
+ if (!error)
+ {
+ row_count++;
+ }
+ else
+ {
+ fprintf(stderr, "maria_write: %d\n", error);
+ goto err;
+ }
+ }
+
+ if (maria_scan_init(file))
+ {
+ fprintf(stderr, "maria_scan_init failed\n");
+ goto err;
+ }
+ if ((error=read_with_pos(file)))
+ goto err;
+ maria_scan_end(file);
+
+ if (!silent)
+ printf("- Reading rows with key\n");
+
+ for (i=0 ; i < nrecords ; i++)
+ {
+ my_errno=0;
+ create_record(record,i);
+
+ bzero((char*) read_record,MAX_REC_LENGTH);
+ error=maria_rkey(file,read_record,0,record+1,HA_WHOLE_KEY,HA_READ_MBR_EQUAL);
+
+ if (error && error!=HA_ERR_KEY_NOT_FOUND)
+ {
+ fprintf(stderr," maria_rkey: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ if (error == HA_ERR_KEY_NOT_FOUND)
+ {
+ print_record(record,maria_position(file)," NOT FOUND\n");
+ continue;
+ }
+ print_record(read_record,maria_position(file),"\n");
+ }
+
+ if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (testflag == 2)
+ goto end;
+
+ if (!silent)
+ printf("- Deleting rows\n");
+ if (maria_scan_init(file))
+ {
+ fprintf(stderr, "maria_scan_init failed\n");
+ goto err;
+ }
+
+ for (i=0; i < nrecords/4; i++)
+ {
+ my_errno=0;
+ bzero((char*) read_record,MAX_REC_LENGTH);
+ error=maria_scan(file,read_record);
+ if (error)
+ {
+ fprintf(stderr, "pos: %2d maria_rrnd: %3d errno: %3d\n", i, error,
+ my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file),"\n");
+
+ error=maria_delete(file,read_record);
+ if (error)
+ {
+ fprintf(stderr, "pos: %2d maria_delete: %3d errno: %3d\n", i, error,
+ my_errno);
+ goto err;
+ }
+ }
+ maria_scan_end(file);
+
+ if (testflag == 3)
+ goto end;
+ if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (!silent)
+ printf("- Updating rows with position\n");
+ if (maria_scan_init(file))
+ {
+ fprintf(stderr, "maria_scan_init failed\n");
+ goto err;
+ }
+
+ /* We are looking for nrecords-necords/2 non-deleted records */
+ for (i=0, max_i= nrecords - nrecords/2; i < max_i ; i++)
+ {
+ my_errno=0;
+ bzero((char*) read_record,MAX_REC_LENGTH);
+ error=maria_scan(file,read_record);
+ if (error)
+ {
+ if (error==HA_ERR_RECORD_DELETED)
+ {
+ if (!silent)
+ printf("found deleted record\n");
+ /*
+ In BLOCK_RECORD format, maria_scan() never returns deleted records,
+ while in DYNAMIC format it can. Don't count such record:
+ */
+ max_i++;
+ continue;
+ }
+ fprintf(stderr, "pos: %2d maria_rrnd: %3d errno: %3d\n",i , error,
+ my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file),"");
+ create_record1(record,i+nrecords*upd);
+ if (!silent)
+ printf("\t-> ");
+ print_record(record,maria_position(file),"\n");
+ error=maria_update(file,read_record,record);
+ if (error)
+ {
+ fprintf(stderr, "pos: %2d maria_update: %3d errno: %3d\n",i, error,
+ my_errno);
+ goto err;
+ }
+ }
+
+ if (testflag == 4)
+ goto end;
+ if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (maria_scan_init(file))
+ {
+ fprintf(stderr, "maria_scan_init failed\n");
+ goto err;
+ }
+ if ((error=read_with_pos(file)))
+ goto err;
+ maria_scan_end(file);
+
+ if (!silent)
+ printf("- Test maria_rkey then a sequence of maria_rnext_same\n");
+
+ create_record(record, nrecords*4/5);
+ print_record(record,0," search for\n");
+
+ if ((error=maria_rkey(file,read_record,0,record+1,HA_WHOLE_KEY,
+ HA_READ_MBR_INTERSECT)))
+ {
+ fprintf(stderr, "maria_rkey: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file)," maria_rkey\n");
+ row_count=1;
+
+ for (;;)
+ {
+ if ((error=maria_rnext_same(file,read_record)))
+ {
+ if (error==HA_ERR_END_OF_FILE)
+ break;
+ fprintf(stderr, "maria_next: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file)," maria_rnext_same\n");
+ row_count++;
+ }
+ if (!silent)
+ printf(" %d rows\n",row_count);
+
+ if (!silent)
+ printf("- Test maria_rfirst then a sequence of maria_rnext\n");
+
+ error=maria_rfirst(file,read_record,0);
+ if (error)
+ {
+ fprintf(stderr, "maria_rfirst: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ row_count=1;
+ print_record(read_record,maria_position(file)," maria_frirst\n");
+
+ for (i=0;i<nrecords;i++)
+ {
+ if ((error=maria_rnext(file,read_record,0)))
+ {
+ if (error==HA_ERR_END_OF_FILE)
+ break;
+ fprintf(stderr, "maria_next: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file)," maria_rnext\n");
+ row_count++;
+ }
+ if (!silent)
+ printf(" %d rows\n",row_count);
+
+ if (!silent)
+ printf("- Test maria_records_in_range()\n");
+
+ create_record1(record, nrecords*4/5);
+ print_record(record,0,"\n");
+
+ range.key= record+1;
+ range.length= 1000; /* Big enough */
+ range.flag= HA_READ_MBR_INTERSECT;
+ hrows= maria_records_in_range(file,0, &range, (key_range*) 0);
+ if (!silent)
+ printf(" %ld rows\n", (long) hrows);
+
+end:
+ maria_scan_end(file);
+ if (die_in_middle_of_transaction)
+ {
+ /* see similar code in ma_test2.c for comments */
+ switch (die_in_middle_of_transaction) {
+ case 1:
+ _ma_flush_table_files(file, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_RELEASE, FLUSH_RELEASE);
+ break;
+ case 2:
+ if (translog_flush(file->trn->undo_lsn))
+ goto err;
+ break;
+ case 3:
+ break;
+ case 4:
+ _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE,
+ FLUSH_RELEASE);
+ if (translog_flush(file->trn->undo_lsn))
+ goto err;
+ break;
+ }
+ if (!silent)
+ printf("Dying on request without maria_commit()/maria_close()\n");
+ exit(0);
+ }
+ if (maria_commit(file))
+ goto err;
+ if (maria_close(file)) goto err;
+ maria_end();
+ my_end(MY_CHECK_ERROR);
+
+ return 0;
+
+err:
+ fprintf(stderr, "got error: %3d when using maria-database\n",my_errno);
+ return 1; /* skip warning */
+}
+
+
+
+static int read_with_pos (MARIA_HA * file)
+{
+ int error;
+ int i;
+ uchar read_record[MAX_REC_LENGTH];
+
+ if (!silent)
+ printf("- Reading rows with position\n");
+ for (i=0;;i++)
+ {
+ my_errno=0;
+ bzero((char*) read_record,MAX_REC_LENGTH);
+ error=maria_scan(file,read_record);
+ if (error)
+ {
+ if (error==HA_ERR_END_OF_FILE)
+ break;
+ if (error==HA_ERR_RECORD_DELETED)
+ continue;
+ fprintf(stderr, "pos: %2d maria_rrnd: %3d errno: %3d\n", i, error,
+ my_errno);
+ return error;
+ }
+ print_record(read_record,maria_position(file),"\n");
+ }
+ return 0;
+}
+
+
+#ifdef NOT_USED
+static void bprint_record(char * record,
+ my_off_t offs __attribute__((unused)),
+ const char * tail)
+{
+ int i;
+ char * pos;
+ if (silent)
+ return;
+ i=(unsigned char)record[0];
+ printf("%02X ",i);
+
+ for( pos=record+1, i=0; i<32; i++,pos++){
+ int b=(unsigned char)*pos;
+ printf("%02X",b);
+ }
+ printf("%s",tail);
+}
+#endif
+
+
+static void print_record(uchar *record,
+ my_off_t offs __attribute__((unused)),
+ const char * tail)
+{
+ int i;
+ uchar *pos;
+ double c;
+
+ if (silent)
+ return;
+ printf(" rec=(%d)",(unsigned char)record[0]);
+ for ( pos=record+1, i=0; i<2*ndims; i++)
+ {
+ memcpy(&c,pos,sizeof(c));
+ float8get(c,pos);
+ printf(" %.14g ",c);
+ pos+=sizeof(c);
+ }
+ printf("pos=%ld",(long int)offs);
+ printf("%s",tail);
+}
+
+
+
+static void create_record1(uchar *record, uint rownr)
+{
+ int i;
+ uchar *pos;
+ double c=rownr+10;
+
+ bzero((char*) record,MAX_REC_LENGTH);
+ record[0]=0x01; /* DEL marker */
+
+ for ( pos=record+1, i=0; i<2*ndims; i++)
+ {
+ memcpy(pos,&c,sizeof(c));
+ float8store(pos,c);
+ pos+=sizeof(c);
+ }
+}
+
+#ifdef NOT_USED
+
+static void create_record0(char *record,uint rownr)
+{
+ int i;
+ char * pos;
+ double c=rownr+10;
+ double c0=0;
+
+ bzero((char*) record,MAX_REC_LENGTH);
+ record[0]=0x01; /* DEL marker */
+
+ for ( pos=record+1, i=0; i<ndims; i++)
+ {
+ memcpy(pos,&c0,sizeof(c0));
+ float8store(pos,c0);
+ pos+=sizeof(c0);
+ memcpy(pos,&c,sizeof(c));
+ float8store(pos,c);
+ pos+=sizeof(c);
+ }
+}
+
+#endif
+
+static void create_record(uchar *record, uint rownr)
+{
+ int i;
+ uchar *pos;
+ double *data= rt_data+rownr*4;
+ record[0]=0x01; /* DEL marker */
+ for ( pos=record+1, i=0; i<ndims*2; i++)
+ {
+ float8store(pos,data[i]);
+ pos+=8;
+ }
+}
+
+
+static struct my_option my_long_options[] =
+{
+ {"checkpoint", 'H', "Checkpoint at specified stage", (uchar**) &checkpoint,
+ (uchar**) &checkpoint, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"checksum", 'c', "Undocumented",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+ {"debug", '#', "Undocumented",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"help", '?', "Display help and exit",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"row-fixed-size", 'S', "Fixed size records",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"rows-in-block", 'M', "Store rows in block format",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"silent", 's', "Undocumented",
+ (uchar**) &silent, (uchar**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
+ 0, 0},
+ {"testflag", 't', "Stop test at specified stage", (uchar**) &testflag,
+ (uchar**) &testflag, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"test-undo", 'A',
+ "Abort hard. Used for testing recovery with undo",
+ (uchar**) &die_in_middle_of_transaction,
+ (uchar**) &die_in_middle_of_transaction,
+ 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"transactional", 'T',
+ "Test in transactional mode. (Only works with block format)",
+ (uchar**) &transactional, (uchar**) &transactional, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+ {"versioning", 'C', "Use row versioning (only works with block format)",
+ (uchar**) &opt_versioning, (uchar**) &opt_versioning, 0, GET_BOOL,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch(optid) {
+ case 'c':
+ create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
+ break;
+ case 'M':
+ record_type= BLOCK_RECORD;
+ break;
+ case 'S':
+ record_type= STATIC_RECORD;
+ break;
+ case '#':
+ DBUG_PUSH(argument);
+ break;
+ case '?':
+ usage();
+ exit(1);
+ }
+ return 0;
+}
+
+
+/* Read options */
+
+static void get_options(int argc, char *argv[])
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ return;
+} /* get options */
+
+
+static void usage()
+{
+ printf("Usage: %s [options]\n\n", my_progname);
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
+
+#else
+int main(int argc __attribute__((unused)),char *argv[] __attribute__((unused)))
+{
+ exit(0);
+}
+#endif /*HAVE_RTREE_KEYS*/
diff --git a/storage/maria/ma_scan.c b/storage/maria/ma_scan.c
new file mode 100644
index 00000000000..cbac463a2c8
--- /dev/null
+++ b/storage/maria/ma_scan.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Read through all rows sequntially */
+
+#include "maria_def.h"
+
+int maria_scan_init(register MARIA_HA *info)
+{
+ DBUG_ENTER("maria_scan_init");
+
+ info->cur_row.nextpos= info->s->pack.header_length; /* Read first record */
+ info->lastinx= -1; /* Can't forward or backward */
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+
+ if ((*info->s->scan_init)(info))
+ DBUG_RETURN(my_errno);
+ DBUG_RETURN(0);
+}
+
+/*
+ Read a row based on position.
+
+ SYNOPSIS
+ maria_scan()
+ info Maria handler
+ record Read data here
+
+ RETURN
+ 0 ok
+ HA_ERR_END_OF_FILE End of file
+ HA_ERR_RECORD_DELETED Record was deleted (can only happen for static rec)
+ # Error code
+*/
+
+int maria_scan(MARIA_HA *info, uchar *record)
+{
+ DBUG_ENTER("maria_scan");
+ /* Init all but update-flag */
+ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+ DBUG_RETURN((*info->s->scan)(info, record, info->cur_row.nextpos, 1));
+}
+
+
+void maria_scan_end(MARIA_HA *info)
+{
+ (*info->s->scan_end)(info);
+}
+
+
+int _ma_def_scan_remember_pos(MARIA_HA *info, MARIA_RECORD_POS *lastpos)
+{
+ *lastpos= info->cur_row.lastpos;
+ return 0;
+}
+
+
+void _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos)
+{
+ info->cur_row.nextpos= lastpos;
+}
diff --git a/storage/maria/ma_search.c b/storage/maria/ma_search.c
new file mode 100644
index 00000000000..470011cb247
--- /dev/null
+++ b/storage/maria/ma_search.c
@@ -0,0 +1,2352 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* key handling functions */
+
+#include "ma_fulltext.h"
+#include "m_ctype.h"
+
+static my_bool _ma_get_prev_key(MARIA_KEY *key, uchar *page, uchar *keypos);
+
+
+/* Check that new index is ok */
+
+int _ma_check_index(MARIA_HA *info, int inx)
+{
+ if (inx < 0 || ! maria_is_key_active(info->s->state.key_map, inx))
+ {
+ my_errno=HA_ERR_WRONG_INDEX;
+ return -1;
+ }
+ if (info->lastinx != inx) /* Index changed */
+ {
+ info->lastinx = inx;
+ info->page_changed=1;
+ info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
+ HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
+ }
+ if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
+ return(-1);
+ return(inx);
+} /* _ma_check_index */
+
+
+/**
+ @breif Search after row by a key
+
+ @note
+ Position to row is stored in info->lastpos
+
+ @return
+ @retval 0 ok (key found)
+ @retval -1 Not found
+ @retval 1 If one should continue search on higher level
+*/
+
+int _ma_search(register MARIA_HA *info, MARIA_KEY *key, uint32 nextflag,
+ register my_off_t pos)
+{
+ my_bool last_key_not_used;
+ int error,flag;
+ uint page_flag, nod_flag, used_length;
+ uchar *keypos,*maxpos;
+ uchar lastkey[MARIA_MAX_KEY_BUFF],*buff;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_search");
+ DBUG_PRINT("enter",("pos: %lu nextflag: %u lastpos: %lu",
+ (ulong) pos, nextflag, (ulong) info->cur_row.lastpos));
+ DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, key););
+
+ if (pos == HA_OFFSET_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
+ DBUG_RETURN(-1); /* Not found ; return error */
+ DBUG_RETURN(1); /* Search at upper levels */
+ }
+
+ if (!(buff= _ma_fetch_keypage(info, keyinfo, pos,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, info->keyread_buff,
+ test(!(nextflag & SEARCH_SAVE_BUFF)), 0)))
+ goto err;
+ DBUG_DUMP("page", buff, _ma_get_page_used(info->s, buff));
+
+ flag= (*keyinfo->bin_search)(key, buff, nextflag, &keypos, lastkey,
+ &last_key_not_used);
+ if (flag == MARIA_FOUND_WRONG_KEY)
+ DBUG_RETURN(-1);
+ page_flag= _ma_get_keypage_flag(info->s, buff);
+ _ma_get_used_and_nod_with_flag(info->s, page_flag, buff, used_length,
+ nod_flag);
+ maxpos= buff + used_length -1;
+
+ if (flag)
+ {
+ if ((error= _ma_search(info, key, nextflag,
+ _ma_kpos(nod_flag,keypos))) <= 0)
+ DBUG_RETURN(error);
+
+ if (flag >0)
+ {
+ if (nextflag & (SEARCH_SMALLER | SEARCH_LAST) &&
+ keypos == buff + info->s->keypage_header + nod_flag)
+ DBUG_RETURN(1); /* Bigger than key */
+ }
+ else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
+ DBUG_RETURN(1); /* Smaller than key */
+ }
+ else
+ {
+ /* Found matching key */
+ if ((nextflag & SEARCH_FIND) && nod_flag &&
+ ((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
+ (key->flag & SEARCH_PART_KEY) || info->s->base.born_transactional))
+ {
+ if ((error= _ma_search(info, key, (nextflag | SEARCH_FIND) &
+ ~(SEARCH_BIGGER | SEARCH_SMALLER | SEARCH_LAST),
+ _ma_kpos(nod_flag,keypos))) >= 0 ||
+ my_errno != HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(error);
+ info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in mem */
+ }
+ }
+ if (pos != info->last_keypage)
+ {
+ uchar *old_buff=buff;
+ if (!(buff= _ma_fetch_keypage(info,keyinfo, pos,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,DFLT_INIT_HITS,
+ info->keyread_buff,
+ test(!(nextflag & SEARCH_SAVE_BUFF)), 0)))
+ goto err;
+ keypos=buff+(keypos-old_buff);
+ maxpos=buff+(maxpos-old_buff);
+ }
+
+ info->last_key.keyinfo= keyinfo;
+ if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
+ {
+ uint not_used[2];
+ if (_ma_get_prev_key(&info->last_key, buff, keypos))
+ goto err;
+ /*
+ We have to use key->flag >> 1 here to transform
+ SEARCH_PAGE_KEY_HAS_TRANSID to SEARCH_USER_KEY_HAS_TRANSID
+ */
+ if (!(nextflag & SEARCH_SMALLER) &&
+ ha_key_cmp(keyinfo->seg, info->last_key.data, key->data,
+ key->data_length + key->ref_length,
+ SEARCH_FIND | (key->flag >> 1) | info->last_key.flag,
+ not_used))
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ goto err;
+ }
+ }
+ else
+ {
+ /* Set info->last_key to temporarily point to last key value */
+ info->last_key.data= lastkey;
+ /* Get key value (if not packed key) and position after key */
+ if (!(*keyinfo->get_key)(&info->last_key, page_flag, nod_flag, &keypos))
+ goto err;
+ memcpy(info->lastkey_buff, lastkey,
+ info->last_key.data_length + info->last_key.ref_length);
+ info->last_key.data= info->lastkey_buff;
+ }
+ info->cur_row.lastpos= _ma_row_pos_from_key(&info->last_key);
+ info->cur_row.trid= _ma_trid_from_key(&info->last_key);
+ /* Save position for a possible read next / previous */
+ info->int_keypos= info->keyread_buff+ (keypos-buff);
+ info->int_maxpos= info->keyread_buff+ (maxpos-buff);
+ info->int_nod_flag=nod_flag;
+ info->int_keytree_version=keyinfo->version;
+ info->last_search_keypage=info->last_keypage;
+ info->page_changed=0;
+ /* Set marker that buffer was used (Marker for mi_search_next()) */
+ info->keyread_buff_used= (info->keyread_buff != buff);
+
+ DBUG_PRINT("exit",("found key at %lu",(ulong) info->cur_row.lastpos));
+ DBUG_RETURN(0);
+
+err:
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ info->page_changed=1;
+ DBUG_RETURN (-1);
+} /* _ma_search */
+
+
+/*
+ Search after key in page-block
+
+ @fn _ma_bin_search
+ @param key Search after this key
+ @param page Start of data page
+ @param comp_flag How key should be compared
+ @param ret_pos
+ @param buff Buffer for holding a key (not used here)
+ @param last_key
+
+ @note
+ If keys are packed, then smaller or identical key is stored in buff
+
+ @return
+ @retval <0, 0 , >0 depending on if if found is smaller, equal or bigger than
+ 'key'
+ @retval ret_pos Points to where the identical or bigger key starts
+ @retval last_key Set to 1 if key is the last key in the page.
+*/
+
+int _ma_bin_search(const MARIA_KEY *key, uchar *page,
+ uint32 comp_flag, uchar **ret_pos,
+ uchar *buff __attribute__((unused)), my_bool *last_key)
+{
+ int flag;
+ uint page_flag;
+ uint start, mid, end, save_end, totlength, nod_flag, used_length;
+ uint not_used[2];
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ MARIA_SHARE *share= keyinfo->share;
+ DBUG_ENTER("_ma_bin_search");
+
+ LINT_INIT(flag);
+
+ page_flag= _ma_get_keypage_flag(share, page);
+ if (page_flag & KEYPAGE_FLAG_HAS_TRANSID)
+ {
+ /* Keys have varying length, can't use binary search */
+ DBUG_RETURN(_ma_seq_search(key, page, comp_flag, ret_pos, buff, last_key));
+ }
+
+ _ma_get_used_and_nod_with_flag(share, page_flag, page, used_length,
+ nod_flag);
+ totlength= keyinfo->keylength + nod_flag;
+ DBUG_ASSERT(used_length >= share->keypage_header + nod_flag + totlength);
+
+ start=0;
+ mid=1;
+ save_end= end= ((used_length - nod_flag - share->keypage_header) /
+ totlength-1);
+ DBUG_PRINT("test",("page_length: %u end: %u", used_length, end));
+ page+= share->keypage_header + nod_flag;
+
+ while (start != end)
+ {
+ mid= (start+end)/2;
+ if ((flag=ha_key_cmp(keyinfo->seg, page + (uint) mid * totlength,
+ key->data, key->data_length + key->ref_length,
+ comp_flag, not_used))
+ >= 0)
+ end=mid;
+ else
+ start=mid+1;
+ }
+ if (mid != start)
+ flag=ha_key_cmp(keyinfo->seg, page + (uint) start * totlength,
+ key->data, key->data_length + key->ref_length, comp_flag,
+ not_used);
+ if (flag < 0)
+ start++; /* point at next, bigger key */
+ *ret_pos= (page + (uint) start * totlength);
+ *last_key= end == save_end;
+ DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start));
+ DBUG_RETURN(flag);
+} /* _ma_bin_search */
+
+
+/**
+ Locate a packed key in a key page.
+
+ @fn _ma_seq_search()
+ @param key Search key.
+ @param page Key page (beginning).
+ @param comp_flag Search flags like SEARCH_SAME etc.
+ @param ret_pos
+ @param buff Buffer for holding temp keys
+ @param last_key
+
+ @description
+ Used instead of _ma_bin_search() when key is packed.
+ Puts smaller or identical key in buff.
+ Key is searched sequentially.
+
+ @todo
+ Don't copy key to buffer if we are not using key with prefix packing
+
+ @return
+ @retval > 0 Key in 'buff' is smaller than search key.
+ @retval 0 Key in 'buff' is identical to search key.
+ @retval < 0 Not found.
+
+ @retval ret_pos Points to where the identical or bigger key starts
+ @retval last_key Set to 1 if key is the last key in the page
+ @retval buff Copy of previous or identical unpacked key
+*/
+
+int _ma_seq_search(const MARIA_KEY *key, uchar *page,
+ uint32 comp_flag, uchar **ret_pos,
+ uchar *buff, my_bool *last_key)
+{
+ int flag;
+ uint page_flag, nod_flag, length, used_length, not_used[2];
+ uchar t_buff[MARIA_MAX_KEY_BUFF], *end;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ MARIA_SHARE *share= keyinfo->share;
+ MARIA_KEY tmp_key;
+ DBUG_ENTER("_ma_seq_search");
+
+ LINT_INIT(flag);
+ LINT_INIT(length);
+
+ page_flag= _ma_get_keypage_flag(share, page);
+ _ma_get_used_and_nod_with_flag(share, page_flag, page, used_length,
+ nod_flag);
+ end= page + used_length;
+ page+= share->keypage_header + nod_flag;
+ *ret_pos= (uchar*) page;
+ t_buff[0]=0; /* Avoid bugs */
+
+ tmp_key.data= t_buff;
+ tmp_key.keyinfo= keyinfo;
+ while (page < end)
+ {
+ length=(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &page);
+ if (length == 0 || page > end)
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_PRINT("error",
+ ("Found wrong key: length: %u page: 0x%lx end: 0x%lx",
+ length, (long) page, (long) end));
+ DBUG_RETURN(MARIA_FOUND_WRONG_KEY);
+ }
+ if ((flag= ha_key_cmp(keyinfo->seg, t_buff, key->data,
+ key->data_length + key->ref_length,
+ comp_flag | tmp_key.flag,
+ not_used)) >= 0)
+ break;
+ DBUG_PRINT("loop_extra",("page: 0x%lx key: '%s' flag: %d",
+ (long) page, t_buff, flag));
+ memcpy(buff,t_buff,length);
+ *ret_pos=page;
+ }
+ if (flag == 0)
+ memcpy(buff,t_buff,length); /* Result is first key */
+ *last_key= page == end;
+ DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
+ DBUG_RETURN(flag);
+} /* _ma_seq_search */
+
+
+/**
+ Search for key on key page with string prefix compression
+
+ @notes
+ This is an optimized function compared to calling _ma_get_pack_key()
+ for each key in the buffer
+
+ Same interface as for _ma_seq_search()
+*/
+
+int _ma_prefix_search(const MARIA_KEY *key, uchar *page,
+ uint32 nextflag, uchar **ret_pos, uchar *buff,
+ my_bool *last_key)
+{
+ /*
+ my_flag is raw comparison result to be changed according to
+ SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
+ flag is the value returned by ha_key_cmp and as treated as final
+ */
+ int flag=0, my_flag=-1;
+ uint nod_flag, used_length, length, len, matched, cmplen, kseg_len;
+ uint page_flag, prefix_len,suffix_len;
+ int key_len_skip, seg_len_pack, key_len_left;
+ uchar *end;
+ uchar *vseg, *saved_vseg, *saved_from;
+ uchar tt_buff[MARIA_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
+ uchar *saved_to;
+ const uchar *kseg;
+ uint saved_length=0, saved_prefix_len=0;
+ uint length_pack;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ MARIA_SHARE *share= keyinfo->share;
+ uchar *sort_order= keyinfo->seg->charset->sort_order;
+ DBUG_ENTER("_ma_prefix_search");
+
+ LINT_INIT(length);
+ LINT_INIT(prefix_len);
+ LINT_INIT(seg_len_pack);
+ LINT_INIT(saved_from);
+ LINT_INIT(saved_to);
+ LINT_INIT(saved_vseg);
+
+ t_buff[0]=0; /* Avoid bugs */
+ page_flag= _ma_get_keypage_flag(share, page);
+ _ma_get_used_and_nod_with_flag(share, page_flag, page, used_length,
+ nod_flag);
+ page_flag&= KEYPAGE_FLAG_HAS_TRANSID; /* For faster test in loop */
+ end= page + used_length;
+ page+= share->keypage_header + nod_flag;
+ *ret_pos= page;
+ kseg= key->data;
+
+ get_key_pack_length(kseg_len, length_pack, kseg);
+ key_len_skip=length_pack+kseg_len;
+ key_len_left=(int) (key->data_length + key->ref_length) - (int) key_len_skip;
+ /* If key_len is 0, then length_pack is 1, then key_len_left is -1. */
+ cmplen= ((key_len_left>=0) ? kseg_len :
+ (key->data_length + key->ref_length - length_pack));
+ DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg));
+
+ /*
+ Keys are compressed the following way:
+
+ If the max length of first key segment <= 127 bytes the prefix is
+ 1 uchar else it's 2 byte
+
+ (prefix) length The high bit is set if this is a prefix for the prev key.
+ [suffix length] Packed length of suffix if the previous was a prefix.
+ (suffix) data Key data bytes (past the common prefix or whole segment).
+ [next-key-seg] Next key segments (([packed length], data), ...)
+ pointer Reference to the data file (last_keyseg->length).
+ */
+
+ matched=0; /* how many char's from prefix were alredy matched */
+ len=0; /* length of previous key unpacked */
+
+ while (page < end)
+ {
+ uint packed= *page & 128;
+ uint key_flag;
+
+ vseg= (uchar*) page;
+ if (keyinfo->seg->length >= 127)
+ {
+ suffix_len=mi_uint2korr(vseg) & 32767;
+ vseg+=2;
+ }
+ else
+ suffix_len= *vseg++ & 127;
+
+ if (packed)
+ {
+ if (suffix_len == 0)
+ {
+ /* == 0x80 or 0x8000, same key, prefix length == old key length. */
+ prefix_len=len;
+ }
+ else
+ {
+ /* > 0x80 or 0x8000, this is prefix lgt, packed suffix lgt follows. */
+ prefix_len=suffix_len;
+ get_key_length(suffix_len,vseg);
+ }
+ }
+ else
+ {
+ /* Not packed. No prefix used from last key. */
+ prefix_len=0;
+ }
+
+ len=prefix_len+suffix_len;
+ seg_len_pack=get_pack_length(len);
+ t_buff=tt_buff+3-seg_len_pack;
+ store_key_length(t_buff,len);
+
+ if (prefix_len > saved_prefix_len)
+ memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg,
+ prefix_len-saved_prefix_len);
+ saved_vseg=vseg;
+ saved_prefix_len=prefix_len;
+
+ DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,
+ suffix_len,vseg));
+ {
+ /* Calculate length of one key */
+ uchar *from= vseg+suffix_len;
+ HA_KEYSEG *keyseg;
+
+ for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ )
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!(*from++))
+ continue;
+ }
+ if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
+ {
+ uint key_part_length;
+ get_key_length(key_part_length,from);
+ from+= key_part_length;
+ }
+ else
+ from+= keyseg->length;
+ }
+ from+= keyseg->length;
+ key_flag=0;
+
+ if (page_flag && key_has_transid(from-1))
+ {
+ from+= transid_packed_length(from);
+ key_flag= SEARCH_PAGE_KEY_HAS_TRANSID;
+ }
+ page= (uchar*) from+nod_flag;
+ length= (uint) (from-vseg);
+ }
+
+ if (page > end)
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_PRINT("error",
+ ("Found wrong key: length: %u page: 0x%lx end: %lx",
+ length, (long) page, (long) end));
+ DBUG_RETURN(MARIA_FOUND_WRONG_KEY);
+ }
+
+ if (matched >= prefix_len)
+ {
+ /* We have to compare. But we can still skip part of the key */
+ uint left;
+ const uchar *k= kseg+prefix_len;
+
+ /*
+ If prefix_len > cmplen then we are in the end-space comparison
+ phase. Do not try to acces the key any more ==> left= 0.
+ */
+ left= ((len <= cmplen) ? suffix_len :
+ ((prefix_len < cmplen) ? cmplen - prefix_len : 0));
+
+ matched=prefix_len+left;
+
+ if (sort_order)
+ {
+ for (my_flag=0;left;left--)
+ if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++]))
+ break;
+ }
+ else
+ {
+ for (my_flag=0;left;left--)
+ if ((my_flag= (int) *vseg++ - (int) *k++))
+ break;
+ }
+
+ if (my_flag>0) /* mismatch */
+ break;
+ if (my_flag==0) /* match */
+ {
+ /*
+ ** len cmplen seg_left_len more_segs
+ ** < matched=len; continue search
+ ** > = prefix ? found : (matched=len;
+ * continue search)
+ ** > < - ok, found
+ ** = < - ok, found
+ ** = = - ok, found
+ ** = = + next seg
+ */
+ if (len < cmplen)
+ {
+ if ((keyinfo->seg->type != HA_KEYTYPE_TEXT &&
+ keyinfo->seg->type != HA_KEYTYPE_VARTEXT1 &&
+ keyinfo->seg->type != HA_KEYTYPE_VARTEXT2))
+ my_flag= -1;
+ else
+ {
+ /* We have to compare k and vseg as if they were space extended */
+ const uchar *k_end= k+ (cmplen - len);
+ for ( ; k < k_end && *k == ' '; k++) ;
+ if (k == k_end)
+ goto cmp_rest; /* should never happen */
+ if ((uchar) *k < (uchar) ' ')
+ {
+ my_flag= 1; /* Compared string is smaller */
+ break;
+ }
+ my_flag= -1; /* Continue searching */
+ }
+ }
+ else if (len > cmplen)
+ {
+ uchar *vseg_end;
+ if ((nextflag & SEARCH_PREFIX) && key_len_left == 0)
+ goto fix_flag;
+
+ /* We have to compare k and vseg as if they were space extended */
+ for (vseg_end= vseg + (len-cmplen) ;
+ vseg < vseg_end && *vseg == (uchar) ' ';
+ vseg++, matched++) ;
+ DBUG_ASSERT(vseg < vseg_end);
+
+ if ((uchar) *vseg > (uchar) ' ')
+ {
+ my_flag= 1; /* Compared string is smaller */
+ break;
+ }
+ my_flag= -1; /* Continue searching */
+ }
+ else
+ {
+ cmp_rest:
+ if (key_len_left>0)
+ {
+ uint not_used[2];
+ if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
+ k, key_len_left, nextflag | key_flag,
+ not_used)) >= 0)
+ break;
+ }
+ else
+ {
+ /*
+ at this line flag==-1 if the following lines were already
+ visited and 0 otherwise, i.e. flag <=0 here always !!!
+ */
+ fix_flag:
+ DBUG_ASSERT(flag <= 0);
+ if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
+ flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
+ if (flag>=0)
+ break;
+ }
+ }
+ }
+ matched-=left;
+ }
+ /* else (matched < prefix_len) ---> do nothing. */
+
+ memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
+ saved_to= buff+saved_length;
+ saved_from= saved_vseg;
+ saved_length=length;
+ *ret_pos=page;
+ }
+ if (my_flag)
+ flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag;
+ if (flag == 0)
+ {
+ memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
+ saved_to= buff+saved_length;
+ saved_from= saved_vseg;
+ saved_length=length;
+ }
+ if (saved_length)
+ memcpy(saved_to, (uchar*) saved_from, saved_length);
+
+ *last_key= page == end;
+
+ DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
+ DBUG_RETURN(flag);
+} /* _ma_prefix_search */
+
+
+/* Get pos to a key_block */
+
+my_off_t _ma_kpos(uint nod_flag, const uchar *after_key)
+{
+ after_key-=nod_flag;
+ switch (nod_flag) {
+#if SIZEOF_OFF_T > 4
+ case 7:
+ return mi_uint7korr(after_key)*maria_block_size;
+ case 6:
+ return mi_uint6korr(after_key)*maria_block_size;
+ case 5:
+ return mi_uint5korr(after_key)*maria_block_size;
+#else
+ case 7:
+ after_key++;
+ case 6:
+ after_key++;
+ case 5:
+ after_key++;
+#endif
+ case 4:
+ return ((my_off_t) mi_uint4korr(after_key))*maria_block_size;
+ case 3:
+ return ((my_off_t) mi_uint3korr(after_key))*maria_block_size;
+ case 2:
+ return (my_off_t) (mi_uint2korr(after_key)*maria_block_size);
+ case 1:
+ return (uint) (*after_key)*maria_block_size;
+ case 0: /* At leaf page */
+ default: /* Impossible */
+ return(HA_OFFSET_ERROR);
+ }
+} /* _kpos */
+
+
+/* Save pos to a key_block */
+
+void _ma_kpointer(register MARIA_HA *info, register uchar *buff, my_off_t pos)
+{
+ pos/=maria_block_size;
+ switch (info->s->base.key_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 7: mi_int7store(buff,pos); break;
+ case 6: mi_int6store(buff,pos); break;
+ case 5: mi_int5store(buff,pos); break;
+#else
+ case 7: *buff++=0;
+ /* fall trough */
+ case 6: *buff++=0;
+ /* fall trough */
+ case 5: *buff++=0;
+ /* fall trough */
+#endif
+ case 4: mi_int4store(buff,pos); break;
+ case 3: mi_int3store(buff,pos); break;
+ case 2: mi_int2store(buff,(uint) pos); break;
+ case 1: buff[0]= (uchar) pos; break;
+ default: abort(); /* impossible */
+ }
+} /* _ma_kpointer */
+
+
+/* Calc pos to a data-record from a key */
+
+MARIA_RECORD_POS _ma_row_pos_from_key(const MARIA_KEY *key)
+{
+ my_off_t pos;
+ const uchar *after_key= key->data + key->data_length;
+ MARIA_SHARE *share= key->keyinfo->share;
+ switch (share->rec_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 8: pos= (my_off_t) mi_uint8korr(after_key); break;
+ case 7: pos= (my_off_t) mi_uint7korr(after_key); break;
+ case 6: pos= (my_off_t) mi_uint6korr(after_key); break;
+ case 5: pos= (my_off_t) mi_uint5korr(after_key); break;
+#else
+ case 8: pos= (my_off_t) mi_uint4korr(after_key+4); break;
+ case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break;
+ case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break;
+ case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break;
+#endif
+ case 4: pos= (my_off_t) mi_uint4korr(after_key); break;
+ case 3: pos= (my_off_t) mi_uint3korr(after_key); break;
+ case 2: pos= (my_off_t) mi_uint2korr(after_key); break;
+ default:
+ pos=0L; /* Shut compiler up */
+ }
+ return (*share->keypos_to_recpos)(share, pos);
+}
+
+
+/**
+ Get trid from a key
+
+ @param key Maria key read from a page
+
+ @retval 0 If key doesn't have a trid
+ @retval trid
+*/
+
+TrID _ma_trid_from_key(const MARIA_KEY *key)
+{
+ if (!(key->flag & (SEARCH_PAGE_KEY_HAS_TRANSID |
+ SEARCH_USER_KEY_HAS_TRANSID)))
+ return 0;
+ return transid_get_packed(key->keyinfo->share,
+ key->data + key->data_length +
+ key->keyinfo->share->rec_reflength);
+}
+
+
+/* Calc position from a record pointer ( in delete link chain ) */
+
+MARIA_RECORD_POS _ma_rec_pos(MARIA_SHARE *share, uchar *ptr)
+{
+ my_off_t pos;
+ switch (share->rec_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 8:
+ pos= (my_off_t) mi_uint8korr(ptr);
+ if (pos == HA_OFFSET_ERROR)
+ return HA_OFFSET_ERROR; /* end of list */
+ break;
+ case 7:
+ pos= (my_off_t) mi_uint7korr(ptr);
+ if (pos == (((my_off_t) 1) << 56) -1)
+ return HA_OFFSET_ERROR; /* end of list */
+ break;
+ case 6:
+ pos= (my_off_t) mi_uint6korr(ptr);
+ if (pos == (((my_off_t) 1) << 48) -1)
+ return HA_OFFSET_ERROR; /* end of list */
+ break;
+ case 5:
+ pos= (my_off_t) mi_uint5korr(ptr);
+ if (pos == (((my_off_t) 1) << 40) -1)
+ return HA_OFFSET_ERROR; /* end of list */
+ break;
+#else
+ case 8:
+ case 7:
+ case 6:
+ case 5:
+ ptr+= (share->rec_reflength-4);
+ /* fall through */
+#endif
+ case 4:
+ pos= (my_off_t) mi_uint4korr(ptr);
+ if (pos == (my_off_t) (uint32) ~0L)
+ return HA_OFFSET_ERROR;
+ break;
+ case 3:
+ pos= (my_off_t) mi_uint3korr(ptr);
+ if (pos == (my_off_t) (1 << 24) -1)
+ return HA_OFFSET_ERROR;
+ break;
+ case 2:
+ pos= (my_off_t) mi_uint2korr(ptr);
+ if (pos == (my_off_t) (1 << 16) -1)
+ return HA_OFFSET_ERROR;
+ break;
+ default: abort(); /* Impossible */
+ }
+ return (*share->keypos_to_recpos)(share, pos);
+}
+
+
+/* save position to record */
+
+void _ma_dpointer(MARIA_SHARE *share, uchar *buff, my_off_t pos)
+{
+ if (pos != HA_OFFSET_ERROR)
+ pos= (*share->recpos_to_keypos)(share, pos);
+
+ switch (share->rec_reflength) {
+#if SIZEOF_OFF_T > 4
+ case 8: mi_int8store(buff,pos); break;
+ case 7: mi_int7store(buff,pos); break;
+ case 6: mi_int6store(buff,pos); break;
+ case 5: mi_int5store(buff,pos); break;
+#else
+ case 8: *buff++=0;
+ /* fall trough */
+ case 7: *buff++=0;
+ /* fall trough */
+ case 6: *buff++=0;
+ /* fall trough */
+ case 5: *buff++=0;
+ /* fall trough */
+#endif
+ case 4: mi_int4store(buff,pos); break;
+ case 3: mi_int3store(buff,pos); break;
+ case 2: mi_int2store(buff,(uint) pos); break;
+ default: abort(); /* Impossible */
+ }
+} /* _ma_dpointer */
+
+
+my_off_t _ma_static_keypos_to_recpos(MARIA_SHARE *share, my_off_t pos)
+{
+ return pos * share->base.pack_reclength;
+}
+
+
+my_off_t _ma_static_recpos_to_keypos(MARIA_SHARE *share, my_off_t pos)
+{
+ return pos / share->base.pack_reclength;
+}
+
+my_off_t _ma_transparent_recpos(MARIA_SHARE *share __attribute__((unused)),
+ my_off_t pos)
+{
+ return pos;
+}
+
+my_off_t _ma_transaction_keypos_to_recpos(MARIA_SHARE *share
+ __attribute__((unused)),
+ my_off_t pos)
+{
+ /* We need one bit to store if there is transid's after position */
+ return pos >> 1;
+}
+
+my_off_t _ma_transaction_recpos_to_keypos(MARIA_SHARE *share
+ __attribute__((unused)),
+ my_off_t pos)
+{
+ return pos << 1;
+}
+
+/*
+ @brief Get key from key-block
+
+ @param key Should contain previous key. Will contain new key
+ @param page_flag Flag on page block
+ @param nod_flag Is set to nod length if we on nod
+ @param page Points at previous key; Its advanced to point at next key
+
+ @notes
+ Same as _ma_get_key but used with fixed length keys
+
+ @return
+ @retval key_length + length of data pointer (without nod length)
+ */
+
+uint _ma_get_static_key(MARIA_KEY *key, uint page_flag, uint nod_flag,
+ register uchar **page)
+{
+ register MARIA_KEYDEF *keyinfo= key->keyinfo;
+ size_t key_length= keyinfo->keylength;
+
+ key->ref_length= keyinfo->share->rec_reflength;
+ key->data_length= key_length - key->ref_length;
+ key->flag= 0;
+ if (page_flag & KEYPAGE_FLAG_HAS_TRANSID)
+ {
+ uchar *end= *page + keyinfo->keylength;
+ if (key_has_transid(end-1))
+ {
+ uint trans_length= transid_packed_length(end);
+ key->ref_length+= trans_length;
+ key_length+= trans_length;
+ key->flag= SEARCH_PAGE_KEY_HAS_TRANSID;
+ }
+ }
+ key_length+= nod_flag;
+ memcpy(key->data, *page, key_length);
+ *page+= key_length;
+ return key_length - nod_flag;
+} /* _ma_get_static_key */
+
+
+/**
+ Skip over static length key from key-block
+
+ @fn _ma_skip_static_key()
+ @param key Keyinfo and buffer that can be used
+ @param nod_flag If nod: Length of node pointer, else zero.
+ @param key Points at key
+
+ @retval pointer to next key
+*/
+
+uchar *_ma_skip_static_key(MARIA_KEY *key, uint page_flag,
+ uint nod_flag, uchar *page)
+{
+ page+= key->keyinfo->keylength;
+ if ((page_flag & KEYPAGE_FLAG_HAS_TRANSID) && key_has_transid(page-1))
+ page+= transid_packed_length(page);
+ return page+ nod_flag;
+}
+
+
+/*
+ get key which is packed against previous key or key with a NULL column.
+
+ SYNOPSIS
+ _ma_get_pack_key()
+ @param int_key Should contain previous key. Will contain new key
+ @param page_flag page_flag from page
+ @param nod_flag If nod: Length of node pointer, else zero.
+ @param page_pos Points at previous key; Its advanced to point at next key
+
+ @return
+ @retval key_length + length of data pointer
+*/
+
+uint _ma_get_pack_key(MARIA_KEY *int_key, uint page_flag,
+ uint nod_flag, uchar **page_pos)
+{
+ reg1 HA_KEYSEG *keyseg;
+ uchar *page= *page_pos;
+ uint length;
+ uchar *key= int_key->data;
+ MARIA_KEYDEF *keyinfo= int_key->keyinfo;
+
+ for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
+ {
+ if (keyseg->flag & HA_PACK_KEY)
+ {
+ /* key with length, packed to previous key */
+ uchar *start= key;
+ uint packed= *page & 128,tot_length,rest_length;
+ if (keyseg->length >= 127)
+ {
+ length=mi_uint2korr(page) & 32767;
+ page+=2;
+ }
+ else
+ length= *page++ & 127;
+
+ if (packed)
+ {
+ if (length > (uint) keyseg->length)
+ {
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Error */
+ }
+ if (length == 0) /* Same key */
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ *key++=1; /* Can't be NULL */
+ get_key_length(length,key);
+ key+= length; /* Same diff_key as prev */
+ if (length > keyseg->length)
+ {
+ DBUG_PRINT("error",
+ ("Found too long null packed key: %u of %u at 0x%lx",
+ length, keyseg->length, (long) *page_pos));
+ DBUG_DUMP("key", *page_pos, 16);
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ return 0;
+ }
+ continue;
+ }
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ key++; /* Skip null marker*/
+ start++;
+ }
+
+ get_key_length(rest_length,page);
+ tot_length=rest_length+length;
+
+ /* If the stored length has changed, we must move the key */
+ if (tot_length >= 255 && *start != 255)
+ {
+ /* length prefix changed from a length of one to a length of 3 */
+ bmove_upp(key+length+3, key+length+1, length);
+ *key=255;
+ mi_int2store(key+1,tot_length);
+ key+=3+length;
+ }
+ else if (tot_length < 255 && *start == 255)
+ {
+ bmove(key+1,key+3,length);
+ *key=tot_length;
+ key+=1+length;
+ }
+ else
+ {
+ store_key_length_inc(key,tot_length);
+ key+=length;
+ }
+ memcpy(key,page,rest_length);
+ page+=rest_length;
+ key+=rest_length;
+ continue;
+ }
+ else
+ {
+ /* Key that is not packed against previous key */
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!length--) /* Null part */
+ {
+ *key++=0;
+ continue;
+ }
+ *key++=1; /* Not null */
+ }
+ }
+ if (length > (uint) keyseg->length)
+ {
+ DBUG_PRINT("error",("Found too long packed key: %u of %u at 0x%lx",
+ length, keyseg->length, (long) *page_pos));
+ DBUG_DUMP("key", *page_pos, 16);
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ return 0; /* Error */
+ }
+ store_key_length_inc(key,length);
+ }
+ else
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!(*key++ = *page++))
+ continue;
+ }
+ if (keyseg->flag &
+ (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
+ {
+ uchar *tmp=page;
+ get_key_length(length,tmp);
+ length+=(uint) (tmp-page);
+ }
+ else
+ length=keyseg->length;
+ }
+ memcpy((uchar*) key,(uchar*) page,(size_t) length);
+ key+=length;
+ page+=length;
+ }
+
+ int_key->data_length= (key - int_key->data);
+ int_key->flag= 0;
+ length= keyseg->length;
+ if (page_flag & KEYPAGE_FLAG_HAS_TRANSID)
+ {
+ uchar *end= page + length;
+ if (key_has_transid(end-1))
+ {
+ length+= transid_packed_length(end);
+ int_key->flag= SEARCH_PAGE_KEY_HAS_TRANSID;
+ }
+ }
+ int_key->ref_length= length;
+ length+= nod_flag;
+ bmove(key, page, length);
+ *page_pos= page+length;
+
+ return (int_key->data_length + int_key->ref_length);
+} /* _ma_get_pack_key */
+
+
+/**
+ skip key which is packed against previous key or key with a NULL column.
+
+ @fn _ma_skip_pack_key()
+ @param key Keyinfo and buffer that can be used
+ @param nod_flag If nod: Length of node pointer, else zero.
+ @param key Points at key
+
+ @note
+ This is in principle a simpler version of _ma_get_pack_key()
+
+ @retval pointer to next key
+*/
+
+uchar *_ma_skip_pack_key(MARIA_KEY *key, uint page_flag,
+ uint nod_flag, uchar *page)
+{
+ reg1 HA_KEYSEG *keyseg;
+ for (keyseg= key->keyinfo->seg ; keyseg->type ; keyseg++)
+ {
+ if (keyseg->flag & HA_PACK_KEY)
+ {
+ /* key with length, packed to previous key */
+ uint packed= *page & 128, length;
+ if (keyseg->length >= 127)
+ {
+ length= mi_uint2korr(page) & 32767;
+ page+= 2;
+ }
+ else
+ length= *page++ & 127;
+
+ if (packed)
+ {
+ if (length == 0) /* Same key */
+ continue;
+ get_key_length(length,page);
+ page+= length;
+ continue;
+ }
+ if ((keyseg->flag & HA_NULL_PART) && length)
+ {
+ /*
+ Keys that can have null use length+1 as the length for date as the
+ number 0 is reserved for keys that have a NULL value
+ */
+ length--;
+ }
+ page+= length;
+ }
+ else
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ if (!*page++)
+ continue;
+ if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
+ {
+ uint length;
+ get_key_length(length,page);
+ page+=length;
+ }
+ else
+ page+= keyseg->length;
+ }
+ }
+ page+= keyseg->length;
+ if ((page_flag & KEYPAGE_FLAG_HAS_TRANSID) && key_has_transid(page-1))
+ page+= transid_packed_length(page);
+ return page + nod_flag;
+}
+
+
+/* Read key that is packed relatively to previous */
+
+uint _ma_get_binary_pack_key(MARIA_KEY *int_key, uint page_flag, uint nod_flag,
+ register uchar **page_pos)
+{
+ reg1 HA_KEYSEG *keyseg;
+ uchar *page, *page_end, *from, *from_end, *key;
+ uint length,tmp;
+ MARIA_KEYDEF *keyinfo= int_key->keyinfo;
+ DBUG_ENTER("_ma_get_binary_pack_key");
+
+ page= *page_pos;
+ page_end=page + MARIA_MAX_KEY_BUFF + 1;
+ key= int_key->data;
+
+ /*
+ Keys are compressed the following way:
+
+ prefix length Packed length of prefix common with prev key.
+ (1 or 3 bytes)
+ for each key segment:
+ [is null] Null indicator if can be null (1 byte, zero means null)
+ [length] Packed length if varlength (1 or 3 bytes)
+ key segment 'length' bytes of key segment value
+ pointer Reference to the data file (last_keyseg->length).
+
+ get_key_length() is a macro. It gets the prefix length from 'page'
+ and puts it into 'length'. It increments 'page' by 1 or 3, depending
+ on the packed length of the prefix length.
+ */
+ get_key_length(length,page);
+ if (length)
+ {
+ if (length > keyinfo->maxlength)
+ {
+ DBUG_PRINT("error",
+ ("Found too long binary packed key: %u of %u at 0x%lx",
+ length, keyinfo->maxlength, (long) *page_pos));
+ DBUG_DUMP("key", *page_pos, 16);
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0); /* Wrong key */
+ }
+ /* Key is packed against prev key, take prefix from prev key. */
+ from= key;
+ from_end= key + length;
+ }
+ else
+ {
+ /* Key is not packed against prev key, take all from page buffer. */
+ from= page;
+ from_end= page_end;
+ }
+
+ /*
+ The trouble is that key can be split in two parts:
+ The first part (prefix) is in from .. from_end - 1.
+ The second part starts at page.
+ The split can be at every byte position. So we need to check for
+ the end of the first part before using every byte.
+ */
+ for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ /* If prefix is used up, switch to rest. */
+ if (from == from_end)
+ {
+ from=page;
+ from_end=page_end;
+ }
+ if (!(*key++ = *from++))
+ continue; /* Null part */
+ }
+ if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
+ {
+ /* If prefix is used up, switch to rest. */
+ if (from == from_end) { from=page; from_end=page_end; }
+ /* Get length of dynamic length key part */
+ if ((length= (uint) (uchar) (*key++ = *from++)) == 255)
+ {
+ /* If prefix is used up, switch to rest. */
+ if (from == from_end) { from=page; from_end=page_end; }
+ length= ((uint) (uchar) ((*key++ = *from++))) << 8;
+ /* If prefix is used up, switch to rest. */
+ if (from == from_end) { from=page; from_end=page_end; }
+ length+= (uint) (uchar) ((*key++ = *from++));
+ }
+ }
+ else
+ length=keyseg->length;
+
+ if ((tmp=(uint) (from_end-from)) <= length)
+ {
+ key+=tmp; /* Use old key */
+ length-=tmp;
+ from=page; from_end=page_end;
+ }
+ DBUG_ASSERT((int) length >= 0);
+ DBUG_PRINT("info",("key: 0x%lx from: 0x%lx length: %u",
+ (long) key, (long) from, length));
+ memmove((uchar*) key, (uchar*) from, (size_t) length);
+ key+=length;
+ from+=length;
+ }
+ /*
+ Last segment (type == 0) contains length of data pointer.
+ If we have mixed key blocks with data pointer and key block pointer,
+ we have to copy both.
+ */
+ int_key->data_length= (key - int_key->data);
+ int_key->ref_length= length= keyseg->length;
+ int_key->flag= 0;
+ if ((tmp=(uint) (from_end-from)) <= length)
+ {
+ /* Skip over the last common part of the data */
+ key+= tmp;
+ length-= tmp;
+ from= page;
+ }
+ else
+ {
+ /*
+ Remaining length is greater than max possible length.
+ This can happen only if we switched to the new key bytes already.
+ 'page_end' is calculated with MARIA_MAX_KEY_BUFF. So it can be far
+ behind the real end of the key.
+ */
+ if (from_end != page_end)
+ {
+ DBUG_PRINT("error",("Error when unpacking key"));
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0); /* Error */
+ }
+ }
+ if (page_flag & KEYPAGE_FLAG_HAS_TRANSID)
+ {
+ uchar *end= from + length;
+ if (key_has_transid(end-1))
+ {
+ uint trans_length= transid_packed_length(end);
+ length+= trans_length;
+ int_key->ref_length+= trans_length;
+ int_key->flag= SEARCH_PAGE_KEY_HAS_TRANSID;
+ }
+ }
+
+ /* Copy rest of data ptr and, if appropriate, trans_id and node_ptr */
+ memcpy(key, from, length + nod_flag);
+ *page_pos= from + length + nod_flag;
+
+ DBUG_RETURN(int_key->data_length + int_key->ref_length);
+}
+
+/**
+ skip key which is ptefix packed against previous key
+
+ @fn _ma_skip_binary_key()
+ @param key Keyinfo and buffer that can be used
+ @param nod_flag If nod: Length of node pointer, else zero.
+ @param key Points at key
+
+ @note
+ We have to copy the key as otherwise we don't know how much left
+ data there is of the key.
+
+ @todo
+ Implement more efficient version of this. We can ignore to copy any rest
+ key parts that are not null or not packed. We also don't have to copy
+ rowid or transid.
+
+ @retval pointer to next key
+*/
+
+uchar *_ma_skip_binary_pack_key(MARIA_KEY *key, uint page_flag,
+ uint nod_flag, uchar *page)
+{
+ if (!_ma_get_binary_pack_key(key, page_flag, nod_flag, &page))
+ return 0;
+ return page;
+}
+
+
+/**
+ @brief Get key at position without knowledge of previous key
+
+ @return pointer to next key
+*/
+
+uchar *_ma_get_key(MARIA_KEY *key, uchar *page, uchar *keypos)
+{
+ uint page_flag, nod_flag;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_get_key");
+
+ page_flag= _ma_get_keypage_flag(keyinfo->share, page);
+ nod_flag= _ma_test_if_nod(keyinfo->share, page);
+
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
+ ! (page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ {
+ bmove(key->data, keypos, keyinfo->keylength+nod_flag);
+ key->ref_length= keyinfo->share->rec_reflength;
+ key->data_length= keyinfo->keylength - key->ref_length;
+ key->flag= 0;
+ DBUG_RETURN(keypos+keyinfo->keylength+nod_flag);
+ }
+ else
+ {
+ page+= keyinfo->share->keypage_header + nod_flag;
+ key->data[0]= 0; /* safety */
+ while (page <= keypos)
+ {
+ if (!(*keyinfo->get_key)(key, page_flag, nod_flag, &page))
+ {
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
+ }
+ }
+ }
+ DBUG_PRINT("exit",("page: 0x%lx length: %u", (long) page,
+ key->data_length + key->ref_length));
+ DBUG_RETURN(page);
+} /* _ma_get_key */
+
+
+/*
+ @brief Get key at position without knowledge of previous key
+
+ @return
+ @retval 0 ok
+ @retval 1 error
+*/
+
+static my_bool _ma_get_prev_key(MARIA_KEY *key, uchar *page, uchar *keypos)
+{
+ uint page_flag, nod_flag;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_get_prev_key");
+
+ page_flag= _ma_get_keypage_flag(keyinfo->share, page);
+ nod_flag= _ma_test_if_nod(keyinfo->share, page);
+
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
+ ! (page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ {
+ bmove(key->data, keypos - keyinfo->keylength - nod_flag,
+ keyinfo->keylength);
+ key->ref_length= keyinfo->share->rec_reflength;
+ key->data_length= keyinfo->keylength - key->ref_length;
+ key->flag= 0;
+ DBUG_RETURN(0);
+ }
+ else
+ {
+ page+= keyinfo->share->keypage_header + nod_flag;
+ key->data[0]= 0; /* safety */
+ DBUG_ASSERT(page != keypos);
+ while (page < keypos)
+ {
+ if (! (*keyinfo->get_key)(key, page_flag, nod_flag, &page))
+ {
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+} /* _ma_get_prev_key */
+
+
+/*
+ @brief Get last key from key-page before 'endpos'
+
+ @note
+ endpos may be either end of buffer or start of a key
+
+ @return
+ @retval pointer to where key starts
+*/
+
+uchar *_ma_get_last_key(MARIA_KEY *key, uchar *page, uchar *endpos)
+{
+ uint page_flag,nod_flag;
+ uchar *lastpos;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_get_last_key");
+ DBUG_PRINT("enter",("page: 0x%lx endpos: 0x%lx", (long) page,
+ (long) endpos));
+
+ page_flag= _ma_get_keypage_flag(keyinfo->share, page);
+ nod_flag= _ma_test_if_nod(keyinfo->share, page);
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
+ ! (page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ {
+ lastpos= endpos-keyinfo->keylength-nod_flag;
+ key->ref_length= keyinfo->share->rec_reflength;
+ key->data_length= keyinfo->keylength - key->ref_length;
+ key->flag= 0;
+ if (lastpos > page)
+ bmove(key->data, lastpos, keyinfo->keylength + nod_flag);
+ }
+ else
+ {
+ page+= keyinfo->share->keypage_header + nod_flag;
+ lastpos= page;
+ key->data[0]=0; /* safety */
+ while (page < endpos)
+ {
+ lastpos= page;
+ if (!(*keyinfo->get_key)(key, page_flag, nod_flag, &page))
+ {
+ DBUG_PRINT("error",("Couldn't find last key: page: 0x%lx",
+ (long) page));
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
+ }
+ }
+ }
+ DBUG_PRINT("exit",("lastpos: 0x%lx length: %u", (ulong) lastpos,
+ key->data_length + key->ref_length));
+ DBUG_RETURN(lastpos);
+} /* _ma_get_last_key */
+
+
+/**
+ Calculate length of unpacked key
+
+ @param info Maria handler
+ @param keyinfo key handler
+ @param key data for key
+
+ @notes
+ This function is very seldom used. It's mainly used for debugging
+ or when calculating a key length from a stored key in batch insert.
+
+ This function does *NOT* calculate length of transid size!
+ This function can't be used against a prefix packed key on a page
+
+ @return
+ @retval total length for key
+*/
+
+uint _ma_keylength(MARIA_KEYDEF *keyinfo, const uchar *key)
+{
+ reg1 HA_KEYSEG *keyseg;
+ const uchar *start;
+
+ if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
+ return (keyinfo->keylength);
+
+ start= key;
+ for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ if (!*key++)
+ continue;
+ if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
+ {
+ uint length;
+ get_key_length(length,key);
+ key+=length;
+ }
+ else
+ key+= keyseg->length;
+ }
+ return((uint) (key-start)+keyseg->length);
+} /* _ma_keylength */
+
+
+/*
+ Calculate length of part key.
+
+ Used in maria_rkey() to find the key found for the key-part that was used.
+ This is needed in case of multi-byte character sets where we may search
+ after '0xDF' but find 'ss'
+*/
+
+uint _ma_keylength_part(MARIA_KEYDEF *keyinfo, register const uchar *key,
+ HA_KEYSEG *end)
+{
+ reg1 HA_KEYSEG *keyseg;
+ const uchar *start= key;
+
+ for (keyseg=keyinfo->seg ; keyseg != end ; keyseg++)
+ {
+ if (keyseg->flag & HA_NULL_PART)
+ if (!*key++)
+ continue;
+ if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
+ {
+ uint length;
+ get_key_length(length,key);
+ key+=length;
+ }
+ else
+ key+= keyseg->length;
+ }
+ return (uint) (key-start);
+}
+
+
+/*
+ Find next/previous record with same key
+
+ WARNING
+ This can't be used when database is touched after last read
+*/
+
+int _ma_search_next(register MARIA_HA *info, MARIA_KEY *key,
+ uint32 nextflag, my_off_t pos)
+{
+ int error;
+ uint page_flag,nod_flag;
+ uchar lastkey[MARIA_MAX_KEY_BUFF];
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ MARIA_KEY tmp_key;
+ DBUG_ENTER("_ma_search_next");
+ DBUG_PRINT("enter",("nextflag: %u lastpos: %lu int_keypos: 0x%lx page_changed %d keyread_buff_used: %d",
+ nextflag, (ulong) info->cur_row.lastpos,
+ (ulong) info->int_keypos,
+ info->page_changed, info->keyread_buff_used));
+ DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, key););
+
+ /*
+ Force full read if we are at last key or if we are not on a leaf
+ and the key tree has changed since we used it last time
+ Note that even if the key tree has changed since last read, we can use
+ the last read data from the leaf if we haven't used the buffer for
+ something else.
+ */
+
+ if (((nextflag & SEARCH_BIGGER) && info->int_keypos >= info->int_maxpos) ||
+ info->page_changed ||
+ (info->int_keytree_version != keyinfo->version &&
+ (info->int_nod_flag || info->keyread_buff_used)))
+ DBUG_RETURN(_ma_search(info, key, nextflag | SEARCH_SAVE_BUFF,
+ pos));
+
+ if (info->keyread_buff_used)
+ {
+ if (!_ma_fetch_keypage(info, keyinfo, info->last_search_keypage,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, info->keyread_buff, 0, 0))
+ DBUG_RETURN(-1);
+ info->keyread_buff_used=0;
+ }
+
+ /* Last used buffer is in info->keyread_buff */
+ page_flag= _ma_get_keypage_flag(keyinfo->share, info->keyread_buff);
+ nod_flag= _ma_test_if_nod(keyinfo->share, info->keyread_buff);
+
+ tmp_key.data= lastkey;
+ info->last_key.keyinfo= tmp_key.keyinfo= keyinfo;
+
+ if (nextflag & SEARCH_BIGGER) /* Next key */
+ {
+ if (nod_flag)
+ {
+ my_off_t tmp_pos= _ma_kpos(nod_flag,info->int_keypos);
+
+ if ((error= _ma_search(info, key, nextflag | SEARCH_SAVE_BUFF,
+ tmp_pos)) <=0)
+ DBUG_RETURN(error);
+ }
+ if (keyinfo->flag & (HA_PACK_KEY | HA_BINARY_PACK_KEY) &&
+ info->last_key.data != key->data)
+ memcpy(info->last_key.data, key->data,
+ key->data_length + key->ref_length);
+ if (!(*keyinfo->get_key)(&info->last_key, page_flag, nod_flag,
+ &info->int_keypos))
+ DBUG_RETURN(-1);
+ }
+ else /* Previous key */
+ {
+ /* Find start of previous key */
+ info->int_keypos= _ma_get_last_key(&tmp_key, info->keyread_buff,
+ info->int_keypos);
+ if (!info->int_keypos)
+ DBUG_RETURN(-1);
+ if (info->int_keypos == info->keyread_buff + info->s->keypage_header)
+ {
+ /* Previous key was first key, read key before this one */
+ DBUG_RETURN(_ma_search(info, key, nextflag | SEARCH_SAVE_BUFF,
+ pos));
+ }
+ if (nod_flag &&
+ (error= _ma_search(info, key, nextflag | SEARCH_SAVE_BUFF,
+ _ma_kpos(nod_flag,info->int_keypos))) <= 0)
+ DBUG_RETURN(error);
+
+ /* QQ: We should be able to optimize away the following call */
+ if (! _ma_get_last_key(&info->last_key, info->keyread_buff,
+ info->int_keypos))
+ DBUG_RETURN(-1);
+ }
+ info->cur_row.lastpos= _ma_row_pos_from_key(&info->last_key);
+ info->cur_row.trid= _ma_trid_from_key(&info->last_key);
+ DBUG_PRINT("exit",("found key at %lu",(ulong) info->cur_row.lastpos));
+ DBUG_RETURN(0);
+} /* _ma_search_next */
+
+
+/**
+ Search after position for the first row in an index
+
+ @return
+ Found row is stored in info->cur_row.lastpos
+*/
+
+int _ma_search_first(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
+ register my_off_t pos)
+{
+ uint page_flag, nod_flag;
+ uchar *page;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_search_first");
+
+ if (pos == HA_OFFSET_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND;
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+
+ do
+ {
+ if (!_ma_fetch_keypage(info, keyinfo, pos, PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, info->keyread_buff, 0, 0))
+ {
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+ page_flag= _ma_get_keypage_flag(share, info->keyread_buff);
+ nod_flag= _ma_test_if_nod(share, info->keyread_buff);
+ page= info->keyread_buff + share->keypage_header + nod_flag;
+ } while ((pos= _ma_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
+
+ info->last_key.keyinfo= keyinfo;
+
+ if (!(*keyinfo->get_key)(&info->last_key, page_flag, nod_flag, &page))
+ DBUG_RETURN(-1); /* Crashed */
+
+ info->int_keypos=page;
+ info->int_maxpos= (info->keyread_buff +
+ _ma_get_page_used(share, info->keyread_buff)-1);
+ info->int_nod_flag=nod_flag;
+ info->int_keytree_version=keyinfo->version;
+ info->last_search_keypage=info->last_keypage;
+ info->page_changed=info->keyread_buff_used=0;
+ info->cur_row.lastpos= _ma_row_pos_from_key(&info->last_key);
+ info->cur_row.trid= _ma_trid_from_key(&info->last_key);
+
+ DBUG_PRINT("exit",("found key at %lu", (ulong) info->cur_row.lastpos));
+ DBUG_RETURN(0);
+} /* _ma_search_first */
+
+
+/**
+ Search after position for the last row in an index
+
+ @return
+ Found row is stored in info->cur_row.lastpos
+*/
+
+int _ma_search_last(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
+ register my_off_t pos)
+{
+ uint page_flag, nod_flag;
+ uchar *buff,*end_of_page;
+ DBUG_ENTER("_ma_search_last");
+
+ if (pos == HA_OFFSET_ERROR)
+ {
+ my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+
+ buff=info->keyread_buff;
+ do
+ {
+ uint used_length;
+ if (!_ma_fetch_keypage(info, keyinfo, pos, PAGECACHE_LOCK_LEFT_UNLOCKED,
+ DFLT_INIT_HITS, buff, 0, 0))
+ {
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ DBUG_RETURN(-1);
+ }
+ page_flag= _ma_get_keypage_flag(info->s, info->keyread_buff);
+ _ma_get_used_and_nod_with_flag(info->s, page_flag, buff, used_length,
+ nod_flag);
+ end_of_page= buff + used_length;
+ } while ((pos= _ma_kpos(nod_flag, end_of_page)) != HA_OFFSET_ERROR);
+
+ info->last_key.keyinfo= keyinfo;
+
+ if (!_ma_get_last_key(&info->last_key, buff, end_of_page))
+ DBUG_RETURN(-1);
+ info->cur_row.lastpos= _ma_row_pos_from_key(&info->last_key);
+ info->cur_row.trid= _ma_trid_from_key(&info->last_key);
+ info->int_keypos= info->int_maxpos= end_of_page;
+ info->int_nod_flag=nod_flag;
+ info->int_keytree_version=keyinfo->version;
+ info->last_search_keypage=info->last_keypage;
+ info->page_changed=info->keyread_buff_used=0;
+
+ DBUG_PRINT("exit",("found key at %lu",(ulong) info->cur_row.lastpos));
+ DBUG_RETURN(0);
+} /* _ma_search_last */
+
+
+
+/****************************************************************************
+**
+** Functions to store and pack a key in a page
+**
+** maria_calc_xx_key_length takes the following arguments:
+** nod_flag If nod: Length of nod-pointer
+** next_key Position to pos after the new key in buffer
+** org_key Key that was before the next key in buffer
+** prev_key Last key before current key
+** key Key that will be stored
+** s_temp Information how next key will be packed
+****************************************************************************/
+
+/* Static length key */
+
+int
+_ma_calc_static_key_length(const MARIA_KEY *key, uint nod_flag,
+ uchar *next_pos __attribute__((unused)),
+ uchar *org_key __attribute__((unused)),
+ uchar *prev_key __attribute__((unused)),
+ MARIA_KEY_PARAM *s_temp)
+{
+ s_temp->key= key->data;
+ return (int) (s_temp->move_length= key->data_length + key->ref_length +
+ nod_flag);
+}
+
+/* Variable length key */
+
+int
+_ma_calc_var_key_length(const MARIA_KEY *key, uint nod_flag,
+ uchar *next_pos __attribute__((unused)),
+ uchar *org_key __attribute__((unused)),
+ uchar *prev_key __attribute__((unused)),
+ MARIA_KEY_PARAM *s_temp)
+{
+ s_temp->key= key->data;
+ return (int) (s_temp->move_length= key->data_length + key->ref_length +
+ nod_flag);
+}
+
+/**
+ @brief Calc length needed to store prefixed compressed keys
+
+ @info
+ Variable length first segment which is prefix compressed
+ (maria_chk reports 'packed + stripped')
+
+ Keys are compressed the following way:
+
+ If the max length of first key segment <= 127 bytes the prefix is
+ 1 uchar else it's 2 byte
+
+ prefix byte(s) The high bit is set if this is a prefix for the prev key
+ length Packed length if the previous was a prefix byte
+ [data_length] data bytes ('length' bytes)
+ next-key-seg Next key segments
+
+ If the first segment can have NULL:
+ If key was packed
+ data_length is length of rest of key
+ If key was not packed
+ The data_length is 0 for NULLS and 1+data_length for not null columns
+*/
+
+int
+_ma_calc_var_pack_key_length(const MARIA_KEY *int_key, uint nod_flag,
+ uchar *next_key, uchar *org_key, uchar *prev_key,
+ MARIA_KEY_PARAM *s_temp)
+{
+ reg1 HA_KEYSEG *keyseg;
+ int length;
+ uint key_length,ref_length,org_key_length=0,
+ length_pack,new_key_length,diff_flag,pack_marker;
+ const uchar *key, *start, *end, *key_end;
+ uchar *sort_order;
+ my_bool same_length;
+ MARIA_KEYDEF *keyinfo= int_key->keyinfo;
+
+ key= int_key->data;
+ length_pack=s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
+ same_length=0; keyseg=keyinfo->seg;
+ key_length= int_key->data_length + int_key->ref_length + nod_flag;
+
+ sort_order=0;
+ if ((keyinfo->flag & HA_FULLTEXT) &&
+ ((keyseg->type == HA_KEYTYPE_TEXT) ||
+ (keyseg->type == HA_KEYTYPE_VARTEXT1) ||
+ (keyseg->type == HA_KEYTYPE_VARTEXT2)) &&
+ !use_strnxfrm(keyseg->charset))
+ sort_order= keyseg->charset->sort_order;
+
+ /* diff flag contains how many bytes is needed to pack key */
+ if (keyseg->length >= 127)
+ {
+ diff_flag=2;
+ pack_marker=32768;
+ }
+ else
+ {
+ diff_flag= 1;
+ pack_marker=128;
+ }
+ s_temp->pack_marker=pack_marker;
+
+ /* Handle the case that the first part have NULL values */
+ if (keyseg->flag & HA_NULL_PART)
+ {
+ if (!*key++)
+ {
+ s_temp->key= key;
+ s_temp->key_length= 0;
+ s_temp->totlength= key_length-1+diff_flag;
+ s_temp->next_key_pos= 0; /* No next key */
+ return (s_temp->move_length= s_temp->totlength);
+ }
+ s_temp->store_not_null=1;
+ key_length--; /* We don't store NULL */
+ if (prev_key && !*prev_key++)
+ org_key=prev_key=0; /* Can't pack against prev */
+ else if (org_key)
+ org_key++; /* Skip NULL */
+ }
+ else
+ s_temp->store_not_null=0;
+ s_temp->prev_key= org_key;
+
+ /* The key part will start with a packed length */
+
+ get_key_pack_length(new_key_length,length_pack,key);
+ end= key_end= key+ new_key_length;
+ start= key;
+
+ /* Calc how many characters are identical between this and the prev. key */
+ if (prev_key)
+ {
+ get_key_length(org_key_length,prev_key);
+ s_temp->prev_key=prev_key; /* Pointer at data */
+ /* Don't use key-pack if length == 0 */
+ if (new_key_length && new_key_length == org_key_length)
+ same_length=1;
+ else if (new_key_length > org_key_length)
+ end= key + org_key_length;
+
+ if (sort_order) /* SerG */
+ {
+ while (key < end &&
+ sort_order[*key] == sort_order[*prev_key])
+ {
+ key++; prev_key++;
+ }
+ }
+ else
+ {
+ while (key < end && *key == *prev_key)
+ {
+ key++; prev_key++;
+ }
+ }
+ }
+
+ s_temp->key=key;
+ s_temp->key_length= (uint) (key_end-key);
+
+ if (same_length && key == key_end)
+ {
+ /* identical variable length key */
+ s_temp->ref_length= pack_marker;
+ length=(int) key_length-(int) (key_end-start)-length_pack;
+ length+= diff_flag;
+ if (next_key)
+ { /* Can't combine with next */
+ s_temp->n_length= *next_key; /* Needed by _ma_store_key */
+ next_key=0;
+ }
+ }
+ else
+ {
+ if (start != key)
+ { /* Starts as prev key */
+ ref_length= (uint) (key-start);
+ s_temp->ref_length= ref_length + pack_marker;
+ length= (int) (key_length - ref_length);
+
+ length-= length_pack;
+ length+= diff_flag;
+ length+= ((new_key_length-ref_length) >= 255) ? 3 : 1;/* Rest_of_key */
+ }
+ else
+ {
+ s_temp->key_length+=s_temp->store_not_null; /* If null */
+ length= key_length - length_pack+ diff_flag;
+ }
+ }
+ s_temp->totlength=(uint) length;
+ s_temp->prev_length=0;
+ DBUG_PRINT("test",("tot_length: %u length: %d uniq_key_length: %u",
+ key_length, length, s_temp->key_length));
+
+ /* If something after that hasn't length=0, test if we can combine */
+ if ((s_temp->next_key_pos=next_key))
+ {
+ uint packed,n_length;
+
+ packed = *next_key & 128;
+ if (diff_flag == 2)
+ {
+ n_length= mi_uint2korr(next_key) & 32767; /* Length of next key */
+ next_key+=2;
+ }
+ else
+ n_length= *next_key++ & 127;
+ if (!packed)
+ n_length-= s_temp->store_not_null;
+
+ if (n_length || packed) /* Don't pack 0 length keys */
+ {
+ uint next_length_pack, new_ref_length=s_temp->ref_length;
+
+ if (packed)
+ {
+ /* If first key and next key is packed (only on delete) */
+ if (!prev_key && org_key)
+ {
+ get_key_length(org_key_length,org_key);
+ key=start;
+ if (sort_order) /* SerG */
+ {
+ while (key < end &&
+ sort_order[*key] == sort_order[*org_key])
+ {
+ key++; org_key++;
+ }
+ }
+ else
+ {
+ while (key < end && *key == *org_key)
+ {
+ key++; org_key++;
+ }
+ }
+ if ((new_ref_length= (uint) (key - start)))
+ new_ref_length+=pack_marker;
+ }
+
+ if (!n_length)
+ {
+ /*
+ We put a different key between two identical variable length keys
+ Extend next key to have same prefix as this key
+ */
+ if (new_ref_length) /* prefix of previus key */
+ { /* make next key longer */
+ s_temp->part_of_prev_key= new_ref_length;
+ s_temp->prev_length= org_key_length -
+ (new_ref_length-pack_marker);
+ s_temp->n_ref_length= s_temp->part_of_prev_key;
+ s_temp->n_length= s_temp->prev_length;
+ n_length= get_pack_length(s_temp->prev_length);
+ s_temp->prev_key+= (new_ref_length - pack_marker);
+ length+= s_temp->prev_length + n_length;
+ }
+ else
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key=0;
+ s_temp->prev_length= org_key_length;
+ s_temp->n_ref_length=s_temp->n_length= org_key_length;
+ length+= org_key_length;
+ }
+ return (s_temp->move_length= (int) length);
+ }
+
+ ref_length=n_length;
+ /* Get information about not packed key suffix */
+ get_key_pack_length(n_length,next_length_pack,next_key);
+
+ /* Test if new keys has fewer characters that match the previous key */
+ if (!new_ref_length)
+ { /* Can't use prev key */
+ s_temp->part_of_prev_key= 0;
+ s_temp->prev_length= ref_length;
+ s_temp->n_ref_length= s_temp->n_length= n_length+ref_length;
+ return s_temp->move_length= ((int) length+ref_length-
+ next_length_pack);
+ }
+ if (ref_length+pack_marker > new_ref_length)
+ {
+ uint new_pack_length=new_ref_length-pack_marker;
+ /* We must copy characters from the original key to the next key */
+ s_temp->part_of_prev_key= new_ref_length;
+ s_temp->prev_length= ref_length - new_pack_length;
+ s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length;
+ s_temp->prev_key+= new_pack_length;
+ length-= (next_length_pack - get_pack_length(s_temp->n_length));
+ return s_temp->move_length= ((int) length + s_temp->prev_length);
+ }
+ }
+ else
+ {
+ /* Next key wasn't a prefix of previous key */
+ ref_length=0;
+ next_length_pack=0;
+ }
+ DBUG_PRINT("test",("length: %d next_key: 0x%lx", length,
+ (long) next_key));
+
+ {
+ uint tmp_length;
+ key=(start+=ref_length);
+ if (key+n_length < key_end) /* Normalize length based */
+ key_end= key+n_length;
+ if (sort_order) /* SerG */
+ {
+ while (key < key_end &&
+ sort_order[*key] == sort_order[*next_key])
+ {
+ key++; next_key++;
+ }
+ }
+ else
+ {
+ while (key < key_end && *key == *next_key)
+ {
+ key++; next_key++;
+ }
+ }
+ if (!(tmp_length=(uint) (key-start)))
+ { /* Key can't be re-packed */
+ s_temp->next_key_pos=0;
+ return (s_temp->move_length= length);
+ }
+ ref_length+=tmp_length;
+ n_length-=tmp_length;
+ length-=tmp_length+next_length_pack; /* We gained these chars */
+ }
+ if (n_length == 0 && ref_length == new_key_length)
+ {
+ s_temp->n_ref_length=pack_marker; /* Same as prev key */
+ }
+ else
+ {
+ s_temp->n_ref_length=ref_length | pack_marker;
+ length+= get_pack_length(n_length);
+ s_temp->n_length=n_length;
+ }
+ }
+ }
+ return (s_temp->move_length= length);
+}
+
+
+/* Length of key which is prefix compressed */
+
+int _ma_calc_bin_pack_key_length(const MARIA_KEY *int_key,
+ uint nod_flag,
+ uchar *next_key,
+ uchar *org_key, uchar *prev_key,
+ MARIA_KEY_PARAM *s_temp)
+{
+ uint length,key_length,ref_length;
+ const uchar *key= int_key->data;
+
+ s_temp->totlength= key_length= (int_key->data_length + int_key->ref_length+
+ nod_flag);
+#ifdef HAVE_purify
+ s_temp->n_length= s_temp->n_ref_length=0; /* For valgrind */
+#endif
+ s_temp->key=key;
+ s_temp->prev_key=org_key;
+ if (prev_key) /* If not first key in block */
+ {
+ /* pack key against previous key */
+ /*
+ As keys may be identical when running a sort in maria_chk, we
+ have to guard against the case where keys may be identical
+ */
+ const uchar *end;
+ end=key+key_length;
+ for ( ; *key == *prev_key && key < end; key++,prev_key++) ;
+ s_temp->ref_length= ref_length=(uint) (key-s_temp->key);
+ length=key_length - ref_length + get_pack_length(ref_length);
+ }
+ else
+ {
+ /* No previous key */
+ s_temp->ref_length=ref_length=0;
+ length=key_length+1;
+ }
+ if ((s_temp->next_key_pos=next_key)) /* If another key after */
+ {
+ /* pack key against next key */
+ uint next_length,next_length_pack;
+ get_key_pack_length(next_length,next_length_pack,next_key);
+
+ /* If first key and next key is packed (only on delete) */
+ if (!prev_key && org_key && next_length)
+ {
+ const uchar *end;
+ for (key= s_temp->key, end=key+next_length ;
+ *key == *org_key && key < end;
+ key++,org_key++) ;
+ ref_length= (uint) (key - s_temp->key);
+ }
+
+ if (next_length > ref_length)
+ {
+ /*
+ We put a key with different case between two keys with the same prefix
+ Extend next key to have same prefix as this key
+ */
+ s_temp->n_ref_length= ref_length;
+ s_temp->prev_length= next_length-ref_length;
+ s_temp->prev_key+= ref_length;
+ return s_temp->move_length= ((int) (length+ s_temp->prev_length -
+ next_length_pack +
+ get_pack_length(ref_length)));
+ }
+ /* Check how many characters are identical to next key */
+ key= s_temp->key+next_length;
+ s_temp->prev_length= 0;
+ while (*key++ == *next_key++) ;
+ if ((ref_length= (uint) (key - s_temp->key)-1) == next_length)
+ {
+ s_temp->next_key_pos=0;
+ return (s_temp->move_length= length); /* Can't pack next key */
+ }
+ s_temp->n_ref_length=ref_length;
+ return s_temp->move_length= (int) (length-(ref_length - next_length) -
+ next_length_pack +
+ get_pack_length(ref_length));
+ }
+ return (s_temp->move_length= (int) length);
+}
+
+
+/*
+** store a key packed with _ma_calc_xxx_key_length in page-buffert
+*/
+
+/* store key without compression */
+
+void _ma_store_static_key(MARIA_KEYDEF *keyinfo __attribute__((unused)),
+ register uchar *key_pos,
+ register MARIA_KEY_PARAM *s_temp)
+{
+ memcpy(key_pos, s_temp->key,(size_t) s_temp->move_length);
+ s_temp->changed_length= s_temp->move_length;
+}
+
+
+/* store variable length key with prefix compression */
+
+#define store_pack_length(test,pos,length) { \
+ if (test) { *((pos)++) = (uchar) (length); } else \
+ { *((pos)++) = (uchar) ((length) >> 8); *((pos)++) = (uchar) (length); } }
+
+
+void _ma_store_var_pack_key(MARIA_KEYDEF *keyinfo __attribute__((unused)),
+ register uchar *key_pos,
+ register MARIA_KEY_PARAM *s_temp)
+{
+ uint length;
+ uchar *org_key_pos= key_pos;
+
+ if (s_temp->ref_length)
+ {
+ /* Packed against previous key */
+ store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->ref_length);
+ /* If not same key after */
+ if (s_temp->ref_length != s_temp->pack_marker)
+ store_key_length_inc(key_pos,s_temp->key_length);
+ }
+ else
+ {
+ /* Not packed against previous key */
+ store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->key_length);
+ }
+ bmove(key_pos, s_temp->key,
+ (length= s_temp->totlength - (uint) (key_pos-org_key_pos)));
+
+ key_pos+= length;
+
+ if (!s_temp->next_key_pos) /* No following key */
+ goto end;
+
+ if (s_temp->prev_length)
+ {
+ /* Extend next key because new key didn't have same prefix as prev key */
+ if (s_temp->part_of_prev_key)
+ {
+ store_pack_length(s_temp->pack_marker == 128,key_pos,
+ s_temp->part_of_prev_key);
+ store_key_length_inc(key_pos,s_temp->n_length);
+ }
+ else
+ {
+ s_temp->n_length+= s_temp->store_not_null;
+ store_pack_length(s_temp->pack_marker == 128,key_pos,
+ s_temp->n_length);
+ }
+ memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
+ key_pos+= s_temp->prev_length;
+ }
+ else if (s_temp->n_ref_length)
+ {
+ store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length);
+ if (s_temp->n_ref_length != s_temp->pack_marker)
+ {
+ /* Not identical key */
+ store_key_length_inc(key_pos,s_temp->n_length);
+ }
+ }
+ else
+ {
+ s_temp->n_length+= s_temp->store_not_null;
+ store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_length);
+ }
+
+end:
+ s_temp->changed_length= (uint) (key_pos - org_key_pos);
+}
+
+
+/* variable length key with prefix compression */
+
+void _ma_store_bin_pack_key(MARIA_KEYDEF *keyinfo __attribute__((unused)),
+ register uchar *key_pos,
+ register MARIA_KEY_PARAM *s_temp)
+{
+ uchar *org_key_pos= key_pos;
+ size_t length= s_temp->totlength - s_temp->ref_length;
+
+ store_key_length_inc(key_pos,s_temp->ref_length);
+ memcpy(key_pos, s_temp->key+s_temp->ref_length, length);
+ key_pos+= length;
+
+ if (s_temp->next_key_pos)
+ {
+ store_key_length_inc(key_pos,s_temp->n_ref_length);
+ if (s_temp->prev_length) /* If we must extend key */
+ {
+ memcpy(key_pos,s_temp->prev_key,s_temp->prev_length);
+ key_pos+= s_temp->prev_length;
+ }
+ }
+ s_temp->changed_length= (uint) (key_pos - org_key_pos);
+}
diff --git a/storage/maria/ma_sort.c b/storage/maria/ma_sort.c
new file mode 100644
index 00000000000..fbbf0b365db
--- /dev/null
+++ b/storage/maria/ma_sort.c
@@ -0,0 +1,1076 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Creates a index for a database by reading keys, sorting them and outputing
+ them in sorted order through MARIA_SORT_INFO functions.
+*/
+
+#include "ma_fulltext.h"
+#if defined(MSDOS) || defined(__WIN__)
+#include <fcntl.h>
+#else
+#include <stddef.h>
+#endif
+#include <queues.h>
+
+/* static variables */
+
+#undef MIN_SORT_MEMORY
+#undef MYF_RW
+#undef DISK_BUFFER_SIZE
+
+#define MERGEBUFF 15
+#define MERGEBUFF2 31
+#define MIN_SORT_MEMORY (4096-MALLOC_OVERHEAD)
+#define MYF_RW MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL)
+#define DISK_BUFFER_SIZE (IO_SIZE*16)
+
+
+/*
+ Pointers of functions for store and read keys from temp file
+*/
+
+extern void print_error _VARARGS((const char *fmt,...));
+
+/* Functions defined in this file */
+
+static ha_rows find_all_keys(MARIA_SORT_PARAM *info,uint keys,
+ uchar **sort_keys,
+ DYNAMIC_ARRAY *buffpek,int *maxbuffer,
+ IO_CACHE *tempfile,
+ IO_CACHE *tempfile_for_exceptions);
+static int write_keys(MARIA_SORT_PARAM *info, uchar **sort_keys,
+ uint count, BUFFPEK *buffpek,IO_CACHE *tempfile);
+static int write_key(MARIA_SORT_PARAM *info, uchar *key,
+ IO_CACHE *tempfile);
+static int write_index(MARIA_SORT_PARAM *info, uchar **sort_keys,
+ uint count);
+static int merge_many_buff(MARIA_SORT_PARAM *info,uint keys,
+ uchar **sort_keys,
+ BUFFPEK *buffpek,int *maxbuffer,
+ IO_CACHE *t_file);
+static uint read_to_buffer(IO_CACHE *fromfile,BUFFPEK *buffpek,
+ uint sort_length);
+static int merge_buffers(MARIA_SORT_PARAM *info,uint keys,
+ IO_CACHE *from_file, IO_CACHE *to_file,
+ uchar **sort_keys, BUFFPEK *lastbuff,
+ BUFFPEK *Fb, BUFFPEK *Tb);
+static int merge_index(MARIA_SORT_PARAM *,uint, uchar **,BUFFPEK *, int,
+ IO_CACHE *);
+static int flush_maria_ft_buf(MARIA_SORT_PARAM *info);
+
+static int write_keys_varlen(MARIA_SORT_PARAM *info, uchar **sort_keys,
+ uint count, BUFFPEK *buffpek,
+ IO_CACHE *tempfile);
+static uint read_to_buffer_varlen(IO_CACHE *fromfile,BUFFPEK *buffpek,
+ uint sort_length);
+static int write_merge_key(MARIA_SORT_PARAM *info, IO_CACHE *to_file,
+ uchar *key, uint sort_length, uint count);
+static int write_merge_key_varlen(MARIA_SORT_PARAM *info,
+ IO_CACHE *to_file, uchar *key,
+ uint sort_length, uint count);
+static inline int
+my_var_write(MARIA_SORT_PARAM *info, IO_CACHE *to_file, uchar *bufs);
+
+/*
+ Creates a index of sorted keys
+
+ SYNOPSIS
+ _ma_create_index_by_sort()
+ info Sort parameters
+ no_messages Set to 1 if no output
+ sortbuff_size Size of sortbuffer to allocate
+
+ RESULT
+ 0 ok
+ <> 0 Error
+*/
+
+int _ma_create_index_by_sort(MARIA_SORT_PARAM *info, my_bool no_messages,
+ size_t sortbuff_size)
+{
+ int error,maxbuffer,skr;
+ size_t memavl,old_memavl;
+ uint keys,sort_length;
+ DYNAMIC_ARRAY buffpek;
+ ha_rows records;
+ uchar **sort_keys;
+ IO_CACHE tempfile, tempfile_for_exceptions;
+ DBUG_ENTER("_ma_create_index_by_sort");
+ DBUG_PRINT("enter",("sort_buff_size: %lu sort_length: %d max_records: %lu",
+ (ulong) sortbuff_size, info->key_length,
+ (ulong) info->sort_info->max_records));
+
+ if (info->keyinfo->flag & HA_VAR_LENGTH_KEY)
+ {
+ info->write_keys= write_keys_varlen;
+ info->read_to_buffer=read_to_buffer_varlen;
+ info->write_key=write_merge_key_varlen;
+ }
+ else
+ {
+ info->write_keys= write_keys;
+ info->read_to_buffer=read_to_buffer;
+ info->write_key=write_merge_key;
+ }
+
+ my_b_clear(&tempfile);
+ my_b_clear(&tempfile_for_exceptions);
+ bzero((char*) &buffpek,sizeof(buffpek));
+ sort_keys= (uchar **) NULL; error= 1;
+ maxbuffer=1;
+
+ memavl=max(sortbuff_size,MIN_SORT_MEMORY);
+ records= info->sort_info->max_records;
+ sort_length= info->key_length;
+ LINT_INIT(keys);
+
+ while (memavl >= MIN_SORT_MEMORY)
+ {
+ if ((records < UINT_MAX32) &&
+ ((my_off_t) (records + 1) *
+ (sort_length + sizeof(char*)) <= (my_off_t) memavl))
+ keys= (uint)records+1;
+ else
+ do
+ {
+ skr=maxbuffer;
+ if (memavl < sizeof(BUFFPEK)*(uint) maxbuffer ||
+ (keys=(memavl-sizeof(BUFFPEK)*(uint) maxbuffer)/
+ (sort_length+sizeof(char*))) <= 1 ||
+ keys < (uint) maxbuffer)
+ {
+ _ma_check_print_error(info->sort_info->param,
+ "maria_sort_buffer_size is too small");
+ goto err;
+ }
+ }
+ while ((maxbuffer= (int) (records/(keys-1)+1)) != skr);
+
+ if ((sort_keys=(uchar**) my_malloc(keys*(sort_length+sizeof(char*))+
+ HA_FT_MAXBYTELEN, MYF(0))))
+ {
+ if (my_init_dynamic_array(&buffpek, sizeof(BUFFPEK), maxbuffer,
+ maxbuffer/2))
+ {
+ my_free((uchar*) sort_keys,MYF(0));
+ sort_keys= 0;
+ }
+ else
+ break;
+ }
+ old_memavl=memavl;
+ if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY)
+ memavl=MIN_SORT_MEMORY;
+ }
+ if (memavl < MIN_SORT_MEMORY)
+ {
+ _ma_check_print_error(info->sort_info->param, "Maria sort buffer"
+ " too small"); /* purecov: tested */
+ goto err; /* purecov: tested */
+ }
+ (*info->lock_in_memory)(info->sort_info->param);/* Everything is allocated */
+
+ if (!no_messages)
+ printf(" - Searching for keys, allocating buffer for %d keys\n",keys);
+
+ if ((records=find_all_keys(info,keys,sort_keys,&buffpek,&maxbuffer,
+ &tempfile,&tempfile_for_exceptions))
+ == HA_POS_ERROR)
+ goto err; /* purecov: tested */
+ if (maxbuffer == 0)
+ {
+ if (!no_messages)
+ printf(" - Dumping %lu keys\n", (ulong) records);
+ if (write_index(info,sort_keys, (uint) records))
+ goto err; /* purecov: inspected */
+ }
+ else
+ {
+ keys=(keys*(sort_length+sizeof(char*)))/sort_length;
+ if (maxbuffer >= MERGEBUFF2)
+ {
+ if (!no_messages)
+ printf(" - Merging %lu keys\n", (ulong) records); /* purecov: tested */
+ if (merge_many_buff(info,keys,sort_keys,
+ dynamic_element(&buffpek,0,BUFFPEK *),&maxbuffer,&tempfile))
+ goto err; /* purecov: inspected */
+ }
+ if (flush_io_cache(&tempfile) ||
+ reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
+ goto err; /* purecov: inspected */
+ if (!no_messages)
+ printf(" - Last merge and dumping keys\n"); /* purecov: tested */
+ if (merge_index(info,keys,sort_keys,dynamic_element(&buffpek,0,BUFFPEK *),
+ maxbuffer,&tempfile))
+ goto err; /* purecov: inspected */
+ }
+
+ if (flush_maria_ft_buf(info) || _ma_flush_pending_blocks(info))
+ goto err;
+
+ if (my_b_inited(&tempfile_for_exceptions))
+ {
+ MARIA_HA *idx=info->sort_info->info;
+ uint16 key_length;
+ MARIA_KEY key;
+ key.keyinfo= idx->s->keyinfo + info->key;
+
+ if (!no_messages)
+ printf(" - Adding exceptions\n"); /* purecov: tested */
+ if (flush_io_cache(&tempfile_for_exceptions) ||
+ reinit_io_cache(&tempfile_for_exceptions,READ_CACHE,0L,0,0))
+ goto err;
+
+ while (!my_b_read(&tempfile_for_exceptions,(uchar*)&key_length,
+ sizeof(key_length))
+ && !my_b_read(&tempfile_for_exceptions,(uchar*)sort_keys,
+ (uint) key_length))
+ {
+ key.data= (uchar*) sort_keys;
+ key.ref_length= idx->s->rec_reflength;
+ key.data_length= key_length - key.ref_length;
+ key.flag= 0;
+ if (_ma_ck_write(idx, &key))
+ goto err;
+ }
+ }
+
+ error =0;
+
+err:
+ if (sort_keys)
+ my_free((uchar*) sort_keys,MYF(0));
+ delete_dynamic(&buffpek);
+ close_cached_file(&tempfile);
+ close_cached_file(&tempfile_for_exceptions);
+
+ DBUG_RETURN(error ? -1 : 0);
+} /* _ma_create_index_by_sort */
+
+
+/* Search after all keys and place them in a temp. file */
+
+static ha_rows find_all_keys(MARIA_SORT_PARAM *info, uint keys,
+ uchar **sort_keys, DYNAMIC_ARRAY *buffpek,
+ int *maxbuffer, IO_CACHE *tempfile,
+ IO_CACHE *tempfile_for_exceptions)
+{
+ int error;
+ uint idx;
+ DBUG_ENTER("find_all_keys");
+
+ idx=error=0;
+ sort_keys[0]= (uchar*) (sort_keys+keys);
+
+ while (!(error=(*info->key_read)(info,sort_keys[idx])))
+ {
+ if (info->real_key_length > info->key_length)
+ {
+ if (write_key(info,sort_keys[idx],tempfile_for_exceptions))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ continue;
+ }
+
+ if (++idx == keys)
+ {
+ if (info->write_keys(info,sort_keys,idx-1,
+ (BUFFPEK *)alloc_dynamic(buffpek),
+ tempfile))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+
+ sort_keys[0]=(uchar*) (sort_keys+keys);
+ memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length);
+ idx=1;
+ }
+ sort_keys[idx]=sort_keys[idx-1]+info->key_length;
+ }
+ if (error > 0)
+ DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */ /* purecov: inspected */
+ if (buffpek->elements)
+ {
+ if (info->write_keys(info,sort_keys,idx,(BUFFPEK *)alloc_dynamic(buffpek),
+ tempfile))
+ DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */
+ *maxbuffer=buffpek->elements-1;
+ }
+ else
+ *maxbuffer=0;
+
+ DBUG_RETURN((*maxbuffer)*(keys-1)+idx);
+} /* find_all_keys */
+
+
+#ifdef THREAD
+/* Search after all keys and place them in a temp. file */
+
+pthread_handler_t _ma_thr_find_all_keys(void *arg)
+{
+ MARIA_SORT_PARAM *sort_param= (MARIA_SORT_PARAM*) arg;
+ int error;
+ size_t memavl,old_memavl;
+ uint sort_length;
+ ulong idx, maxbuffer, keys;
+ uchar **sort_keys=0;
+
+ LINT_INIT(keys);
+
+ error=1;
+
+ if (my_thread_init())
+ goto err;
+
+ { /* Add extra block since DBUG_ENTER declare variables */
+ DBUG_ENTER("_ma_thr_find_all_keys");
+ DBUG_PRINT("enter", ("master: %d", sort_param->master));
+ if (sort_param->sort_info->got_error)
+ goto err;
+
+ if (sort_param->keyinfo->flag & HA_VAR_LENGTH_KEY)
+ {
+ sort_param->write_keys= write_keys_varlen;
+ sort_param->read_to_buffer= read_to_buffer_varlen;
+ sort_param->write_key= write_merge_key_varlen;
+ }
+ else
+ {
+ sort_param->write_keys= write_keys;
+ sort_param->read_to_buffer= read_to_buffer;
+ sort_param->write_key= write_merge_key;
+ }
+
+ my_b_clear(&sort_param->tempfile);
+ my_b_clear(&sort_param->tempfile_for_exceptions);
+ bzero((char*) &sort_param->buffpek,sizeof(sort_param->buffpek));
+ bzero((char*) &sort_param->unique, sizeof(sort_param->unique));
+
+ memavl= max(sort_param->sortbuff_size, MIN_SORT_MEMORY);
+ idx= (uint)sort_param->sort_info->max_records;
+ sort_length= sort_param->key_length;
+ maxbuffer= 1;
+
+ while (memavl >= MIN_SORT_MEMORY)
+ {
+ if ((my_off_t) (idx+1)*(sort_length+sizeof(char*)) <= (my_off_t) memavl)
+ keys= idx+1;
+ else
+ {
+ ulong skr;
+ do
+ {
+ skr= maxbuffer;
+ if (memavl < sizeof(BUFFPEK)*maxbuffer ||
+ (keys=(memavl-sizeof(BUFFPEK)*maxbuffer)/
+ (sort_length+sizeof(char*))) <= 1 ||
+ keys < maxbuffer)
+ {
+ _ma_check_print_error(sort_param->sort_info->param,
+ "maria_sort_buffer_size is too small");
+ goto err;
+ }
+ }
+ while ((maxbuffer= (int) (idx/(keys-1)+1)) != skr);
+ }
+ if ((sort_keys= (uchar **)
+ my_malloc(keys*(sort_length+sizeof(char*))+
+ ((sort_param->keyinfo->flag & HA_FULLTEXT) ?
+ HA_FT_MAXBYTELEN : 0), MYF(0))))
+ {
+ if (my_init_dynamic_array(&sort_param->buffpek, sizeof(BUFFPEK),
+ maxbuffer, maxbuffer/2))
+ {
+ my_free((uchar*) sort_keys,MYF(0));
+ sort_keys= (uchar **) NULL; /* for err: label */
+ }
+ else
+ break;
+ }
+ old_memavl= memavl;
+ if ((memavl= memavl/4*3) < MIN_SORT_MEMORY &&
+ old_memavl > MIN_SORT_MEMORY)
+ memavl= MIN_SORT_MEMORY;
+ }
+ if (memavl < MIN_SORT_MEMORY)
+ {
+ _ma_check_print_error(sort_param->sort_info->param,
+ "Maria sort buffer too small");
+ goto err; /* purecov: tested */
+ }
+
+ if (sort_param->sort_info->param->testflag & T_VERBOSE)
+ printf("Key %d - Allocating buffer for %lu keys\n",
+ sort_param->key+1, (ulong) keys);
+ sort_param->sort_keys= sort_keys;
+
+ idx= error= 0;
+ sort_keys[0]= (uchar*) (sort_keys+keys);
+
+ DBUG_PRINT("info", ("reading keys"));
+ while (!(error= sort_param->sort_info->got_error) &&
+ !(error= (*sort_param->key_read)(sort_param, sort_keys[idx])))
+ {
+ if (sort_param->real_key_length > sort_param->key_length)
+ {
+ if (write_key(sort_param,sort_keys[idx],
+ &sort_param->tempfile_for_exceptions))
+ goto err;
+ continue;
+ }
+
+ if (++idx == keys)
+ {
+ if (sort_param->write_keys(sort_param, sort_keys, idx - 1,
+ (BUFFPEK *)alloc_dynamic(&sort_param->
+ buffpek),
+ &sort_param->tempfile))
+ goto err;
+ sort_keys[0]= (uchar*) (sort_keys+keys);
+ memcpy(sort_keys[0], sort_keys[idx - 1],
+ (size_t) sort_param->key_length);
+ idx= 1;
+ }
+ sort_keys[idx]=sort_keys[idx - 1] + sort_param->key_length;
+ }
+ if (error > 0)
+ goto err;
+ if (sort_param->buffpek.elements)
+ {
+ if (sort_param->write_keys(sort_param,sort_keys, idx,
+ (BUFFPEK *) alloc_dynamic(&sort_param->
+ buffpek),
+ &sort_param->tempfile))
+ goto err;
+ sort_param->keys= (sort_param->buffpek.elements - 1) * (keys - 1) + idx;
+ }
+ else
+ sort_param->keys= idx;
+
+ sort_param->sort_keys_length= keys;
+ goto ok;
+
+err:
+ DBUG_PRINT("error", ("got some error"));
+ sort_param->sort_info->got_error= 1; /* no need to protect with a mutex */
+ my_free((uchar*) sort_keys,MYF(MY_ALLOW_ZERO_PTR));
+ sort_param->sort_keys=0;
+ delete_dynamic(& sort_param->buffpek);
+ close_cached_file(&sort_param->tempfile);
+ close_cached_file(&sort_param->tempfile_for_exceptions);
+
+ok:
+ free_root(&sort_param->wordroot, MYF(0));
+ /*
+ Detach from the share if the writer is involved. Avoid others to
+ be blocked. This includes a flush of the write buffer. This will
+ also indicate EOF to the readers.
+ */
+ if (sort_param->sort_info->info->rec_cache.share)
+ remove_io_thread(&sort_param->sort_info->info->rec_cache);
+
+ /* Readers detach from the share if any. Avoid others to be blocked. */
+ if (sort_param->read_cache.share)
+ remove_io_thread(&sort_param->read_cache);
+
+ pthread_mutex_lock(&sort_param->sort_info->mutex);
+ if (!--sort_param->sort_info->threads_running)
+ pthread_cond_signal(&sort_param->sort_info->cond);
+ pthread_mutex_unlock(&sort_param->sort_info->mutex);
+ DBUG_PRINT("exit", ("======== ending thread ========"));
+ }
+ my_thread_end();
+ return NULL;
+}
+
+
+int _ma_thr_write_keys(MARIA_SORT_PARAM *sort_param)
+{
+ MARIA_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
+ ulong length, keys;
+ double *rec_per_key_part= param->new_rec_per_key_part;
+ int got_error=sort_info->got_error;
+ uint i;
+ MARIA_HA *info=sort_info->info;
+ MARIA_SHARE *share= info->s;
+ MARIA_SORT_PARAM *sinfo;
+ uchar *mergebuf=0;
+ DBUG_ENTER("_ma_thr_write_keys");
+ LINT_INIT(length);
+
+ for (i= 0, sinfo= sort_param ;
+ i < sort_info->total_keys ;
+ i++, rec_per_key_part+=sinfo->keyinfo->keysegs, sinfo++)
+ {
+ if (!sinfo->sort_keys)
+ {
+ got_error=1;
+ my_free(sinfo->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
+ continue;
+ }
+ if (!got_error)
+ {
+ maria_set_key_active(share->state.key_map, sinfo->key);
+
+ if (!sinfo->buffpek.elements)
+ {
+ if (param->testflag & T_VERBOSE)
+ {
+ printf("Key %d - Dumping %u keys\n",sinfo->key+1, sinfo->keys);
+ fflush(stdout);
+ }
+ if (write_index(sinfo, sinfo->sort_keys, sinfo->keys) ||
+ flush_maria_ft_buf(sinfo) || _ma_flush_pending_blocks(sinfo))
+ got_error=1;
+ }
+ if (!got_error && param->testflag & T_STATISTICS)
+ maria_update_key_parts(sinfo->keyinfo, rec_per_key_part, sinfo->unique,
+ param->stats_method ==
+ MI_STATS_METHOD_IGNORE_NULLS ?
+ sinfo->notnull : NULL,
+ (ulonglong) share->state.state.records);
+ }
+ my_free((uchar*) sinfo->sort_keys,MYF(0));
+ my_free(sinfo->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
+ sinfo->sort_keys=0;
+ }
+
+ for (i= 0, sinfo= sort_param ;
+ i < sort_info->total_keys ;
+ i++,
+ delete_dynamic(&sinfo->buffpek),
+ close_cached_file(&sinfo->tempfile),
+ close_cached_file(&sinfo->tempfile_for_exceptions),
+ sinfo++)
+ {
+ if (got_error)
+ continue;
+ if (sinfo->keyinfo->flag & HA_VAR_LENGTH_KEY)
+ {
+ sinfo->write_keys=write_keys_varlen;
+ sinfo->read_to_buffer=read_to_buffer_varlen;
+ sinfo->write_key=write_merge_key_varlen;
+ }
+ else
+ {
+ sinfo->write_keys=write_keys;
+ sinfo->read_to_buffer=read_to_buffer;
+ sinfo->write_key=write_merge_key;
+ }
+ if (sinfo->buffpek.elements)
+ {
+ uint maxbuffer=sinfo->buffpek.elements-1;
+ if (!mergebuf)
+ {
+ length=param->sort_buffer_length;
+ while (length >= MIN_SORT_MEMORY)
+ {
+ if ((mergebuf= my_malloc(length, MYF(0))))
+ break;
+ length=length*3/4;
+ }
+ if (!mergebuf)
+ {
+ got_error=1;
+ continue;
+ }
+ }
+ keys=length/sinfo->key_length;
+ if (maxbuffer >= MERGEBUFF2)
+ {
+ if (param->testflag & T_VERBOSE)
+ printf("Key %d - Merging %u keys\n",sinfo->key+1, sinfo->keys);
+ if (merge_many_buff(sinfo, keys, (uchar **) mergebuf,
+ dynamic_element(&sinfo->buffpek, 0, BUFFPEK *),
+ (int*) &maxbuffer, &sinfo->tempfile))
+ {
+ got_error=1;
+ continue;
+ }
+ }
+ if (flush_io_cache(&sinfo->tempfile) ||
+ reinit_io_cache(&sinfo->tempfile,READ_CACHE,0L,0,0))
+ {
+ got_error=1;
+ continue;
+ }
+ if (param->testflag & T_VERBOSE)
+ printf("Key %d - Last merge and dumping keys\n", sinfo->key+1);
+ if (merge_index(sinfo, keys, (uchar**) mergebuf,
+ dynamic_element(&sinfo->buffpek,0,BUFFPEK *),
+ maxbuffer,&sinfo->tempfile) ||
+ flush_maria_ft_buf(sinfo) ||
+ _ma_flush_pending_blocks(sinfo))
+ {
+ got_error=1;
+ continue;
+ }
+ }
+ if (my_b_inited(&sinfo->tempfile_for_exceptions))
+ {
+ uint16 key_length;
+
+ if (param->testflag & T_VERBOSE)
+ printf("Key %d - Dumping 'long' keys\n", sinfo->key+1);
+
+ if (flush_io_cache(&sinfo->tempfile_for_exceptions) ||
+ reinit_io_cache(&sinfo->tempfile_for_exceptions,READ_CACHE,0L,0,0))
+ {
+ got_error=1;
+ continue;
+ }
+
+ while (!got_error &&
+ !my_b_read(&sinfo->tempfile_for_exceptions,(uchar*)&key_length,
+ sizeof(key_length)))
+ {
+ uchar maria_ft_buf[HA_FT_MAXBYTELEN + HA_FT_WLEN + 10];
+ if (key_length > sizeof(maria_ft_buf) ||
+ my_b_read(&sinfo->tempfile_for_exceptions, (uchar*)maria_ft_buf,
+ (uint) key_length))
+ got_error= 1;
+ else
+ {
+ MARIA_KEY tmp_key;
+ tmp_key.keyinfo= info->s->keyinfo + sinfo->key;
+ tmp_key.data= maria_ft_buf;
+ tmp_key.ref_length= info->s->rec_reflength;
+ tmp_key.data_length= key_length - info->s->rec_reflength;
+ tmp_key.flag= 0;
+ if (_ma_ck_write(info, &tmp_key))
+ got_error=1;
+ }
+ }
+ }
+ }
+ my_free((uchar*) mergebuf,MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_RETURN(got_error);
+}
+#endif /* THREAD */
+
+/* Write all keys in memory to file for later merge */
+
+static int write_keys(MARIA_SORT_PARAM *info, register uchar **sort_keys,
+ uint count, BUFFPEK *buffpek, IO_CACHE *tempfile)
+{
+ uchar **end;
+ uint sort_length=info->key_length;
+ DBUG_ENTER("write_keys");
+
+ my_qsort2((uchar*) sort_keys,count,sizeof(uchar*),(qsort2_cmp) info->key_cmp,
+ info);
+ if (!my_b_inited(tempfile) &&
+ open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST",
+ DISK_BUFFER_SIZE, info->sort_info->param->myf_rw))
+ DBUG_RETURN(1); /* purecov: inspected */
+
+ buffpek->file_pos=my_b_tell(tempfile);
+ buffpek->count=count;
+
+ for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
+ {
+ if (my_b_write(tempfile, *sort_keys, (uint) sort_length))
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+ DBUG_RETURN(0);
+} /* write_keys */
+
+
+static inline int
+my_var_write(MARIA_SORT_PARAM *info, IO_CACHE *to_file, uchar *bufs)
+{
+ int err;
+ uint16 len= _ma_keylength(info->keyinfo, bufs);
+
+ /* The following is safe as this is a local file */
+ if ((err= my_b_write(to_file, (uchar*)&len, sizeof(len))))
+ return (err);
+ if ((err= my_b_write(to_file,bufs, (uint) len)))
+ return (err);
+ return (0);
+}
+
+
+static int write_keys_varlen(MARIA_SORT_PARAM *info,
+ register uchar **sort_keys,
+ uint count, BUFFPEK *buffpek,
+ IO_CACHE *tempfile)
+{
+ uchar **end;
+ int err;
+ DBUG_ENTER("write_keys_varlen");
+
+ my_qsort2((uchar*) sort_keys,count,sizeof(uchar*),(qsort2_cmp) info->key_cmp,
+ info);
+ if (!my_b_inited(tempfile) &&
+ open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST",
+ DISK_BUFFER_SIZE, info->sort_info->param->myf_rw))
+ DBUG_RETURN(1); /* purecov: inspected */
+
+ buffpek->file_pos=my_b_tell(tempfile);
+ buffpek->count=count;
+ for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
+ {
+ if ((err= my_var_write(info,tempfile, *sort_keys)))
+ DBUG_RETURN(err);
+ }
+ DBUG_RETURN(0);
+} /* write_keys_varlen */
+
+
+static int write_key(MARIA_SORT_PARAM *info, uchar *key,
+ IO_CACHE *tempfile)
+{
+ uint16 key_length=info->real_key_length;
+ DBUG_ENTER("write_key");
+
+ if (!my_b_inited(tempfile) &&
+ open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST",
+ DISK_BUFFER_SIZE, info->sort_info->param->myf_rw))
+ DBUG_RETURN(1);
+
+ if (my_b_write(tempfile, (uchar*)&key_length,sizeof(key_length)) ||
+ my_b_write(tempfile, key, (uint) key_length))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* write_key */
+
+
+/* Write index */
+
+static int write_index(MARIA_SORT_PARAM *info,
+ register uchar **sort_keys,
+ register uint count)
+{
+ DBUG_ENTER("write_index");
+
+ my_qsort2((uchar*) sort_keys,(size_t) count,sizeof(uchar*),
+ (qsort2_cmp) info->key_cmp,info);
+ while (count--)
+ {
+ if ((*info->key_write)(info, *sort_keys++))
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ DBUG_RETURN(0);
+} /* write_index */
+
+
+ /* Merge buffers to make < MERGEBUFF2 buffers */
+
+static int merge_many_buff(MARIA_SORT_PARAM *info, uint keys,
+ uchar **sort_keys, BUFFPEK *buffpek,
+ int *maxbuffer, IO_CACHE *t_file)
+{
+ register int i;
+ IO_CACHE t_file2, *from_file, *to_file, *temp;
+ BUFFPEK *lastbuff;
+ DBUG_ENTER("merge_many_buff");
+
+ if (*maxbuffer < MERGEBUFF2)
+ DBUG_RETURN(0); /* purecov: inspected */
+ if (flush_io_cache(t_file) ||
+ open_cached_file(&t_file2,my_tmpdir(info->tmpdir),"ST",
+ DISK_BUFFER_SIZE, info->sort_info->param->myf_rw))
+ DBUG_RETURN(1); /* purecov: inspected */
+
+ from_file= t_file ; to_file= &t_file2;
+ while (*maxbuffer >= MERGEBUFF2)
+ {
+ reinit_io_cache(from_file,READ_CACHE,0L,0,0);
+ reinit_io_cache(to_file,WRITE_CACHE,0L,0,0);
+ lastbuff=buffpek;
+ for (i=0 ; i <= *maxbuffer-MERGEBUFF*3/2 ; i+=MERGEBUFF)
+ {
+ if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+i+MERGEBUFF-1))
+ goto cleanup;
+ }
+ if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++,
+ buffpek+i,buffpek+ *maxbuffer))
+ break; /* purecov: inspected */
+ if (flush_io_cache(to_file))
+ break; /* purecov: inspected */
+ temp=from_file; from_file=to_file; to_file=temp;
+ *maxbuffer= (int) (lastbuff-buffpek)-1;
+ }
+cleanup:
+ close_cached_file(to_file); /* This holds old result */
+ if (to_file == t_file)
+ *t_file=t_file2; /* Copy result file */
+
+ DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */
+} /* merge_many_buff */
+
+
+/*
+ Read data to buffer
+
+ SYNOPSIS
+ read_to_buffer()
+ fromfile File to read from
+ buffpek Where to read from
+ sort_length max length to read
+ RESULT
+ > 0 Ammount of bytes read
+ -1 Error
+*/
+
+static uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
+ uint sort_length)
+{
+ register uint count;
+ uint length;
+
+ if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
+ {
+ if (my_pread(fromfile->file,(uchar*) buffpek->base,
+ (length= sort_length*count),buffpek->file_pos,MYF_RW))
+ return((uint) -1); /* purecov: inspected */
+ buffpek->key=buffpek->base;
+ buffpek->file_pos+= length; /* New filepos */
+ buffpek->count-= count;
+ buffpek->mem_count= count;
+ }
+ return (count*sort_length);
+} /* read_to_buffer */
+
+static uint read_to_buffer_varlen(IO_CACHE *fromfile, BUFFPEK *buffpek,
+ uint sort_length)
+{
+ register uint count;
+ uint idx;
+ uchar *buffp;
+
+ if ((count=(uint) min((ha_rows) buffpek->max_keys,buffpek->count)))
+ {
+ buffp= buffpek->base;
+
+ for (idx=1;idx<=count;idx++)
+ {
+ uint16 length_of_key;
+ if (my_pread(fromfile->file,(uchar*)&length_of_key,sizeof(length_of_key),
+ buffpek->file_pos,MYF_RW))
+ return((uint) -1);
+ buffpek->file_pos+=sizeof(length_of_key);
+ if (my_pread(fromfile->file,(uchar*) buffp,length_of_key,
+ buffpek->file_pos,MYF_RW))
+ return((uint) -1);
+ buffpek->file_pos+=length_of_key;
+ buffp = buffp + sort_length;
+ }
+ buffpek->key=buffpek->base;
+ buffpek->count-= count;
+ buffpek->mem_count= count;
+ }
+ return (count*sort_length);
+} /* read_to_buffer_varlen */
+
+
+static int write_merge_key_varlen(MARIA_SORT_PARAM *info,
+ IO_CACHE *to_file, uchar* key,
+ uint sort_length, uint count)
+{
+ uint idx;
+ uchar *bufs = key;
+
+ for (idx=1;idx<=count;idx++)
+ {
+ int err;
+ if ((err= my_var_write(info, to_file, bufs)))
+ return (err);
+ bufs=bufs+sort_length;
+ }
+ return(0);
+}
+
+
+static int write_merge_key(MARIA_SORT_PARAM *info __attribute__((unused)),
+ IO_CACHE *to_file, uchar *key,
+ uint sort_length, uint count)
+{
+ return my_b_write(to_file, key, (size_t) sort_length*count);
+}
+
+/*
+ Merge buffers to one buffer
+ If to_file == 0 then use info->key_write
+*/
+
+static int NEAR_F
+merge_buffers(MARIA_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
+ IO_CACHE *to_file, uchar **sort_keys, BUFFPEK *lastbuff,
+ BUFFPEK *Fb, BUFFPEK *Tb)
+{
+ int error;
+ uint sort_length,maxcount;
+ ha_rows count;
+ my_off_t to_start_filepos;
+ uchar *strpos;
+ BUFFPEK *buffpek,**refpek;
+ QUEUE queue;
+ volatile int *killed= _ma_killed_ptr(info->sort_info->param);
+ DBUG_ENTER("merge_buffers");
+
+ count=error=0;
+ maxcount=keys/((uint) (Tb-Fb) +1);
+ DBUG_ASSERT(maxcount > 0);
+ LINT_INIT(to_start_filepos);
+ if (to_file)
+ to_start_filepos=my_b_tell(to_file);
+ strpos= (uchar*) sort_keys;
+ sort_length=info->key_length;
+
+ if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
+ (int (*)(void*, uchar *,uchar*)) info->key_cmp,
+ (void*) info))
+ DBUG_RETURN(1); /* purecov: inspected */
+
+ for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
+ {
+ count+= buffpek->count;
+ buffpek->base= strpos;
+ buffpek->max_keys=maxcount;
+ strpos+= (uint) (error=(int) info->read_to_buffer(from_file,buffpek,
+ sort_length));
+ if (error == -1)
+ goto err; /* purecov: inspected */
+ queue_insert(&queue,(uchar*) buffpek);
+ }
+
+ while (queue.elements > 1)
+ {
+ for (;;)
+ {
+ if (*killed)
+ {
+ error=1; goto err;
+ }
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ if (to_file)
+ {
+ if (info->write_key(info,to_file,(uchar*) buffpek->key,
+ (uint) sort_length,1))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ }
+ else
+ {
+ if ((*info->key_write)(info,(void*) buffpek->key))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ }
+ buffpek->key+=sort_length;
+ if (! --buffpek->mem_count)
+ {
+ if (!(error=(int) info->read_to_buffer(from_file,buffpek,sort_length)))
+ {
+ uchar *base= buffpek->base;
+ uint max_keys=buffpek->max_keys;
+
+ VOID(queue_remove(&queue,0));
+
+ /* Put room used by buffer to use in other buffer */
+ for (refpek= (BUFFPEK**) &queue_top(&queue);
+ refpek <= (BUFFPEK**) &queue_end(&queue);
+ refpek++)
+ {
+ buffpek= *refpek;
+ if (buffpek->base+buffpek->max_keys*sort_length == base)
+ {
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ else if (base+max_keys*sort_length == buffpek->base)
+ {
+ buffpek->base=base;
+ buffpek->max_keys+=max_keys;
+ break;
+ }
+ }
+ break; /* One buffer have been removed */
+ }
+ }
+ else if (error == -1)
+ goto err; /* purecov: inspected */
+ queue_replaced(&queue); /* Top element has been replaced */
+ }
+ }
+ buffpek=(BUFFPEK*) queue_top(&queue);
+ buffpek->base= (uchar*) sort_keys;
+ buffpek->max_keys=keys;
+ do
+ {
+ if (to_file)
+ {
+ if (info->write_key(info,to_file,(uchar*) buffpek->key,
+ sort_length,buffpek->mem_count))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ }
+ else
+ {
+ register uchar *end;
+ strpos= buffpek->key;
+ for (end= strpos+buffpek->mem_count*sort_length;
+ strpos != end ;
+ strpos+=sort_length)
+ {
+ if ((*info->key_write)(info, (uchar*) strpos))
+ {
+ error=1; goto err; /* purecov: inspected */
+ }
+ }
+ }
+ }
+ while ((error=(int) info->read_to_buffer(from_file,buffpek,sort_length)) !=
+ -1 && error != 0);
+
+ lastbuff->count=count;
+ if (to_file)
+ lastbuff->file_pos=to_start_filepos;
+err:
+ delete_queue(&queue);
+ DBUG_RETURN(error);
+} /* merge_buffers */
+
+
+ /* Do a merge to output-file (save only positions) */
+
+static int NEAR_F
+merge_index(MARIA_SORT_PARAM *info, uint keys, uchar **sort_keys,
+ BUFFPEK *buffpek, int maxbuffer, IO_CACHE *tempfile)
+{
+ DBUG_ENTER("merge_index");
+ if (merge_buffers(info,keys,tempfile,(IO_CACHE*) 0,sort_keys,buffpek,buffpek,
+ buffpek+maxbuffer))
+ DBUG_RETURN(1); /* purecov: inspected */
+ DBUG_RETURN(0);
+} /* merge_index */
+
+
+static int flush_maria_ft_buf(MARIA_SORT_PARAM *info)
+{
+ int err=0;
+ if (info->sort_info->ft_buf)
+ {
+ err=_ma_sort_ft_buf_flush(info);
+ my_free((uchar*)info->sort_info->ft_buf, MYF(0));
+ info->sort_info->ft_buf=0;
+ }
+ return err;
+}
diff --git a/storage/maria/ma_sp_defs.h b/storage/maria/ma_sp_defs.h
new file mode 100644
index 00000000000..398bf99c52e
--- /dev/null
+++ b/storage/maria/ma_sp_defs.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin & MySQL Finland AB
+ & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _SP_DEFS_H
+#define _SP_DEFS_H
+
+#define SPDIMS 2
+#define SPTYPE HA_KEYTYPE_DOUBLE
+#define SPLEN 8
+
+#ifdef HAVE_SPATIAL
+
+enum wkbType
+{
+ wkbPoint = 1,
+ wkbLineString = 2,
+ wkbPolygon = 3,
+ wkbMultiPoint = 4,
+ wkbMultiLineString = 5,
+ wkbMultiPolygon = 6,
+ wkbGeometryCollection = 7
+};
+
+enum wkbByteOrder
+{
+ wkbXDR = 0, /* Big Endian */
+ wkbNDR = 1 /* Little Endian */
+};
+
+MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr,
+ uchar *key, const uchar *record, my_off_t filepos,
+ ulonglong trid);
+
+#endif /*HAVE_SPATIAL*/
+#endif /* _SP_DEFS_H */
diff --git a/storage/maria/ma_sp_key.c b/storage/maria/ma_sp_key.c
new file mode 100644
index 00000000000..22944a5db0a
--- /dev/null
+++ b/storage/maria/ma_sp_key.c
@@ -0,0 +1,305 @@
+/* Copyright (C) 2006 MySQL AB & Ramil Kalimullin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "ma_blockrec.h" /* For ROW_FLAG_TRANSID */
+#include "trnman.h"
+
+#ifdef HAVE_SPATIAL
+
+#include "ma_sp_defs.h"
+
+static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order, double *mbr);
+static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order, double *mbr);
+static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order, double *mbr);
+static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order, double *mbr);
+static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ double *mbr, int top);
+static int sp_mbr_from_wkb(uchar (*wkb), uint size, uint n_dims, double *mbr);
+
+
+/**
+ Create spactial key
+*/
+
+MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr,
+ uchar *key, const uchar *record, my_off_t filepos,
+ ulonglong trid)
+{
+ HA_KEYSEG *keyseg;
+ MARIA_KEYDEF *keyinfo = &info->s->keyinfo[keynr];
+ uint len = 0;
+ const uchar *pos;
+ uint dlen;
+ uchar *dptr;
+ double mbr[SPDIMS * 2];
+ uint i;
+ DBUG_ENTER("_ma_sp_make_key");
+
+ keyseg = &keyinfo->seg[-1];
+ pos = record + keyseg->start;
+ ret_key->data= key;
+
+ dlen = _ma_calc_blob_length(keyseg->bit_start, pos);
+ memcpy_fixed(&dptr, pos + keyseg->bit_start, sizeof(char*));
+ if (!dptr)
+ {
+ my_errno= HA_ERR_NULL_IN_SPATIAL;
+ DBUG_RETURN(0);
+ }
+
+ sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr); /* SRID */
+
+ for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++)
+ {
+ uint length = keyseg->length, start= keyseg->start;
+ double val;
+
+ DBUG_ASSERT(length == 8);
+ DBUG_ASSERT(!(start % 8));
+ DBUG_ASSERT(start < sizeof(mbr));
+ DBUG_ASSERT(keyseg->type == HA_KEYTYPE_DOUBLE);
+
+ val= mbr[start / sizeof (double)];
+#ifdef HAVE_ISNAN
+ if (isnan(val))
+ {
+ bzero(key, length);
+ key+= length;
+ len+= length;
+ continue;
+ }
+#endif
+
+ if (keyseg->flag & HA_SWAP_KEY)
+ {
+ mi_float8store(key, val);
+ }
+ else
+ {
+ float8store((uchar *)key, val);
+ }
+ key += length;
+ len+= length;
+ }
+ _ma_dpointer(info->s, key, filepos);
+ ret_key->keyinfo= keyinfo;
+ ret_key->data_length= len;
+ ret_key->ref_length= info->s->rec_reflength;
+ ret_key->flag= 0;
+ if (_ma_have_versioning(info) && trid)
+ {
+ ret_key->ref_length+= transid_store_packed(info,
+ key + ret_key->ref_length,
+ trid);
+ }
+ DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, ret_key););
+ DBUG_RETURN(ret_key);
+}
+
+
+/*
+ Calculate minimal bounding rectangle (mbr) of the spatial object
+ stored in "well-known binary representation" (wkb) format.
+*/
+
+static int sp_mbr_from_wkb(uchar *wkb, uint size, uint n_dims, double *mbr)
+{
+ uint i;
+
+ for (i=0; i < n_dims; ++i)
+ {
+ mbr[i * 2] = DBL_MAX;
+ mbr[i * 2 + 1] = -DBL_MAX;
+ }
+
+ return sp_get_geometry_mbr(&wkb, wkb + size, n_dims, mbr, 1);
+}
+
+/*
+ Add one point stored in wkb to mbr
+*/
+
+static int sp_add_point_to_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order __attribute__((unused)),
+ double *mbr)
+{
+ double ord;
+ double *mbr_end= mbr + n_dims * 2;
+
+ while (mbr < mbr_end)
+ {
+ if ((*wkb) > end - 8)
+ return -1;
+ float8get(ord, (const uchar*) *wkb);
+ (*wkb)+= 8;
+ if (ord < *mbr)
+ *mbr= ord;
+ mbr++;
+ if (ord > *mbr)
+ *mbr= ord;
+ mbr++;
+ }
+ return 0;
+}
+
+
+static int sp_get_point_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order, double *mbr)
+{
+ return sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr);
+}
+
+
+static int sp_get_linestring_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order, double *mbr)
+{
+ uint n_points;
+
+ n_points = uint4korr(*wkb);
+ (*wkb) += 4;
+ for (; n_points > 0; --n_points)
+ {
+ /* Add next point to mbr */
+ if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
+ return -1;
+ }
+ return 0;
+}
+
+
+static int sp_get_polygon_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ uchar byte_order, double *mbr)
+{
+ uint n_linear_rings;
+ uint n_points;
+
+ n_linear_rings = uint4korr((*wkb));
+ (*wkb) += 4;
+
+ for (; n_linear_rings > 0; --n_linear_rings)
+ {
+ n_points = uint4korr((*wkb));
+ (*wkb) += 4;
+ for (; n_points > 0; --n_points)
+ {
+ /* Add next point to mbr */
+ if (sp_add_point_to_mbr(wkb, end, n_dims, byte_order, mbr))
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int sp_get_geometry_mbr(uchar *(*wkb), uchar *end, uint n_dims,
+ double *mbr, int top)
+{
+ int res;
+ uchar byte_order;
+ uint wkb_type;
+
+ byte_order = *(*wkb);
+ ++(*wkb);
+
+ wkb_type = uint4korr((*wkb));
+ (*wkb) += 4;
+
+ switch ((enum wkbType) wkb_type)
+ {
+ case wkbPoint:
+ res = sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr);
+ break;
+ case wkbLineString:
+ res = sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr);
+ break;
+ case wkbPolygon:
+ res = sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr);
+ break;
+ case wkbMultiPoint:
+ {
+ uint n_items;
+ n_items = uint4korr((*wkb));
+ (*wkb) += 4;
+ for (; n_items > 0; --n_items)
+ {
+ byte_order = *(*wkb);
+ ++(*wkb);
+ (*wkb) += 4;
+ if (sp_get_point_mbr(wkb, end, n_dims, byte_order, mbr))
+ return -1;
+ }
+ res = 0;
+ break;
+ }
+ case wkbMultiLineString:
+ {
+ uint n_items;
+ n_items = uint4korr((*wkb));
+ (*wkb) += 4;
+ for (; n_items > 0; --n_items)
+ {
+ byte_order = *(*wkb);
+ ++(*wkb);
+ (*wkb) += 4;
+ if (sp_get_linestring_mbr(wkb, end, n_dims, byte_order, mbr))
+ return -1;
+ }
+ res = 0;
+ break;
+ }
+ case wkbMultiPolygon:
+ {
+ uint n_items;
+ n_items = uint4korr((*wkb));
+ (*wkb) += 4;
+ for (; n_items > 0; --n_items)
+ {
+ byte_order = *(*wkb);
+ ++(*wkb);
+ (*wkb) += 4;
+ if (sp_get_polygon_mbr(wkb, end, n_dims, byte_order, mbr))
+ return -1;
+ }
+ res = 0;
+ break;
+ }
+ case wkbGeometryCollection:
+ {
+ uint n_items;
+
+ if (!top)
+ return -1;
+
+ n_items = uint4korr((*wkb));
+ (*wkb) += 4;
+ for (; n_items > 0; --n_items)
+ {
+ if (sp_get_geometry_mbr(wkb, end, n_dims, mbr, 0))
+ return -1;
+ }
+ res = 0;
+ break;
+ }
+ default:
+ res = -1;
+ }
+ return res;
+}
+
+#endif /*HAVE_SPATIAL*/
diff --git a/storage/maria/ma_sp_test.c b/storage/maria/ma_sp_test.c
new file mode 100644
index 00000000000..b8c00753acb
--- /dev/null
+++ b/storage/maria/ma_sp_test.c
@@ -0,0 +1,568 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Testing of the basic functions of a MARIA spatial table */
+/* Written by Alex Barkov, who has a shared copyright to this code */
+
+#include "maria.h"
+
+#ifdef HAVE_SPATIAL
+#include "ma_sp_defs.h"
+
+#define MAX_REC_LENGTH 1024
+#define KEYALG HA_KEY_ALG_RTREE
+
+static void create_linestring(uchar *record,uint rownr);
+static void print_record(uchar * record,my_off_t offs,const char * tail);
+
+static void create_key(uchar *key,uint rownr);
+static void print_key(const uchar *key,const char * tail);
+
+static int run_test(const char *filename);
+static int read_with_pos(MARIA_HA * file, int silent);
+
+static int maria_rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points,
+ uchar *wkb);
+static void maria_rtree_PrintWKB(uchar *wkb, uint n_dims);
+
+static char blob_key[MAX_REC_LENGTH];
+
+
+int main(int argc __attribute__((unused)),char *argv[])
+{
+ MY_INIT(argv[0]);
+ maria_init();
+ exit(run_test("sp_test"));
+}
+
+
+int run_test(const char *filename)
+{
+ MARIA_HA *file;
+ MARIA_UNIQUEDEF uniquedef;
+ MARIA_CREATE_INFO create_info;
+ MARIA_COLUMNDEF recinfo[20];
+ MARIA_KEYDEF keyinfo[20];
+ HA_KEYSEG keyseg[20];
+ key_range min_range, max_range;
+ int silent=0;
+ int create_flag=0;
+ int null_fields=0;
+ int nrecords=30;
+ int uniques=0;
+ int i;
+ int error;
+ int row_count=0;
+ uchar record[MAX_REC_LENGTH];
+ uchar key[MAX_REC_LENGTH];
+ uchar read_record[MAX_REC_LENGTH];
+ int upd=10;
+ ha_rows hrows;
+
+ /* Define a column for NULLs and DEL markers*/
+
+ recinfo[0].type=FIELD_NORMAL;
+ recinfo[0].length=1; /* For NULL bits */
+
+
+ /* Define spatial column */
+
+ recinfo[1].type=FIELD_BLOB;
+ recinfo[1].length=4 + portable_sizeof_char_ptr;
+
+
+
+ /* Define a key with 1 spatial segment */
+
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].flag=HA_SPATIAL;
+ keyinfo[0].key_alg=KEYALG;
+
+ keyinfo[0].seg[0].type= HA_KEYTYPE_BINARY;
+ keyinfo[0].seg[0].flag=0;
+ keyinfo[0].seg[0].start= 1;
+ keyinfo[0].seg[0].length=1; /* Spatial ignores it anyway */
+ keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].seg[0].language=default_charset_info->number;
+ keyinfo[0].seg[0].bit_start=4; /* Long BLOB */
+
+
+ if (!silent)
+ printf("- Creating isam-file\n");
+
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.max_rows=10000000;
+
+ if (maria_create(filename,
+ DYNAMIC_RECORD,
+ 1, /* keys */
+ keyinfo,
+ 2, /* columns */
+ recinfo,uniques,&uniquedef,&create_info,create_flag))
+ goto err;
+
+ if (!silent)
+ printf("- Open isam-file\n");
+
+ if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ for (i=0; i<nrecords; i++ )
+ {
+ create_linestring(record,i);
+ error=maria_write(file,record);
+ print_record(record,maria_position(file),"\n");
+ if (!error)
+ {
+ row_count++;
+ }
+ else
+ {
+ printf("maria_write: %d\n", error);
+ goto err;
+ }
+ }
+
+ if ((error=read_with_pos(file,silent)))
+ goto err;
+
+ if (!silent)
+ printf("- Deleting rows with position\n");
+ for (i=0; i < nrecords/4; i++)
+ {
+ my_errno=0;
+ bzero((char*) read_record,MAX_REC_LENGTH);
+ error=maria_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR);
+ if (error)
+ {
+ printf("pos: %2d maria_rrnd: %3d errno: %3d\n",i,error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file),"\n");
+ error=maria_delete(file,read_record);
+ if (error)
+ {
+ printf("pos: %2d maria_delete: %3d errno: %3d\n",i,error,my_errno);
+ goto err;
+ }
+ }
+
+ if (!silent)
+ printf("- Updating rows with position\n");
+ for (i=0; i < nrecords/2 ; i++)
+ {
+ my_errno=0;
+ bzero((char*) read_record,MAX_REC_LENGTH);
+ error=maria_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR);
+ if (error)
+ {
+ if (error==HA_ERR_RECORD_DELETED)
+ continue;
+ printf("pos: %2d maria_rrnd: %3d errno: %3d\n",i,error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file),"");
+ create_linestring(record,i+nrecords*upd);
+ printf("\t-> ");
+ print_record(record,maria_position(file),"\n");
+ error=maria_update(file,read_record,record);
+ if (error)
+ {
+ printf("pos: %2d maria_update: %3d errno: %3d\n",i,error,my_errno);
+ goto err;
+ }
+ }
+
+ if ((error=read_with_pos(file,silent)))
+ goto err;
+
+ if (!silent)
+ printf("- Test maria_rkey then a sequence of maria_rnext_same\n");
+
+ create_key(key, nrecords*4/5);
+ print_key(key," search for INTERSECT\n");
+
+ if ((error=maria_rkey(file,read_record,0,key,0,HA_READ_MBR_INTERSECT)))
+ {
+ printf("maria_rkey: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file)," maria_rkey\n");
+ row_count=1;
+
+ for (;;)
+ {
+ if ((error=maria_rnext_same(file,read_record)))
+ {
+ if (error==HA_ERR_END_OF_FILE)
+ break;
+ printf("maria_next: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file)," maria_rnext_same\n");
+ row_count++;
+ }
+ printf(" %d rows\n",row_count);
+
+ if (!silent)
+ printf("- Test maria_rfirst then a sequence of maria_rnext\n");
+
+ error=maria_rfirst(file,read_record,0);
+ if (error)
+ {
+ printf("maria_rfirst: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ row_count=1;
+ print_record(read_record,maria_position(file)," maria_frirst\n");
+
+ for(i=0;i<nrecords;i++) {
+ if ((error=maria_rnext(file,read_record,0)))
+ {
+ if (error==HA_ERR_END_OF_FILE)
+ break;
+ printf("maria_next: %3d errno: %3d\n",error,my_errno);
+ goto err;
+ }
+ print_record(read_record,maria_position(file)," maria_rnext\n");
+ row_count++;
+ }
+ printf(" %d rows\n",row_count);
+
+ if (!silent)
+ printf("- Test maria_records_in_range()\n");
+
+ create_key(key, nrecords*upd);
+ print_key(key," INTERSECT\n");
+ min_range.key= key;
+ min_range.length= 1000; /* Big enough */
+ min_range.flag= HA_READ_MBR_INTERSECT;
+ max_range.key= record+1;
+ max_range.length= 1000; /* Big enough */
+ max_range.flag= HA_READ_KEY_EXACT;
+ hrows= maria_records_in_range(file,0, &min_range, &max_range);
+ printf(" %ld rows\n", (long) hrows);
+
+ if (maria_close(file)) goto err;
+ maria_end();
+ my_end(MY_CHECK_ERROR);
+
+ return 0;
+
+err:
+ printf("got error: %3d when using maria-database\n",my_errno);
+ maria_end();
+ return 1; /* skip warning */
+}
+
+
+static int read_with_pos (MARIA_HA * file,int silent)
+{
+ int error;
+ int i;
+ uchar read_record[MAX_REC_LENGTH];
+ int rows=0;
+
+ if (!silent)
+ printf("- Reading rows with position\n");
+ for (i=0;;i++)
+ {
+ my_errno=0;
+ bzero((char*) read_record,MAX_REC_LENGTH);
+ error=maria_rrnd(file,read_record,i == 0 ? 0L : HA_OFFSET_ERROR);
+ if (error)
+ {
+ if (error==HA_ERR_END_OF_FILE)
+ break;
+ if (error==HA_ERR_RECORD_DELETED)
+ continue;
+ printf("pos: %2d maria_rrnd: %3d errno: %3d\n",i,error,my_errno);
+ return error;
+ }
+ rows++;
+ print_record(read_record,maria_position(file),"\n");
+ }
+ printf(" %d rows\n",rows);
+ return 0;
+}
+
+
+#ifdef NOT_USED
+static void bprint_record(uchar * record,
+ my_off_t offs __attribute__((unused)),
+ const char * tail)
+{
+ int i;
+ char * pos;
+ i=(unsigned char)record[0];
+ printf("%02X ",i);
+
+ for( pos=record+1, i=0; i<32; i++,pos++)
+ {
+ int b=(unsigned char)*pos;
+ printf("%02X",b);
+ }
+ printf("%s",tail);
+}
+#endif
+
+
+static void print_record(uchar * record, my_off_t offs,const char * tail)
+{
+ uchar *pos;
+ char *ptr;
+ uint len;
+
+ printf(" rec=(%d)",(unsigned char)record[0]);
+ pos=record+1;
+ len=sint4korr(pos);
+ pos+=4;
+ printf(" len=%d ",len);
+ memcpy_fixed(&ptr,pos,sizeof(char*));
+ if (ptr)
+ maria_rtree_PrintWKB((uchar*) ptr,SPDIMS);
+ else
+ printf("<NULL> ");
+ printf(" offs=%ld ",(long int)offs);
+ printf("%s",tail);
+}
+
+
+#ifdef NOT_USED
+static void create_point(uchar *record,uint rownr)
+{
+ uint tmp;
+ char *ptr;
+ char *pos=record;
+ double x[200];
+ int i;
+
+ for(i=0;i<SPDIMS;i++)
+ x[i]=rownr;
+
+ bzero((char*) record,MAX_REC_LENGTH);
+ *pos=0x01; /* DEL marker */
+ pos++;
+
+ memset(blob_key,0,sizeof(blob_key));
+ tmp=maria_rtree_CreatePointWKB(x,SPDIMS,blob_key);
+
+ int4store(pos,tmp);
+ pos+=4;
+
+ ptr=blob_key;
+ memcpy_fixed(pos,&ptr,sizeof(char*));
+}
+#endif
+
+
+static void create_linestring(uchar *record,uint rownr)
+{
+ uint tmp;
+ char *ptr;
+ uchar *pos= record;
+ double x[200];
+ int i,j;
+ int npoints=2;
+
+ for(j=0;j<npoints;j++)
+ for(i=0;i<SPDIMS;i++)
+ x[i+j*SPDIMS]=rownr*j;
+
+ bzero((char*) record,MAX_REC_LENGTH);
+ *pos=0x01; /* DEL marker */
+ pos++;
+
+ memset(blob_key,0,sizeof(blob_key));
+ tmp=maria_rtree_CreateLineStringWKB(x,SPDIMS,npoints, (uchar*) blob_key);
+
+ int4store(pos,tmp);
+ pos+=4;
+
+ ptr=blob_key;
+ memcpy_fixed(pos,&ptr,sizeof(char*));
+}
+
+
+static void create_key(uchar *key,uint rownr)
+{
+ double c=rownr;
+ uchar *pos;
+ uint i;
+
+ bzero(key,MAX_REC_LENGTH);
+ for ( pos=key, i=0; i<2*SPDIMS; i++)
+ {
+ float8store(pos,c);
+ pos+=sizeof(c);
+ }
+}
+
+static void print_key(const uchar *key,const char * tail)
+{
+ double c;
+ uint i;
+
+ printf(" key=");
+ for (i=0; i<2*SPDIMS; i++)
+ {
+ float8get(c,key);
+ key+=sizeof(c);
+ printf("%.14g ",c);
+ }
+ printf("%s",tail);
+}
+
+
+#ifdef NOT_USED
+
+static int maria_rtree_CreatePointWKB(double *ords, uint n_dims, uchar *wkb)
+{
+ uint i;
+
+ *wkb = wkbXDR;
+ ++wkb;
+ int4store(wkb, wkbPoint);
+ wkb += 4;
+
+ for (i=0; i < n_dims; ++i)
+ {
+ float8store(wkb, ords[i]);
+ wkb += 8;
+ }
+ return 5 + n_dims * 8;
+}
+#endif
+
+
+static int maria_rtree_CreateLineStringWKB(double *ords, uint n_dims, uint n_points,
+ uchar *wkb)
+{
+ uint i;
+ uint n_ords = n_dims * n_points;
+
+ *wkb = wkbXDR;
+ ++wkb;
+ int4store(wkb, wkbLineString);
+ wkb += 4;
+ int4store(wkb, n_points);
+ wkb += 4;
+ for (i=0; i < n_ords; ++i)
+ {
+ float8store(wkb, ords[i]);
+ wkb += 8;
+ }
+ return 9 + n_points * n_dims * 8;
+}
+
+
+static void maria_rtree_PrintWKB(uchar *wkb, uint n_dims)
+{
+ uint wkb_type;
+
+ ++wkb;
+ wkb_type = uint4korr(wkb);
+ wkb += 4;
+
+ switch ((enum wkbType)wkb_type)
+ {
+ case wkbPoint:
+ {
+ uint i;
+ double ord;
+
+ printf("POINT(");
+ for (i=0; i < n_dims; ++i)
+ {
+ float8get(ord, wkb);
+ wkb += 8;
+ printf("%.14g", ord);
+ if (i < n_dims - 1)
+ printf(" ");
+ else
+ printf(")");
+ }
+ break;
+ }
+ case wkbLineString:
+ {
+ uint p, i;
+ uint n_points;
+ double ord;
+
+ printf("LineString(");
+ n_points = uint4korr(wkb);
+ wkb += 4;
+ for (p=0; p < n_points; ++p)
+ {
+ for (i=0; i < n_dims; ++i)
+ {
+ float8get(ord, wkb);
+ wkb += 8;
+ printf("%.14g", ord);
+ if (i < n_dims - 1)
+ printf(" ");
+ }
+ if (p < n_points - 1)
+ printf(", ");
+ else
+ printf(")");
+ }
+ break;
+ }
+ case wkbPolygon:
+ {
+ printf("POLYGON(...)");
+ break;
+ }
+ case wkbMultiPoint:
+ {
+ printf("MULTIPOINT(...)");
+ break;
+ }
+ case wkbMultiLineString:
+ {
+ printf("MULTILINESTRING(...)");
+ break;
+ }
+ case wkbMultiPolygon:
+ {
+ printf("MULTIPOLYGON(...)");
+ break;
+ }
+ case wkbGeometryCollection:
+ {
+ printf("GEOMETRYCOLLECTION(...)");
+ break;
+ }
+ default:
+ {
+ printf("UNKNOWN GEOMETRY TYPE");
+ break;
+ }
+ }
+}
+
+#else
+int main(int argc __attribute__((unused)),char *argv[] __attribute__((unused)))
+{
+ exit(0);
+}
+#endif /*HAVE_SPATIAL*/
diff --git a/storage/maria/ma_state.c b/storage/maria/ma_state.c
new file mode 100644
index 00000000000..a7e3b49e284
--- /dev/null
+++ b/storage/maria/ma_state.c
@@ -0,0 +1,720 @@
+/* Copyright (C) 2008 Sun AB and Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Functions to maintain live statistics for Maria transactional tables
+ and versioning for not transactional tables
+
+ See WL#3138; Maria - fast "SELECT COUNT(*) FROM t;" and "CHECKSUM TABLE t"
+ for details about live number of rows and live checksums
+
+ TODO
+ - Allocate MA_USED_TABLES and MA_HISTORY_STATE from a global pool (to
+ avoid calls to malloc()
+ - In trnamn_end_trans_hook(), don't call _ma_remove_not_visible_states()
+ every time. One could for example call it if there has been more than
+ 10 ended transactions since last time it was called.
+*/
+
+#include "maria_def.h"
+#include "trnman.h"
+#include "ma_blockrec.h"
+
+/**
+ @brief Setup initial start-of-transaction state for a table
+
+ @fn _ma_setup_live_state
+ @param info Maria handler
+
+ @notes
+ This function ensures that trn->used_tables contains a list of
+ start and live states for tables that are part of the transaction
+ and that info->state points to the current live state for the table.
+
+ @TODO
+ Change trn->table_list to a hash and share->state_history to a binary tree
+
+ @return
+ @retval 0 ok
+ @retval 1 error (out of memory)
+*/
+
+my_bool _ma_setup_live_state(MARIA_HA *info)
+{
+ TRN *trn= info->trn;
+ MARIA_SHARE *share= info->s;
+ MARIA_USED_TABLES *tables;
+ MARIA_STATE_HISTORY *history;
+ DBUG_ENTER("_ma_setup_live_state");
+
+ for (tables= (MARIA_USED_TABLES*) info->trn->used_tables;
+ tables;
+ tables= tables->next)
+ {
+ if (tables->share == share)
+ {
+ /* Table is already used by transaction */
+ goto end;
+ }
+ }
+ /* Table was not used before, create new table state entry */
+ if (!(tables= (MARIA_USED_TABLES*) my_malloc(sizeof(*tables),
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(1);
+ tables->next= trn->used_tables;
+ trn->used_tables= tables;
+ tables->share= share;
+
+ pthread_mutex_lock(&share->intern_lock);
+ share->in_trans++;
+ DBUG_PRINT("info", ("share: 0x%lx in_trans: %d",
+ (ulong) share, share->in_trans));
+
+ history= share->state_history;
+
+ /*
+ We must keep share locked to ensure that we don't access a history
+ link that is deleted by concurrently running checkpoint.
+
+ It's enough to compare trids here (instead of calling
+ tranman_can_read_from) as history->trid is a commit_trid
+ */
+ while (trn->trid <= history->trid)
+ history= history->next;
+ pthread_mutex_unlock(&share->intern_lock);
+ /* The current item can't be deleted as it's the first one visible for us */
+ tables->state_start= tables->state_current= history->state;
+ tables->state_current.changed= tables->state_current.no_transid= 0;
+
+ DBUG_PRINT("info", ("records: %ld", (ulong) tables->state_start.records));
+
+end:
+ info->state_start= &tables->state_start;
+ info->state= &tables->state_current;
+
+ /*
+ Mark in transaction state if we are not using transid (versioning)
+ on rows. If not, then we will in _ma_trnman_end_trans_hook()
+ ensure that the state is visible for all at end of transaction
+ */
+ tables->state_current.no_transid|= !(info->row_flag & ROW_FLAG_TRANSID);
+
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Remove states that are not visible by anyone
+
+ @fn _ma_remove_not_visible_states()
+ @param org_history List to history
+ @param all 1 if we should delete the first state if it's
+ visible for all. For the moment this is only used
+ on close() of table.
+ @param trnman_is_locked Set to 1 if we have already a lock on trnman.
+
+ @notes
+ The assumption is that items in the history list is ordered by
+ commit_trid.
+
+ A state is not visible anymore if there is no new transaction
+ that has been started between the commit_trid's of two states
+
+ As long as some states exists, we keep the newest = (last commit)
+ state as first state in the history. This is to allow us to just move
+ the history from the global list to the share when we open the table.
+
+ Note that if 'all' is set trnman_is_locked must be 0, becasue
+ trnman_get_min_trid() will take a lock on trnman.
+
+ @return
+ @retval Pointer to new history list
+*/
+
+MARIA_STATE_HISTORY
+*_ma_remove_not_visible_states(MARIA_STATE_HISTORY *org_history,
+ my_bool all,
+ my_bool trnman_is_locked)
+{
+ TrID last_trid;
+ MARIA_STATE_HISTORY *history, **parent, *next;
+ DBUG_ENTER("_ma_remove_not_visible_states");
+
+ if (!org_history)
+ DBUG_RETURN(0); /* Not versioned table */
+
+ last_trid= org_history->trid;
+ parent= &org_history->next;
+ for (history= org_history->next; history; history= next)
+ {
+ next= history->next;
+ if (!trnman_exists_active_transactions(history->trid, last_trid,
+ trnman_is_locked))
+ {
+ DBUG_PRINT("info", ("removing history->trid: %lu next: %lu",
+ (ulong) history->trid, (ulong) last_trid));
+ my_free(history, MYF(0));
+ continue;
+ }
+ *parent= history;
+ parent= &history->next;
+ last_trid= history->trid;
+ }
+ *parent= 0;
+
+ if (all && parent == &org_history->next)
+ {
+ /* There is only one state left. Delete this if it's visible for all */
+ if (last_trid < trnman_get_min_trid())
+ {
+ my_free(org_history, MYF(0));
+ org_history= 0;
+ }
+ }
+ DBUG_RETURN(org_history);
+}
+
+
+/**
+ @brief Remove not used state history
+
+ @param share Maria table information
+ @param all 1 if we should delete the first state if it's
+ visible for all. For the moment this is only used
+ on close() of table.
+
+ @notes
+ share and trnman are not locked.
+
+ We must first lock trnman and then share->intern_lock. This is becasue
+ _ma_trnman_end_trans_hook() has a lock on trnman and then
+ takes share->intern_lock.
+*/
+
+void _ma_remove_not_visible_states_with_lock(MARIA_SHARE *share,
+ my_bool all)
+{
+ my_bool is_lock_trman;
+ if ((is_lock_trman= trman_is_inited()))
+ trnman_lock();
+
+ pthread_mutex_lock(&share->intern_lock);
+ share->state_history= _ma_remove_not_visible_states(share->state_history,
+ all, 1);
+ pthread_mutex_unlock(&share->intern_lock);
+ if (is_lock_trman)
+ trnman_unlock();
+}
+
+
+/*
+ Free state history information from share->history and reset information
+ to current state.
+
+ @notes
+ Used after repair as then all rows are visible for everyone
+*/
+
+void _ma_reset_state(MARIA_HA *info)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_STATE_HISTORY *history= share->state_history;
+
+ if (history)
+ {
+ MARIA_STATE_HISTORY *next;
+
+ /* Set the current history to current state */
+ share->state_history->state= share->state.state;
+ /* Set current table handler to point to new history state */
+ info->state= info->state_start= &share->state_history->state;
+ for (history= history->next ; history ; history= next)
+ {
+ next= history->next;
+ my_free(history, MYF(0));
+ }
+ share->state_history->next= 0;
+ share->state_history->trid= 0; /* Visibile for all */
+ }
+}
+
+
+/****************************************************************************
+ The following functions are called by thr_lock() in threaded applications
+ for not transactional tables
+****************************************************************************/
+
+/*
+ Create a copy of the current status for the table
+
+ SYNOPSIS
+ _ma_get_status()
+ param Pointer to Myisam handler
+ concurrent_insert Set to 1 if we are going to do concurrent inserts
+ (THR_WRITE_CONCURRENT_INSERT was used)
+*/
+
+void _ma_get_status(void* param, my_bool concurrent_insert)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ DBUG_ENTER("_ma_get_status");
+ DBUG_PRINT("info",("key_file: %ld data_file: %ld concurrent_insert: %d",
+ (long) info->s->state.state.key_file_length,
+ (long) info->s->state.state.data_file_length,
+ concurrent_insert));
+#ifndef DBUG_OFF
+ if (info->state->key_file_length > info->s->state.state.key_file_length ||
+ info->state->data_file_length > info->s->state.state.data_file_length)
+ DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
+ (long) info->state->key_file_length,
+ (long) info->state->data_file_length));
+#endif
+ info->state_save= info->s->state.state;
+ info->state= &info->state_save;
+ info->state->changed= 0;
+ info->append_insert_at_end= concurrent_insert;
+ DBUG_VOID_RETURN;
+}
+
+
+void _ma_update_status(void* param)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ /*
+ Because someone may have closed the table we point at, we only
+ update the state if its our own state. This isn't a problem as
+ we are always pointing at our own lock or at a read lock.
+ (This is enforced by thr_multi_lock.c)
+ */
+ if (info->state == &info->state_save)
+ {
+ MARIA_SHARE *share= info->s;
+#ifndef DBUG_OFF
+ DBUG_PRINT("info",("updating status: key_file: %ld data_file: %ld",
+ (long) info->state->key_file_length,
+ (long) info->state->data_file_length));
+ if (info->state->key_file_length < share->state.state.key_file_length ||
+ info->state->data_file_length < share->state.state.data_file_length)
+ DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
+ (long) share->state.state.key_file_length,
+ (long) share->state.state.data_file_length));
+#endif
+ /*
+ we are going to modify the state without lock's log, this would break
+ recovery if done with a transactional table.
+ */
+ DBUG_ASSERT(!info->s->base.born_transactional);
+ share->state.state= *info->state;
+ info->state= &share->state.state;
+ }
+ info->append_insert_at_end= 0;
+}
+
+
+void _ma_restore_status(void *param)
+{
+ MARIA_HA *info= (MARIA_HA*) param;
+ info->state= &info->s->state.state;
+ info->append_insert_at_end= 0;
+}
+
+
+void _ma_copy_status(void* to, void *from)
+{
+ ((MARIA_HA*) to)->state= &((MARIA_HA*) from)->state_save;
+}
+
+
+void _ma_reset_update_flag(void *param,
+ my_bool concurrent_insert __attribute__((unused)))
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ info->state->changed= 0;
+}
+
+
+/**
+ @brief Check if should allow concurrent inserts
+
+ @implementation
+ Allow concurrent inserts if we don't have a hole in the table or
+ if there is no active write lock and there is active read locks and
+ maria_concurrent_insert == 2. In this last case the new
+ row('s) are inserted at end of file instead of filling up the hole.
+
+ The last case is to allow one to inserts into a heavily read-used table
+ even if there is holes.
+
+ @notes
+ If there is a an rtree indexes in the table, concurrent inserts are
+ disabled in maria_open()
+
+ @return
+ @retval 0 ok to use concurrent inserts
+ @retval 1 not ok
+*/
+
+my_bool _ma_check_status(void *param)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ /*
+ The test for w_locks == 1 is here because this thread has already done an
+ external lock (in other words: w_locks == 1 means no other threads has
+ a write lock)
+ */
+ DBUG_PRINT("info",("dellink: %ld r_locks: %u w_locks: %u",
+ (long) info->s->state.dellink, (uint) info->s->r_locks,
+ (uint) info->s->w_locks));
+ return (my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR ||
+ (maria_concurrent_insert == 2 && info->s->r_locks &&
+ info->s->w_locks == 1));
+}
+
+
+/**
+ @brief write hook at end of trans to store status for all used table
+
+ @Notes
+ This function must be called under trnman_lock in trnman_end_trn()
+ because of the following reasons:
+ - After trnman_end_trn() is called, the current transaction will be
+ regarded as committed and all used tables state_history will be
+ visible to other transactions. To do this, we loop over all used
+ tables and create/update a history entries that contains the correct
+ state_history for them.
+*/
+
+my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
+ my_bool active_transactions)
+{
+ my_bool error= 0;
+ MARIA_USED_TABLES *tables, *next;
+ DBUG_ENTER("_ma_trnman_end_trans_hook");
+
+ for (tables= (MARIA_USED_TABLES*) trn->used_tables;
+ tables;
+ tables= next)
+ {
+ MARIA_SHARE *share= tables->share;
+ next= tables->next;
+ if (commit)
+ {
+ MARIA_STATE_HISTORY *history;
+
+ pthread_mutex_lock(&share->intern_lock);
+
+ /* We only have to update history state if something changed */
+ if (tables->state_current.changed)
+ {
+ if (tables->state_current.no_transid)
+ {
+ /*
+ The change was done without using transid on rows (like in
+ bulk insert). In this case this thread is the only one
+ that is using the table and all rows will be visble
+ for all transactions.
+ */
+ _ma_reset_history(share);
+ }
+ else
+ {
+ if (active_transactions && share->now_transactional &&
+ trnman_exists_active_transactions(share->state_history->trid,
+ trn->commit_trid, 1))
+ {
+ /*
+ There exist transactions that are still using the current
+ share->state_history. Create a new history item for this
+ commit and add it first in the state_history list. This
+ ensures that all history items are stored in the list in
+ decresing trid order.
+ */
+ if (!(history= my_malloc(sizeof(*history), MYF(MY_WME))))
+ {
+ /* purecov: begin inspected */
+ error= 1;
+ pthread_mutex_unlock(&share->intern_lock);
+ my_free(tables, MYF(0));
+ continue;
+ /* purecov: end */
+ }
+ history->state= share->state_history->state;
+ history->next= share->state_history;
+ share->state_history= history;
+ }
+ else
+ {
+ /* Previous history can't be seen by anyone, reuse old memory */
+ history= share->state_history;
+ DBUG_PRINT("info", ("removing history->trid: %lu new: %lu",
+ (ulong) history->trid,
+ (ulong) trn->commit_trid));
+ }
+
+ history->state.records+= (tables->state_current.records -
+ tables->state_start.records);
+ history->state.checksum+= (tables->state_current.checksum -
+ tables->state_start.checksum);
+ history->trid= trn->commit_trid;
+
+ if (history->next)
+ {
+ /* Remove not visible states */
+ share->state_history= _ma_remove_not_visible_states(history, 0, 1);
+ }
+ DBUG_PRINT("info", ("share: 0x%lx in_trans: %d",
+ (ulong) share, share->in_trans));
+ }
+ }
+ share->in_trans--;
+ pthread_mutex_unlock(&share->intern_lock);
+ }
+ else
+ {
+#ifndef DBUG_OFF
+ /*
+ We need to keep share->in_trans correct in the debug library
+ because of the assert in maria_close()
+ */
+ pthread_mutex_lock(&share->intern_lock);
+ share->in_trans--;
+ pthread_mutex_unlock(&share->intern_lock);
+#endif
+ }
+ my_free(tables, MYF(0));
+ }
+ trn->used_tables= 0;
+ DBUG_RETURN(error);
+}
+
+
+/**
+ Remove table from trnman_list
+
+ @notes
+ This is used when we unlock a table from a group of locked tables
+ just before doing a rename or drop table.
+
+ share->internal_lock must be locked when function is called
+*/
+
+void _ma_remove_table_from_trnman(MARIA_SHARE *share, TRN *trn)
+{
+ MARIA_USED_TABLES *tables, **prev;
+ DBUG_ENTER("_ma_remove_table_from_trnman");
+ DBUG_PRINT("enter", ("share: 0x%lx in_trans: %d",
+ (ulong) share, share->in_trans));
+
+ safe_mutex_assert_owner(&share->intern_lock);
+
+ for (prev= (MARIA_USED_TABLES**) &trn->used_tables, tables= *prev;
+ tables;
+ tables= *prev)
+ {
+ if (tables->share == share)
+ {
+ *prev= tables->next;
+ share->in_trans--;
+ DBUG_PRINT("info", ("in_trans: %d", share->in_trans));
+ my_free(tables, MYF(0));
+ break;
+ }
+ prev= &tables->next;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+
+/****************************************************************************
+ The following functions are called by thr_lock() in threaded applications
+ for transactional tables.
+****************************************************************************/
+
+/*
+ Create a copy of the current status for the table
+
+ SYNOPSIS
+ _ma_get_status()
+ param Pointer to Myisam handler
+ concurrent_insert Set to 1 if we are going to do concurrent inserts
+ (THR_WRITE_CONCURRENT_INSERT was used)
+*/
+
+void _ma_block_get_status(void* param, my_bool concurrent_insert)
+{
+ MARIA_HA *info=(MARIA_HA*) param;
+ DBUG_ENTER("_ma_block_get_status");
+ DBUG_PRINT("info", ("concurrent_insert %d", concurrent_insert));
+ info->row_base_length= info->s->base_length;
+ info->row_flag= info->s->base.default_row_flag;
+ if (concurrent_insert)
+ {
+ DBUG_ASSERT(info->lock.type == TL_WRITE_CONCURRENT_INSERT);
+ info->row_flag|= ROW_FLAG_TRANSID;
+ info->row_base_length+= TRANSID_SIZE;
+ }
+ else
+ {
+ DBUG_ASSERT(info->lock.type != TL_WRITE_CONCURRENT_INSERT);
+ }
+
+ if (info->s->lock_key_trees)
+ {
+ /*
+ Assume for now that this doesn't fail (It can only fail in
+ out of memory conditions)
+ TODO: Fix this by having one extra state pre-allocated
+ */
+ (void) _ma_setup_live_state(info);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void _ma_block_update_status(void *param __attribute__((unused)))
+{
+}
+
+void _ma_block_restore_status(void *param __attribute__((unused)))
+{
+}
+
+
+/**
+ Check if should allow concurrent inserts
+
+ @return
+ @retval 0 ok to use concurrent inserts
+ @retval 1 not ok
+*/
+
+my_bool _ma_block_check_status(void *param __attribute__((unused)))
+{
+ return (my_bool) 0;
+}
+
+
+/**
+ Enable/disable versioning
+*/
+
+void maria_versioning(MARIA_HA *info, my_bool versioning)
+{
+ /* For now, this is a hack */
+ if (info->s->have_versioning)
+ {
+ enum thr_lock_type save_lock_type;
+ /* Assume is a non threaded application (for now) */
+ info->s->lock_key_trees= 0;
+ /* Set up info->lock.type temporary for _ma_block_get_status() */
+ save_lock_type= info->lock.type;
+ info->lock.type= versioning ? TL_WRITE_CONCURRENT_INSERT : TL_WRITE;
+ _ma_block_get_status((void*) info, versioning);
+ info->lock.type= save_lock_type;
+ }
+}
+
+
+/**
+ Update data_file_length to new length
+
+ NOTES
+ Only used by block records
+*/
+
+void _ma_set_share_data_file_length(MARIA_SHARE *share, ulonglong new_length)
+{
+ pthread_mutex_lock(&share->intern_lock);
+ if (share->state.state.data_file_length < new_length)
+ share->state.state.data_file_length= new_length;
+ pthread_mutex_unlock(&share->intern_lock);
+}
+
+
+/**
+ Copy state information that where updated while the table was used
+ in not transactional mode
+*/
+
+void _ma_copy_nontrans_state_information(MARIA_HA *info)
+{
+ info->s->state.state.records= info->state->records;
+ info->s->state.state.checksum= info->state->checksum;
+}
+
+
+void _ma_reset_history(MARIA_SHARE *share)
+{
+ MARIA_STATE_HISTORY *history, *next;
+ DBUG_ENTER("_ma_reset_history");
+
+ share->state_history->trid= 0; /* Visibly by all */
+ share->state_history->state= share->state.state;
+ history= share->state_history->next;
+ share->state_history->next= 0;
+
+ for (; history; history= next)
+ {
+ next= history->next;
+ my_free(history, MYF(0));
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+ Virtual functions to check if row is visible
+****************************************************************************/
+
+/**
+ Row is always visible
+ This is for tables without concurrent insert
+*/
+
+my_bool _ma_row_visible_always(MARIA_HA *info __attribute__((unused)))
+{
+ return 1;
+}
+
+
+/**
+ Row visibility for non transactional tables with concurrent insert
+
+ @implementation
+ When we got our table lock, we saved the current
+ data_file_length. Concurrent inserts always go to the end of the
+ file. So we can test if the found key references a new record.
+*/
+
+my_bool _ma_row_visible_non_transactional_table(MARIA_HA *info)
+{
+ return info->cur_row.lastpos < info->state->data_file_length;
+}
+
+
+/**
+ Row visibility for transactional tables with versioning
+
+
+ @TODO
+ Add test if found key was marked deleted and it was deleted by
+ us. In that case we should return 0
+*/
+
+my_bool _ma_row_visible_transactional_table(MARIA_HA *info)
+{
+ return trnman_can_read_from(info->trn, info->cur_row.trid);
+}
diff --git a/storage/maria/ma_state.h b/storage/maria/ma_state.h
new file mode 100644
index 00000000000..f3317f0084a
--- /dev/null
+++ b/storage/maria/ma_state.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2008 Sun AB & Michael Widenius
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Struct to store tables in use by one transaction */
+
+typedef struct st_maria_status_info
+{
+ ha_rows records; /* Rows in table */
+ ha_rows del; /* Removed rows */
+ my_off_t empty; /* lost space in datafile */
+ my_off_t key_empty; /* lost space in indexfile */
+ my_off_t key_file_length;
+ my_off_t data_file_length;
+ ha_checksum checksum;
+ uint32 changed:1, /* Set if table was changed */
+ no_transid:1; /* Set if no transid was set on rows */
+} MARIA_STATUS_INFO;
+
+
+typedef struct st_used_tables {
+ struct st_used_tables *next;
+ struct st_maria_share *share;
+ MARIA_STATUS_INFO state_current;
+ MARIA_STATUS_INFO state_start;
+} MARIA_USED_TABLES;
+
+
+/* Struct to store commit state at different times */
+
+typedef struct st_state_history {
+ struct st_state_history *next;
+ TrID trid;
+ MARIA_STATUS_INFO state;
+} MARIA_STATE_HISTORY;
+
+
+/* struct to remember history for closed tables */
+
+typedef struct st_state_history_closed {
+ LSN create_rename_lsn;
+ MARIA_STATE_HISTORY *state_history;
+} MARIA_STATE_HISTORY_CLOSED;
+
+
+my_bool _ma_setup_live_state(MARIA_HA *info);
+MARIA_STATE_HISTORY *_ma_remove_not_visible_states(MARIA_STATE_HISTORY
+ *org_history,
+ my_bool all,
+ my_bool trman_is_locked);
+void _ma_reset_state(MARIA_HA *info);
+void _ma_get_status(void* param, my_bool concurrent_insert);
+void _ma_update_status(void* param);
+void _ma_restore_status(void *param);
+void _ma_copy_status(void* to, void *from);
+void _ma_reset_update_flag(void *param, my_bool concurrent_insert);
+my_bool _ma_check_status(void *param);
+void _ma_block_get_status(void* param, my_bool concurrent_insert);
+void _ma_block_update_status(void *param);
+void _ma_block_restore_status(void *param);
+my_bool _ma_block_check_status(void *param);
+void maria_versioning(MARIA_HA *info, my_bool versioning);
+void _ma_set_share_data_file_length(struct st_maria_share *share,
+ ulonglong new_length);
+void _ma_copy_nontrans_state_information(MARIA_HA *info);
+my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
+ my_bool active_transactions);
+my_bool _ma_row_visible_always(MARIA_HA *info);
+my_bool _ma_row_visible_non_transactional_table(MARIA_HA *info);
+my_bool _ma_row_visible_transactional_table(MARIA_HA *info);
+void _ma_remove_not_visible_states_with_lock(struct st_maria_share *share,
+ my_bool all);
+void _ma_remove_table_from_trnman(struct st_maria_share *share, TRN *trn);
+void _ma_reset_history(struct st_maria_share *share);
diff --git a/storage/maria/ma_static.c b/storage/maria/ma_static.c
new file mode 100644
index 00000000000..b4589469caf
--- /dev/null
+++ b/storage/maria/ma_static.c
@@ -0,0 +1,107 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/*
+ Static variables for MARIA library. All definied here for easy making of
+ a shared library
+*/
+
+#ifndef _global_h
+#include "maria_def.h"
+#include "trnman.h"
+#endif
+
+LIST *maria_open_list=0;
+uchar maria_file_magic[]=
+{ (uchar) 254, (uchar) 254, (uchar) 9, '\003', };
+uchar maria_pack_file_magic[]=
+{ (uchar) 254, (uchar) 254, (uchar) 10, '\001', };
+/* Unique number for this maria instance */
+uchar maria_uuid[MY_UUID_SIZE];
+uint maria_quick_table_bits=9;
+ulong maria_block_size= MARIA_KEY_BLOCK_LENGTH;
+my_bool maria_flush= 0, maria_single_user= 0;
+my_bool maria_delay_key_write= 0, maria_page_checksums= 1;
+my_bool maria_inited= FALSE;
+my_bool maria_in_ha_maria= FALSE; /* If used from ha_maria or not */
+pthread_mutex_t THR_LOCK_maria;
+#if defined(THREAD) && !defined(DONT_USE_RW_LOCKS)
+ulong maria_concurrent_insert= 2;
+#else
+ulong maria_concurrent_insert= 0;
+#endif
+my_off_t maria_max_temp_length= MAX_FILE_SIZE;
+ulong maria_bulk_insert_tree_size=8192*1024;
+ulong maria_data_pointer_size= 4;
+
+PAGECACHE maria_pagecache_var;
+PAGECACHE *maria_pagecache= &maria_pagecache_var;
+
+PAGECACHE maria_log_pagecache_var;
+PAGECACHE *maria_log_pagecache= &maria_log_pagecache_var;
+MY_TMPDIR *maria_tmpdir; /* Tempdir for redo */
+char *maria_data_root;
+HASH maria_stored_state;
+
+/**
+ @brief when transactionality does not matter we can use this transaction
+
+ Used in external programs like ma_test*, and also internally inside
+ libmaria when there is no transaction around and the operation isn't
+ transactional (CREATE/DROP/RENAME/OPTIMIZE/REPAIR).
+*/
+TRN dummy_transaction_object;
+
+/* a WT_RESOURCE_TYPE for transactions waiting on a unique key conflict */
+WT_RESOURCE_TYPE ma_rc_dup_unique={ wt_resource_id_memcmp, 0};
+
+/* Enough for comparing if number is zero */
+uchar maria_zero_string[]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+/*
+ read_vec[] is used for converting between P_READ_KEY.. and SEARCH_
+ Position is , == , >= , <= , > , <
+*/
+
+uint32 maria_read_vec[]=
+{
+ SEARCH_FIND, /* HA_READ_KEY_EXACT */
+ SEARCH_FIND | SEARCH_BIGGER, /* HA_READ_KEY_OR_NEXT */
+ SEARCH_FIND | SEARCH_SMALLER, /* HA_READ_KEY_OR_PREV */
+ SEARCH_NO_FIND | SEARCH_BIGGER, /* HA_READ_AFTER_KEY */
+ SEARCH_NO_FIND | SEARCH_SMALLER, /* HA_READ_BEFORE_KEY */
+ SEARCH_FIND | SEARCH_PART_KEY, /* HA_READ_PREFIX */
+ SEARCH_LAST, /* HA_READ_PREFIX_LAST */
+ SEARCH_LAST | SEARCH_SMALLER, /* HA_READ_PREFIX_LAST_OR_PREV */
+ MBR_CONTAIN, /* HA_READ_MBR_CONTAIN */
+ MBR_INTERSECT, /* HA_READ_MBR_INTERSECT */
+ MBR_WITHIN, /* HA_READ_MBR_WITHIN */
+ MBR_DISJOINT, /* HA_READ_MBR_DISJOINT */
+ MBR_EQUAL /* HA_READ_MBR_EQUAL */
+};
+
+uint32 maria_readnext_vec[]=
+{
+ SEARCH_BIGGER, SEARCH_BIGGER, SEARCH_SMALLER, SEARCH_BIGGER, SEARCH_SMALLER,
+ SEARCH_BIGGER, SEARCH_SMALLER, SEARCH_SMALLER
+};
+
+static int always_valid(const char *filename __attribute__((unused)))
+{
+ return 0;
+}
+
+int (*maria_test_invalid_symlink)(const char *filename)= always_valid;
diff --git a/storage/maria/ma_statrec.c b/storage/maria/ma_statrec.c
new file mode 100644
index 00000000000..d3b457e7dc4
--- /dev/null
+++ b/storage/maria/ma_statrec.c
@@ -0,0 +1,302 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+ /* Functions to handle fixed-length-records */
+
+#include "maria_def.h"
+
+
+my_bool _ma_write_static_record(MARIA_HA *info, const uchar *record)
+{
+ uchar temp[8]; /* max pointer length */
+ if (info->s->state.dellink != HA_OFFSET_ERROR &&
+ !info->append_insert_at_end)
+ {
+ my_off_t filepos=info->s->state.dellink;
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ if (info->s->file_read(info, &temp[0],info->s->base.rec_reflength,
+ info->s->state.dellink+1,
+ MYF(MY_NABP)))
+ goto err;
+ info->s->state.dellink= _ma_rec_pos(info->s, temp);
+ info->state->del--;
+ info->state->empty-=info->s->base.pack_reclength;
+ if (info->s->file_write(info, record, info->s->base.reclength,
+ filepos, MYF(MY_NABP)))
+ goto err;
+ }
+ else
+ {
+ if (info->state->data_file_length > info->s->base.max_data_file_length-
+ info->s->base.pack_reclength)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ return(2);
+ }
+ if (info->opt_flag & WRITE_CACHE_USED)
+ { /* Cash in use */
+ if (my_b_write(&info->rec_cache, record,
+ info->s->base.reclength))
+ goto err;
+ if (info->s->base.pack_reclength != info->s->base.reclength)
+ {
+ uint length=info->s->base.pack_reclength - info->s->base.reclength;
+ bzero(temp,length);
+ if (my_b_write(&info->rec_cache, temp,length))
+ goto err;
+ }
+ }
+ else
+ {
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ if (info->s->file_write(info, record, info->s->base.reclength,
+ info->state->data_file_length,
+ info->s->write_flag))
+ goto err;
+ if (info->s->base.pack_reclength != info->s->base.reclength)
+ {
+ uint length=info->s->base.pack_reclength - info->s->base.reclength;
+ bzero(temp,length);
+ if (info->s->file_write(info, temp,length,
+ info->state->data_file_length+
+ info->s->base.reclength,
+ info->s->write_flag))
+ goto err;
+ }
+ }
+ info->state->data_file_length+=info->s->base.pack_reclength;
+ info->s->state.split++;
+ }
+ return 0;
+ err:
+ return 1;
+}
+
+my_bool _ma_update_static_record(MARIA_HA *info, MARIA_RECORD_POS pos,
+ const uchar *oldrec __attribute__ ((unused)),
+ const uchar *record)
+{
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ return (info->s->file_write(info,
+ record, info->s->base.reclength,
+ pos,
+ MYF(MY_NABP)) != 0);
+}
+
+
+my_bool _ma_delete_static_record(MARIA_HA *info,
+ const uchar *record __attribute__ ((unused)))
+{
+ uchar temp[9]; /* 1+sizeof(uint32) */
+ info->state->del++;
+ info->state->empty+=info->s->base.pack_reclength;
+ temp[0]= '\0'; /* Mark that record is deleted */
+ _ma_dpointer(info->s, temp+1, info->s->state.dellink);
+ info->s->state.dellink= info->cur_row.lastpos;
+ info->rec_cache.seek_not_done=1;
+ return (info->s->file_write(info, temp, 1+info->s->rec_reflength,
+ info->cur_row.lastpos, MYF(MY_NABP)) != 0);
+}
+
+
+my_bool _ma_cmp_static_record(register MARIA_HA *info,
+ register const uchar *old)
+{
+ DBUG_ENTER("_ma_cmp_static_record");
+
+ /* We are going to do changes; dont let anybody disturb */
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+
+ if (info->opt_flag & WRITE_CACHE_USED)
+ {
+ if (flush_io_cache(&info->rec_cache))
+ {
+ DBUG_RETURN(1);
+ }
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ }
+
+ if ((info->opt_flag & READ_CHECK_USED))
+ { /* If check isn't disabled */
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ if (info->s->file_read(info, info->rec_buff, info->s->base.reclength,
+ info->cur_row.lastpos, MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ if (memcmp(info->rec_buff, old, (uint) info->s->base.reclength))
+ {
+ DBUG_DUMP("read",old,info->s->base.reclength);
+ DBUG_DUMP("disk",info->rec_buff,info->s->base.reclength);
+ my_errno=HA_ERR_RECORD_CHANGED; /* Record have changed */
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+my_bool _ma_cmp_static_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
+ const uchar *record, MARIA_RECORD_POS pos)
+{
+ DBUG_ENTER("_ma_cmp_static_unique");
+
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+ if (info->s->file_read(info, info->rec_buff, info->s->base.reclength,
+ pos, MYF(MY_NABP)))
+ DBUG_RETURN(1);
+ DBUG_RETURN(_ma_unique_comp(def, record, (uchar*) info->rec_buff,
+ def->null_are_equal));
+}
+
+
+/*
+ Read a fixed-length-record
+
+ RETURN
+ 0 Ok
+ 1 record delete
+ -1 on read-error or locking-error
+*/
+
+int _ma_read_static_record(register MARIA_HA *info, register uchar *record,
+ MARIA_RECORD_POS pos)
+{
+ int error;
+ DBUG_ENTER("_ma_read_static_record");
+
+ if (pos != HA_OFFSET_ERROR)
+ {
+ if (info->opt_flag & WRITE_CACHE_USED &&
+ info->rec_cache.pos_in_file <= pos &&
+ flush_io_cache(&info->rec_cache))
+ DBUG_RETURN(my_errno);
+ info->rec_cache.seek_not_done=1; /* We have done a seek */
+
+ error= (int) info->s->file_read(info, record,info->s->base.reclength,
+ pos, MYF(MY_NABP));
+ if (! error)
+ {
+ fast_ma_writeinfo(info);
+ if (!*record)
+ {
+ /* Record is deleted */
+ DBUG_PRINT("warning", ("Record is deleted"));
+ DBUG_RETURN((my_errno=HA_ERR_RECORD_DELETED));
+ }
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ DBUG_RETURN(0);
+ }
+ }
+ fast_ma_writeinfo(info); /* No such record */
+ DBUG_RETURN(my_errno);
+}
+
+
+/**
+ @brief Read record from given position or next record
+
+ @note
+ When scanning, this function will return HA_ERR_RECORD_DELETED
+ for deleted rows even if skip_deleted_blocks is set.
+ The reason for this is to allow the caller to calculate the record
+ position without having to do call maria_position() for each record.
+*/
+
+int _ma_read_rnd_static_record(MARIA_HA *info, uchar *buf,
+ MARIA_RECORD_POS filepos,
+ my_bool skip_deleted_blocks)
+{
+ int locked,error,cache_read;
+ uint cache_length;
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_read_rnd_static_record");
+
+ cache_read=0;
+ cache_length=0;
+ if (info->opt_flag & READ_CACHE_USED)
+ { /* Cache in use */
+ if (filepos == my_b_tell(&info->rec_cache) &&
+ (skip_deleted_blocks || !filepos))
+ {
+ cache_read=1; /* Read record using cache */
+ cache_length= (uint) (info->rec_cache.read_end -
+ info->rec_cache.read_pos);
+ }
+ else
+ info->rec_cache.seek_not_done=1; /* Filepos is changed */
+ }
+ locked=0;
+ if (info->lock_type == F_UNLCK)
+ {
+ if (filepos >= info->state->data_file_length)
+ { /* Test if new records */
+ if (_ma_readinfo(info,F_RDLCK,0))
+ DBUG_RETURN(my_errno);
+ locked=1;
+ }
+ else
+ { /* We don't nead new info */
+#ifndef UNSAFE_LOCKING
+ if ((! cache_read || share->base.reclength > cache_length) &&
+ share->tot_locks == 0)
+ { /* record not in cache */
+ locked=1;
+ }
+#else
+ info->tmp_lock_type=F_RDLCK;
+#endif
+ }
+ }
+ if (filepos >= info->state->data_file_length)
+ {
+ DBUG_PRINT("test",("filepos: %ld (%ld) records: %ld del: %ld",
+ (long) filepos/share->base.reclength, (long) filepos,
+ (long) info->state->records, (long) info->state->del));
+ fast_ma_writeinfo(info);
+ DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE);
+ }
+ info->cur_row.lastpos= filepos;
+ info->cur_row.nextpos= filepos+share->base.pack_reclength;
+
+ if (! cache_read) /* No cacheing */
+ {
+ error= _ma_read_static_record(info, buf, filepos);
+ DBUG_RETURN(error);
+ }
+
+ /* Read record with cacheing */
+ error=my_b_read(&info->rec_cache,(uchar*) buf,share->base.reclength);
+ if (info->s->base.pack_reclength != info->s->base.reclength && !error)
+ {
+ char tmp[8]; /* Skill fill bytes */
+ error=my_b_read(&info->rec_cache,(uchar*) tmp,
+ info->s->base.pack_reclength - info->s->base.reclength);
+ }
+ if (locked)
+ VOID(_ma_writeinfo(info,0)); /* Unlock keyfile */
+ if (!error)
+ {
+ if (!buf[0])
+ { /* Record is removed */
+ DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED);
+ }
+ /* Found and may be updated */
+ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
+ DBUG_RETURN(0);
+ }
+ /* my_errno should be set if rec_cache.error == -1 */
+ if (info->rec_cache.error != -1 || my_errno == 0)
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ DBUG_RETURN(my_errno); /* Something wrong (EOF?) */
+}
diff --git a/storage/maria/ma_test1.c b/storage/maria/ma_test1.c
new file mode 100644
index 00000000000..affa3a71634
--- /dev/null
+++ b/storage/maria/ma_test1.c
@@ -0,0 +1,899 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Testing of the basic functions of a MARIA table */
+
+#include "maria_def.h"
+#include <my_getopt.h>
+#include <m_string.h>
+#include "ma_control_file.h"
+#include "ma_loghandler.h"
+#include "ma_checkpoint.h"
+#include "trnman.h"
+
+extern PAGECACHE *maria_log_pagecache;
+extern char *maria_data_root;
+
+#define MAX_REC_LENGTH 1024
+
+static void usage();
+
+static int rec_pointer_size=0, flags[50], testflag, checkpoint;
+static int key_field=FIELD_SKIP_PRESPACE,extra_field=FIELD_SKIP_ENDSPACE;
+static int key_type=HA_KEYTYPE_NUM;
+static int create_flag=0;
+static ulong blob_length;
+static enum data_file_type record_type= DYNAMIC_RECORD;
+
+static uint insert_count, update_count, remove_count;
+static uint pack_keys=0, pack_seg=0, key_length;
+static uint unique_key=HA_NOSAME;
+static uint die_in_middle_of_transaction;
+static my_bool pagecacheing, null_fields, silent, skip_update, opt_unique;
+static my_bool verbose, skip_delete, transactional;
+static my_bool opt_versioning= 0;
+static MARIA_COLUMNDEF recinfo[4];
+static MARIA_KEYDEF keyinfo[10];
+static HA_KEYSEG keyseg[10];
+static HA_KEYSEG uniqueseg[10];
+
+static int run_test(const char *filename);
+static void get_options(int argc, char *argv[]);
+static void create_key(uchar *key,uint rownr);
+static void create_record(uchar *record,uint rownr);
+static void update_record(uchar *record);
+
+
+/*
+ These are here only for testing of recovery with undo. We are not
+ including maria_def.h here as this test is also to be an example of
+ how to use maria outside of the maria directory
+*/
+
+extern int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
+ enum flush_type flush_type_for_data,
+ enum flush_type flush_type_for_index);
+#define MARIA_FLUSH_DATA 1
+
+
+int main(int argc,char *argv[])
+{
+#if defined(SAFE_MUTEX) && defined(THREAD)
+ safe_mutex_deadlock_detector= 1;
+#endif
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+ maria_data_root= (char *)".";
+ /* Maria requires that we always have a page cache */
+ if (maria_init() ||
+ (init_pagecache(maria_pagecache, maria_block_size * 16, 0, 0,
+ maria_block_size, MY_WME) == 0) ||
+ ma_control_file_open(TRUE, TRUE) ||
+ (init_pagecache(maria_log_pagecache,
+ TRANSLOG_PAGECACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, MY_WME) == 0) ||
+ translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
+ 0, 0, maria_log_pagecache,
+ TRANSLOG_DEFAULT_FLAGS, 0) ||
+ (transactional && (trnman_init(0) || ma_checkpoint_init(0))))
+ {
+ fprintf(stderr, "Error in initialization\n");
+ exit(1);
+ }
+ if (opt_versioning)
+ init_thr_lock();
+
+ exit(run_test("test1"));
+}
+
+
+static int run_test(const char *filename)
+{
+ MARIA_HA *file;
+ int i,j= 0,error,deleted,rec_length,uniques=0;
+ uint offset_to_key;
+ ha_rows found,row_count;
+ uchar record[MAX_REC_LENGTH],key[MAX_REC_LENGTH],read_record[MAX_REC_LENGTH];
+ MARIA_UNIQUEDEF uniquedef;
+ MARIA_CREATE_INFO create_info;
+
+ if (die_in_middle_of_transaction)
+ null_fields= 1;
+
+ bzero((char*) recinfo,sizeof(recinfo));
+ bzero((char*) &create_info,sizeof(create_info));
+
+ /* First define 2 columns */
+ create_info.null_bytes= 1;
+ recinfo[0].type= key_field;
+ recinfo[0].length= (key_field == FIELD_BLOB ? 4+portable_sizeof_char_ptr :
+ key_length);
+ if (key_field == FIELD_VARCHAR)
+ recinfo[0].length+= HA_VARCHAR_PACKLENGTH(key_length);
+ recinfo[1].type=extra_field;
+ recinfo[1].length= (extra_field == FIELD_BLOB ? 4 + portable_sizeof_char_ptr : 24);
+ if (extra_field == FIELD_VARCHAR)
+ recinfo[1].length+= HA_VARCHAR_PACKLENGTH(recinfo[1].length);
+ recinfo[1].null_bit= null_fields ? 2 : 0;
+
+ if (opt_unique)
+ {
+ recinfo[2].type=FIELD_CHECK;
+ recinfo[2].length=MARIA_UNIQUE_HASH_LENGTH;
+ }
+ rec_length= recinfo[0].length + recinfo[1].length + recinfo[2].length +
+ create_info.null_bytes;
+
+ if (key_type == HA_KEYTYPE_VARTEXT1 &&
+ key_length > 255)
+ key_type= HA_KEYTYPE_VARTEXT2;
+
+ /* Define a key over the first column */
+ keyinfo[0].seg=keyseg;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].block_length= 0; /* Default block length */
+ keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[0].seg[0].type= key_type;
+ keyinfo[0].seg[0].flag= pack_seg;
+ keyinfo[0].seg[0].start=1;
+ keyinfo[0].seg[0].length=key_length;
+ keyinfo[0].seg[0].null_bit= null_fields ? 2 : 0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].seg[0].language= default_charset_info->number;
+ if (pack_seg & HA_BLOB_PART)
+ {
+ keyinfo[0].seg[0].bit_start=4; /* Length of blob length */
+ }
+ keyinfo[0].flag = (uint8) (pack_keys | unique_key);
+
+ bzero((uchar*) flags,sizeof(flags));
+ if (opt_unique)
+ {
+ uint start;
+ uniques=1;
+ bzero((char*) &uniquedef,sizeof(uniquedef));
+ bzero((char*) uniqueseg,sizeof(uniqueseg));
+ uniquedef.seg=uniqueseg;
+ uniquedef.keysegs=2;
+
+ /* Make a unique over all columns (except first NULL fields) */
+ for (i=0, start=1 ; i < 2 ; i++)
+ {
+ uniqueseg[i].start=start;
+ start+=recinfo[i].length;
+ uniqueseg[i].length=recinfo[i].length;
+ uniqueseg[i].language= default_charset_info->number;
+ }
+ uniqueseg[0].type= key_type;
+ uniqueseg[0].null_bit= null_fields ? 2 : 0;
+ uniqueseg[1].type= HA_KEYTYPE_TEXT;
+ if (extra_field == FIELD_BLOB)
+ {
+ uniqueseg[1].length=0; /* The whole blob */
+ uniqueseg[1].bit_start=4; /* long blob */
+ uniqueseg[1].flag|= HA_BLOB_PART;
+ }
+ else if (extra_field == FIELD_VARCHAR)
+ {
+ uniqueseg[1].flag|= HA_VAR_LENGTH_PART;
+ uniqueseg[1].type= (HA_VARCHAR_PACKLENGTH(recinfo[1].length-1) == 1 ?
+ HA_KEYTYPE_VARTEXT1 : HA_KEYTYPE_VARTEXT2);
+ }
+ }
+ else
+ uniques=0;
+
+ offset_to_key= test(null_fields);
+ if (key_field == FIELD_BLOB || key_field == FIELD_VARCHAR)
+ offset_to_key+= 2;
+
+ if (!silent)
+ printf("- Creating maria file\n");
+ create_info.max_rows=(ulong) (rec_pointer_size ?
+ (1L << (rec_pointer_size*8))/40 :
+ 0);
+ create_info.transactional= transactional;
+ if (maria_create(filename, record_type, 1, keyinfo,2+opt_unique,recinfo,
+ uniques, &uniquedef, &create_info,
+ create_flag))
+ goto err;
+ if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ if (!silent)
+ printf("- Writing key:s\n");
+
+ if (maria_begin(file))
+ goto err;
+ if (opt_versioning)
+ maria_versioning(file, 1);
+ my_errno=0;
+ row_count=deleted=0;
+ for (i=49 ; i>=1 ; i-=2 )
+ {
+ if (insert_count-- == 0)
+ {
+ if (testflag)
+ break;
+ VOID(maria_close(file));
+ exit(0);
+ }
+ j=i%25 +1;
+ create_record(record,j);
+ error=maria_write(file,record);
+ if (!error)
+ row_count++;
+ flags[j]=1;
+ if (verbose || error)
+ printf("J= %2d maria_write: %d errno: %d\n", j,error,my_errno);
+ }
+
+ if (maria_commit(file) || maria_begin(file))
+ goto err;
+
+ if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (testflag == 1)
+ goto end;
+
+ /* Insert 2 rows with null values */
+ if (null_fields)
+ {
+ create_record(record,0);
+ error=maria_write(file,record);
+ if (!error)
+ row_count++;
+ if (verbose || error)
+ printf("J= NULL maria_write: %d errno: %d\n", error,my_errno);
+ error=maria_write(file,record);
+ if (!error)
+ row_count++;
+ if (verbose || error)
+ printf("J= NULL maria_write: %d errno: %d\n", error,my_errno);
+ flags[0]=2;
+ }
+
+ if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (testflag == 2)
+ {
+ printf("Terminating after inserts\n");
+ goto end;
+ }
+
+ if (maria_commit(file) || maria_begin(file))
+ goto err;
+
+ if (!skip_update)
+ {
+ if (opt_unique)
+ {
+ if (!silent)
+ printf("- Checking unique constraint\n");
+ create_record(record,j); /* Check last created row */
+ if (!maria_write(file,record) || my_errno != HA_ERR_FOUND_DUPP_UNIQUE)
+ {
+ printf("unique check failed\n");
+ }
+ }
+ if (!silent)
+ printf("- Updating rows\n");
+
+ /* Update first last row to force extend of file */
+ if (maria_rsame(file,read_record,-1))
+ {
+ printf("Can't find last row with maria_rsame\n");
+ }
+ else
+ {
+ memcpy(record,read_record,rec_length);
+ update_record(record);
+ if (maria_update(file,read_record,record))
+ {
+ printf("Can't update last row: %.*s\n",
+ keyinfo[0].seg[0].length,read_record+1);
+ }
+ }
+
+ /* Read through all rows and update them */
+ assert(maria_scan_init(file) == 0);
+
+ found=0;
+ while ((error= maria_scan(file,read_record)) == 0)
+ {
+ if (--update_count == 0) { VOID(maria_close(file)) ; exit(0) ; }
+ memcpy(record,read_record,rec_length);
+ update_record(record);
+ if (maria_update(file,read_record,record))
+ {
+ printf("Can't update row: %.*s, error: %d\n",
+ keyinfo[0].seg[0].length,record+1,my_errno);
+ }
+ found++;
+ }
+ if (found != row_count)
+ printf("Found %ld of %ld rows\n", (ulong) found, (ulong) row_count);
+ maria_scan_end(file);
+ }
+
+ if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (testflag == 3)
+ {
+ printf("Terminating after updates\n");
+ goto end;
+ }
+ if (!silent)
+ printf("- Reopening file\n");
+ if (maria_commit(file))
+ goto err;
+ if (maria_close(file))
+ goto err;
+ if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ if (maria_begin(file))
+ goto err;
+ if (opt_versioning)
+ maria_versioning(file, 1);
+ if (!skip_delete)
+ {
+ if (!silent)
+ printf("- Removing keys\n");
+
+ for (i=0 ; i <= 10 ; i++)
+ {
+ /*
+ If you want to debug the problem in ma_test_recovery with BLOBs
+ (see @todo there), you can break out of the loop after just one
+ delete, it is enough, like this:
+ if (i==1) break;
+ */
+ /* testing */
+ if (remove_count-- == 0)
+ {
+ fprintf(stderr,
+ "delete-rows number of rows deleted; Going down hard!\n");
+ goto end;
+ }
+ j=i*2;
+ if (!flags[j])
+ continue;
+ create_key(key,j);
+ my_errno=0;
+ if ((error = maria_rkey(file, read_record, 0, key,
+ HA_WHOLE_KEY, HA_READ_KEY_EXACT)))
+ {
+ if (verbose || (flags[j] >= 1 ||
+ (error && my_errno != HA_ERR_KEY_NOT_FOUND)))
+ printf("key: '%.*s' maria_rkey: %3d errno: %3d\n",
+ (int) key_length,key+offset_to_key,error,my_errno);
+ }
+ else
+ {
+ error=maria_delete(file,read_record);
+ if (verbose || error)
+ printf("key: '%.*s' maria_delete: %3d errno: %3d\n",
+ (int) key_length, key+offset_to_key, error, my_errno);
+ if (! error)
+ {
+ deleted++;
+ flags[j]--;
+ }
+ }
+ }
+ }
+
+ if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (testflag == 4)
+ {
+ printf("Terminating after deletes\n");
+ goto end;
+ }
+
+ if (!silent)
+ printf("- Reading rows with key\n");
+ record[1]= 0; /* For nicer printf */
+ for (i=0 ; i <= 25 ; i++)
+ {
+ create_key(key,i);
+ my_errno=0;
+ error=maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT);
+ if (verbose ||
+ (error == 0 && flags[i] == 0 && unique_key) ||
+ (error && (flags[i] != 0 || my_errno != HA_ERR_KEY_NOT_FOUND)))
+ {
+ printf("key: '%.*s' maria_rkey: %3d errno: %3d record: %s\n",
+ (int) key_length,key+offset_to_key,error,my_errno,record+1);
+ }
+ }
+
+ if (!silent)
+ printf("- Reading rows with position\n");
+ if (maria_scan_init(file))
+ {
+ fprintf(stderr, "maria_scan_init failed\n");
+ goto err;
+ }
+
+ for (i=1,found=0 ; i <= 30 ; i++)
+ {
+ my_errno=0;
+ if ((error= maria_scan(file, read_record)) == HA_ERR_END_OF_FILE)
+ {
+ if (found != row_count-deleted)
+ printf("Found only %ld of %ld rows\n", (ulong) found,
+ (ulong) (row_count - deleted));
+ break;
+ }
+ if (!error)
+ found++;
+ if (verbose || (error != 0 && error != HA_ERR_RECORD_DELETED &&
+ error != HA_ERR_END_OF_FILE))
+ {
+ printf("pos: %2d maria_rrnd: %3d errno: %3d record: %s\n",
+ i-1,error,my_errno,read_record+1);
+ }
+ }
+ maria_scan_end(file);
+
+end:
+ if (die_in_middle_of_transaction)
+ {
+ /* As commit record is not done, UNDO entries needs to be rolled back */
+ switch (die_in_middle_of_transaction) {
+ case 1:
+ /*
+ Flush changed pages go to disk. That will also flush log. Recovery
+ will skip REDOs and apply UNDOs.
+ */
+ _ma_flush_table_files(file, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_RELEASE, FLUSH_RELEASE);
+ break;
+ case 2:
+ /*
+ Just flush log. Pages are likely to not be on disk. Recovery will
+ then execute REDOs and UNDOs.
+ */
+ if (translog_flush(file->trn->undo_lsn))
+ goto err;
+ break;
+ case 3:
+ /*
+ Flush nothing. Pages and log are likely to not be on disk. Recovery
+ will then do nothing.
+ */
+ break;
+ case 4:
+ /*
+ Flush changed data pages go to disk. Changed index pages are not
+ flushed. Recovery will skip some REDOs and apply UNDOs.
+ */
+ _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE,
+ FLUSH_RELEASE);
+ /*
+ We have to flush log separately as the redo for the last key page
+ may not be flushed
+ */
+ if (translog_flush(file->trn->undo_lsn))
+ goto err;
+ break;
+ }
+ printf("Dying on request without maria_commit()/maria_close()\n");
+ exit(0);
+ }
+
+ if (maria_commit(file))
+ goto err;
+ if (maria_close(file))
+ goto err;
+ maria_end();
+ my_end(MY_CHECK_ERROR);
+
+ return (0);
+err:
+ printf("got error: %3d when using maria-database\n",my_errno);
+ return 1; /* skip warning */
+}
+
+
+static void create_key_part(uchar *key,uint rownr)
+{
+ if (!unique_key)
+ rownr&=7; /* Some identical keys */
+ if (keyinfo[0].seg[0].type == HA_KEYTYPE_NUM)
+ {
+ sprintf((char*) key,"%*d",keyinfo[0].seg[0].length,rownr);
+ }
+ else if (keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT1 ||
+ keyinfo[0].seg[0].type == HA_KEYTYPE_VARTEXT2)
+ { /* Alpha record */
+ /* Create a key that may be easily packed */
+ bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
+ sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d",rownr);
+ if ((rownr & 7) == 0)
+ {
+ /* Change the key to force a unpack of the next key */
+ bfill(key+3,keyinfo[0].seg[0].length-5,rownr < 10 ? 'a' : 'b');
+ }
+ }
+ else
+ { /* Alpha record */
+ if (keyinfo[0].seg[0].flag & HA_SPACE_PACK)
+ sprintf((char*) key,"%-*d",keyinfo[0].seg[0].length,rownr);
+ else
+ {
+ /* Create a key that may be easily packed */
+ bfill(key,keyinfo[0].seg[0].length,rownr < 10 ? 'A' : 'B');
+ sprintf((char*) key+keyinfo[0].seg[0].length-2,"%-2d",rownr);
+ if ((rownr & 7) == 0)
+ {
+ /* Change the key to force a unpack of the next key */
+ key[1]= (rownr < 10 ? 'a' : 'b');
+ }
+ }
+ }
+}
+
+
+static void create_key(uchar *key,uint rownr)
+{
+ if (keyinfo[0].seg[0].null_bit)
+ {
+ if (rownr == 0)
+ {
+ key[0]=1; /* null key */
+ key[1]=0; /* For easy print of key */
+ return;
+ }
+ *key++=0;
+ }
+ if (keyinfo[0].seg[0].flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
+ {
+ uint tmp;
+ create_key_part(key+2,rownr);
+ tmp=strlen((char*) key+2);
+ int2store(key,tmp);
+ }
+ else
+ create_key_part(key,rownr);
+}
+
+
+static uchar blob_key[MAX_REC_LENGTH];
+static uchar blob_record[MAX_REC_LENGTH+20*20];
+
+
+static void create_record(uchar *record,uint rownr)
+{
+ uchar *pos;
+ bzero((char*) record,MAX_REC_LENGTH);
+ record[0]=1; /* delete marker */
+ if (rownr == 0 && keyinfo[0].seg[0].null_bit)
+ record[0]|=keyinfo[0].seg[0].null_bit; /* Null key */
+
+ pos=record+1;
+ if (recinfo[0].type == FIELD_BLOB)
+ {
+ uint tmp;
+ uchar *ptr;
+ create_key_part(blob_key,rownr);
+ tmp=strlen((char*) blob_key);
+ int4store(pos,tmp);
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ pos+=recinfo[0].length;
+ }
+ else if (recinfo[0].type == FIELD_VARCHAR)
+ {
+ uint tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[0].length-1);
+ create_key_part(pos+pack_length,rownr);
+ tmp= strlen((char*) pos+pack_length);
+ if (pack_length == 1)
+ *(uchar*) pos= (uchar) tmp;
+ else
+ int2store(pos,tmp);
+ pos+= recinfo[0].length;
+ }
+ else
+ {
+ create_key_part(pos,rownr);
+ pos+=recinfo[0].length;
+ }
+ if (recinfo[1].type == FIELD_BLOB)
+ {
+ uint tmp;
+ uchar *ptr;;
+ sprintf((char*) blob_record,"... row: %d", rownr);
+ strappend((char*) blob_record,max(MAX_REC_LENGTH-rownr,10),' ');
+ tmp=strlen((char*) blob_record);
+ int4store(pos,tmp);
+ ptr=blob_record;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*));
+ }
+ else if (recinfo[1].type == FIELD_VARCHAR)
+ {
+ uint tmp, pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
+ sprintf((char*) pos+pack_length, "... row: %d", rownr);
+ tmp= strlen((char*) pos+pack_length);
+ if (pack_length == 1)
+ *pos= (uchar) tmp;
+ else
+ int2store(pos,tmp);
+ }
+ else
+ {
+ sprintf((char*) pos,"... row: %d", rownr);
+ strappend((char*) pos,recinfo[1].length,' ');
+ }
+}
+
+/* change row to test re-packing of rows and reallocation of keys */
+
+static void update_record(uchar *record)
+{
+ uchar *pos=record+1;
+ if (recinfo[0].type == FIELD_BLOB)
+ {
+ uchar *column,*ptr;
+ int length;
+ length=uint4korr(pos); /* Long blob */
+ memcpy_fixed(&column,pos+4,sizeof(char*));
+ memcpy(blob_key,column,length); /* Move old key */
+ ptr=blob_key;
+ memcpy_fixed(pos+4,&ptr,sizeof(char*)); /* Store pointer to new key */
+ if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM)
+ default_charset_info->cset->casedn(default_charset_info,
+ (char*) blob_key, length,
+ (char*) blob_key, length);
+ pos+=recinfo[0].length;
+ }
+ else if (recinfo[0].type == FIELD_VARCHAR)
+ {
+ uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[0].length-1);
+ uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos);
+ default_charset_info->cset->casedn(default_charset_info,
+ (char*) pos + pack_length, length,
+ (char*) pos + pack_length, length);
+ pos+=recinfo[0].length;
+ }
+ else
+ {
+ if (keyinfo[0].seg[0].type != HA_KEYTYPE_NUM)
+ default_charset_info->cset->casedn(default_charset_info,
+ (char*) pos, keyinfo[0].seg[0].length,
+ (char*) pos, keyinfo[0].seg[0].length);
+ pos+=recinfo[0].length;
+ }
+
+ if (recinfo[1].type == FIELD_BLOB)
+ {
+ uchar *column;
+ int length;
+ length=uint4korr(pos);
+ memcpy_fixed(&column,pos+4,sizeof(char*));
+ memcpy(blob_record,column,length);
+ bfill(blob_record+length,20,'.'); /* Make it larger */
+ length+=20;
+ int4store(pos,length);
+ column=blob_record;
+ memcpy_fixed(pos+4,&column,sizeof(char*));
+ }
+ else if (recinfo[1].type == FIELD_VARCHAR)
+ {
+ /* Second field is longer than 10 characters */
+ uint pack_length= HA_VARCHAR_PACKLENGTH(recinfo[1].length-1);
+ uint length= pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos);
+ pos= record+ recinfo[1].offset;
+ bfill(pos+pack_length+length,recinfo[1].length-length-pack_length,'.');
+ length=recinfo[1].length-pack_length;
+ if (pack_length == 1)
+ *(uchar*) pos= (uchar) length;
+ else
+ int2store(pos,length);
+ }
+ else
+ {
+ bfill(pos+recinfo[1].length-10,10,'.');
+ }
+}
+
+
+static struct my_option my_long_options[] =
+{
+ {"checkpoint", 'H', "Checkpoint at specified stage", (uchar**) &checkpoint,
+ (uchar**) &checkpoint, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"checksum", 'c', "Undocumented",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+ {"debug", '#', "Undocumented",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"delete-rows", 'd', "Abort after this many rows has been deleted",
+ (uchar**) &remove_count, (uchar**) &remove_count, 0, GET_UINT, REQUIRED_ARG,
+ 1000, 0, 0, 0, 0, 0},
+ {"help", '?', "Display help and exit",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"insert-rows", 'i', "Undocumented", (uchar**) &insert_count,
+ (uchar**) &insert_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0},
+ {"key-alpha", 'a', "Use a key of type HA_KEYTYPE_TEXT",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"key-binary-pack", 'B', "Undocumented",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"key-blob", 'b', "Undocumented",
+ (uchar**) &blob_length, (uchar**) &blob_length,
+ 0, GET_ULONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"key-cache", 'K', "Undocumented", (uchar**) &pagecacheing,
+ (uchar**) &pagecacheing, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"key-length", 'k', "Undocumented", (uchar**) &key_length,
+ (uchar**) &key_length, 0, GET_UINT, REQUIRED_ARG, 6, 0, 0, 0, 0, 0},
+ {"key-multiple", 'm', "Don't use unique keys",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"key-prefix_pack", 'P', "Undocumented",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"key-space_pack", 'p', "Undocumented",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"key-varchar", 'w', "Test VARCHAR keys",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"null-fields", 'N', "Define fields with NULL",
+ (uchar**) &null_fields, (uchar**) &null_fields, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+ {"row-fixed-size", 'S', "Fixed size records",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"rows-in-block", 'M', "Store rows in block format",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"row-pointer-size", 'R', "Undocumented", (uchar**) &rec_pointer_size,
+ (uchar**) &rec_pointer_size, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"silent", 's', "Undocumented",
+ (uchar**) &silent, (uchar**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
+ 0, 0},
+ {"skip-delete", 'D', "Don't test deletes", (uchar**) &skip_delete,
+ (uchar**) &skip_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"skip-update", 'U', "Don't test updates", (uchar**) &skip_update,
+ (uchar**) &skip_update, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"testflag", 't', "Stop test at specified stage", (uchar**) &testflag,
+ (uchar**) &testflag, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"test-undo", 'A',
+ "Abort hard. Used for testing recovery with undo",
+ (uchar**) &die_in_middle_of_transaction,
+ (uchar**) &die_in_middle_of_transaction,
+ 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"transactional", 'T',
+ "Test in transactional mode. (Only works with block format)",
+ (uchar**) &transactional, (uchar**) &transactional, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+ {"unique", 'E', "Check unique handling", (uchar**) &opt_unique,
+ (uchar**) &opt_unique, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"update-rows", 'u', "Max number of rows to update", (uchar**) &update_count,
+ (uchar**) &update_count, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0},
+ {"verbose", 'v', "Be more verbose", (uchar**) &verbose,
+ (uchar**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version number and exit",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"versioning", 'C', "Use row versioning (only works with block format)",
+ (uchar**) &opt_versioning, (uchar**) &opt_versioning, 0, GET_BOOL,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch(optid) {
+ case 'a':
+ key_type= HA_KEYTYPE_TEXT;
+ break;
+ case 'c':
+ create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
+ break;
+ case 'R': /* Length of record pointer */
+ if (rec_pointer_size > 3)
+ rec_pointer_size=0;
+ break;
+ case 'P':
+ pack_keys= HA_PACK_KEY; /* Use prefix compression */
+ break;
+ case 'B':
+ pack_keys= HA_BINARY_PACK_KEY; /* Use binary compression */
+ break;
+ case 'M':
+ record_type= BLOCK_RECORD;
+ break;
+ case 'S':
+ if (key_field == FIELD_VARCHAR)
+ {
+ create_flag=0; /* Static sized varchar */
+ record_type= STATIC_RECORD;
+ }
+ else if (key_field != FIELD_BLOB)
+ {
+ key_field=FIELD_NORMAL; /* static-size record */
+ extra_field=FIELD_NORMAL;
+ record_type= STATIC_RECORD;
+ }
+ break;
+ case 'p':
+ pack_keys=HA_PACK_KEY; /* Use prefix + space packing */
+ pack_seg=HA_SPACE_PACK;
+ key_type=HA_KEYTYPE_TEXT;
+ break;
+ case 'm':
+ unique_key=0;
+ break;
+ case 'b':
+ key_field=FIELD_BLOB; /* blob key */
+ extra_field= FIELD_BLOB;
+ pack_seg|= HA_BLOB_PART;
+ key_type= HA_KEYTYPE_VARTEXT1;
+ if (record_type == STATIC_RECORD)
+ record_type= DYNAMIC_RECORD;
+ break;
+ case 'k':
+ if (key_length < 4 || key_length > HA_MAX_KEY_LENGTH)
+ {
+ fprintf(stderr,"Wrong key length\n");
+ exit(1);
+ }
+ break;
+ case 'w':
+ key_field=FIELD_VARCHAR; /* varchar keys */
+ extra_field= FIELD_VARCHAR;
+ key_type= HA_KEYTYPE_VARTEXT1;
+ pack_seg|= HA_VAR_LENGTH_PART;
+ if (record_type == STATIC_RECORD)
+ record_type= DYNAMIC_RECORD;
+ break;
+ case 'K': /* Use key cacheing */
+ pagecacheing=1;
+ break;
+ case 'V':
+ printf("test1 Ver 1.2 \n");
+ exit(0);
+ case '#':
+ DBUG_PUSH(argument);
+ break;
+ case '?':
+ usage();
+ exit(1);
+ }
+ return 0;
+}
+
+
+/* Read options */
+
+static void get_options(int argc, char *argv[])
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
+ exit(ho_error);
+ if (transactional)
+ record_type= BLOCK_RECORD;
+ return;
+} /* get options */
+
+
+static void usage()
+{
+ printf("Usage: %s [options]\n\n", my_progname);
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
diff --git a/storage/maria/ma_test2.c b/storage/maria/ma_test2.c
new file mode 100644
index 00000000000..07d67b4fce4
--- /dev/null
+++ b/storage/maria/ma_test2.c
@@ -0,0 +1,1240 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Test av isam-databas: stor test */
+
+#ifndef USE_MY_FUNC /* We want to be able to dbug this !! */
+#define USE_MY_FUNC
+#endif
+#include "maria_def.h"
+#include "trnman.h"
+#include <m_ctype.h>
+#include <my_bit.h>
+#include "ma_checkpoint.h"
+
+#define STANDARD_LENGTH 37
+#define MARIA_KEYS 6
+#define MAX_PARTS 4
+#if !defined(MSDOS) && !defined(labs)
+#define labs(a) abs(a)
+#endif
+
+static void get_options(int argc, char *argv[]);
+static uint rnd(uint max_value);
+static void fix_length(uchar *record,uint length);
+static void put_blob_in_record(uchar *blob_pos,char **blob_buffer,
+ ulong *length);
+static void copy_key(MARIA_HA *info, uint inx, uchar *record, uchar *key);
+
+static int verbose= 0, testflag= 0, first_key= 0, async_io= 0, pagecacheing= 0;
+static int write_cacheing= 0, do_locking= 0, rec_pointer_size= 0;
+static int silent= 0, opt_quick_mode= 0, transactional= 0, skip_update= 0;
+static int die_in_middle_of_transaction= 0, pack_fields= 1;
+static int pack_seg= HA_SPACE_PACK, pack_type= HA_PACK_KEY, remove_count= -1;
+static int create_flag= 0, srand_arg= 0, checkpoint= 0;
+static my_bool opt_versioning= 0;
+static uint use_blob= 0, update_count= 0;
+static ulong pagecache_size=8192*32;
+static enum data_file_type record_type= DYNAMIC_RECORD;
+
+static uint keys=MARIA_KEYS,recant=1000;
+static uint16 key1[1001],key3[5000];
+static uchar record[300],record2[300],key[100],key2[100];
+static uchar read_record[300],read_record2[300],read_record3[300];
+static HA_KEYSEG glob_keyseg[MARIA_KEYS][MAX_PARTS];
+
+ /* Test program */
+
+int main(int argc, char *argv[])
+{
+ uint i;
+ int j,n1,n2,n3,error,k;
+ uint write_count,update,dupp_keys,opt_delete,start,length,blob_pos,
+ reclength,ant,found_parts;
+ my_off_t lastpos;
+ ha_rows range_records,records;
+ MARIA_HA *file;
+ MARIA_KEYDEF keyinfo[10];
+ MARIA_COLUMNDEF recinfo[10];
+ MARIA_INFO info;
+ const char *filename;
+ char *blob_buffer;
+ MARIA_CREATE_INFO create_info;
+
+#if defined(SAFE_MUTEX) && defined(THREAD)
+ safe_mutex_deadlock_detector= 1;
+#endif
+ MY_INIT(argv[0]);
+
+ filename= "test2";
+ get_options(argc,argv);
+ if (! async_io)
+ my_disable_async_io=1;
+
+ maria_data_root= (char *)".";
+ /* Maria requires that we always have a page cache */
+ if (maria_init() ||
+ (init_pagecache(maria_pagecache, pagecache_size, 0, 0,
+ maria_block_size, MY_WME) == 0) ||
+ ma_control_file_open(TRUE, TRUE) ||
+ (init_pagecache(maria_log_pagecache,
+ TRANSLOG_PAGECACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, MY_WME) == 0) ||
+ translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
+ 0, 0, maria_log_pagecache,
+ TRANSLOG_DEFAULT_FLAGS, 0) ||
+ (transactional && (trnman_init(0) || ma_checkpoint_init(0))))
+ {
+ fprintf(stderr, "Error in initialization");
+ exit(1);
+ }
+ if (opt_versioning)
+ init_thr_lock();
+
+ reclength=STANDARD_LENGTH+60+(use_blob ? 8 : 0);
+ blob_pos=STANDARD_LENGTH+60;
+ keyinfo[0].seg= &glob_keyseg[0][0];
+ keyinfo[0].seg[0].start=0;
+ keyinfo[0].seg[0].length=6;
+ keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].language= default_charset_info->number;
+ keyinfo[0].seg[0].flag=(uint8) pack_seg;
+ keyinfo[0].seg[0].null_bit=0;
+ keyinfo[0].seg[0].null_pos=0;
+ keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].flag = pack_type;
+ keyinfo[0].block_length= 0; /* Default block length */
+ keyinfo[1].seg= &glob_keyseg[1][0];
+ keyinfo[1].seg[0].start=7;
+ keyinfo[1].seg[0].length=6;
+ keyinfo[1].seg[0].type=HA_KEYTYPE_BINARY;
+ keyinfo[1].seg[0].flag=0;
+ keyinfo[1].seg[0].null_bit=0;
+ keyinfo[1].seg[0].null_pos=0;
+ keyinfo[1].seg[1].start=0; /* two part key */
+ keyinfo[1].seg[1].length=6;
+ keyinfo[1].seg[1].type=HA_KEYTYPE_NUM;
+ keyinfo[1].seg[1].flag=HA_REVERSE_SORT;
+ keyinfo[1].seg[1].null_bit=0;
+ keyinfo[1].seg[1].null_pos=0;
+ keyinfo[1].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[1].keysegs=2;
+ keyinfo[1].flag =0;
+ keyinfo[1].block_length= MARIA_MIN_KEY_BLOCK_LENGTH; /* Diff blocklength */
+ keyinfo[2].seg= &glob_keyseg[2][0];
+ keyinfo[2].seg[0].start=12;
+ keyinfo[2].seg[0].length=8;
+ keyinfo[2].seg[0].type=HA_KEYTYPE_BINARY;
+ keyinfo[2].seg[0].flag=HA_REVERSE_SORT;
+ keyinfo[2].seg[0].null_bit=0;
+ keyinfo[2].seg[0].null_pos=0;
+ keyinfo[2].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[2].keysegs=1;
+ keyinfo[2].flag =HA_NOSAME;
+ keyinfo[2].block_length= 0; /* Default block length */
+ keyinfo[3].seg= &glob_keyseg[3][0];
+ keyinfo[3].seg[0].start=0;
+ keyinfo[3].seg[0].length=reclength-(use_blob ? 8 : 0);
+ keyinfo[3].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[3].seg[0].language=default_charset_info->number;
+ keyinfo[3].seg[0].flag=(uint8) pack_seg;
+ keyinfo[3].seg[0].null_bit=0;
+ keyinfo[3].seg[0].null_pos=0;
+ keyinfo[3].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[3].keysegs=1;
+ keyinfo[3].flag = pack_type;
+ keyinfo[3].block_length= 0; /* Default block length */
+ keyinfo[4].seg= &glob_keyseg[4][0];
+ keyinfo[4].seg[0].start=0;
+ keyinfo[4].seg[0].length=5;
+ keyinfo[4].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[4].seg[0].language=default_charset_info->number;
+ keyinfo[4].seg[0].flag=0;
+ keyinfo[4].seg[0].null_bit=0;
+ keyinfo[4].seg[0].null_pos=0;
+ keyinfo[4].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[4].keysegs=1;
+ keyinfo[4].flag = pack_type;
+ keyinfo[4].block_length= 0; /* Default block length */
+ keyinfo[5].seg= &glob_keyseg[5][0];
+ keyinfo[5].seg[0].start=0;
+ keyinfo[5].seg[0].length=4;
+ keyinfo[5].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[5].seg[0].language=default_charset_info->number;
+ keyinfo[5].seg[0].flag=pack_seg;
+ keyinfo[5].seg[0].null_bit=0;
+ keyinfo[5].seg[0].null_pos=0;
+ keyinfo[5].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[5].keysegs=1;
+ keyinfo[5].flag = pack_type;
+ keyinfo[5].block_length= 0; /* Default block length */
+
+ recinfo[0].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
+ recinfo[0].length=7;
+ recinfo[0].null_bit=0;
+ recinfo[0].null_pos=0;
+ recinfo[1].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
+ recinfo[1].length=5;
+ recinfo[1].null_bit=0;
+ recinfo[1].null_pos=0;
+ recinfo[2].type=pack_fields ? FIELD_SKIP_PRESPACE : 0;
+ recinfo[2].length=9;
+ recinfo[2].null_bit=0;
+ recinfo[2].null_pos=0;
+ recinfo[3].type=FIELD_NORMAL;
+ recinfo[3].length=STANDARD_LENGTH-7-5-9-4;
+ recinfo[3].null_bit=0;
+ recinfo[3].null_pos=0;
+ recinfo[4].type=pack_fields ? FIELD_SKIP_ZERO : 0;
+ recinfo[4].length=4;
+ recinfo[4].null_bit=0;
+ recinfo[4].null_pos=0;
+ recinfo[5].type=pack_fields ? FIELD_SKIP_ENDSPACE : 0;
+ recinfo[5].length=60;
+ recinfo[5].null_bit=0;
+ recinfo[5].null_pos=0;
+ if (use_blob)
+ {
+ recinfo[6].type=FIELD_BLOB;
+ recinfo[6].length=4+portable_sizeof_char_ptr;
+ recinfo[6].null_bit=0;
+ recinfo[6].null_pos=0;
+ }
+
+ write_count=update=dupp_keys=opt_delete=0;
+ blob_buffer=0;
+
+ for (i=1000 ; i>0 ; i--) key1[i]=0;
+ for (i=4999 ; i>0 ; i--) key3[i]=0;
+
+ if (!silent)
+ printf("- Creating maria-file\n");
+ file= 0;
+ bzero((char*) &create_info,sizeof(create_info));
+ create_info.max_rows=(ha_rows) (rec_pointer_size ?
+ (1L << (rec_pointer_size*8))/
+ reclength : 0);
+ create_info.reloc_rows=(ha_rows) 100;
+ create_info.transactional= transactional;
+ if (maria_create(filename, record_type, keys,&keyinfo[first_key],
+ use_blob ? 7 : 6, &recinfo[0],
+ 0,(MARIA_UNIQUEDEF*) 0,
+ &create_info,create_flag))
+ goto err;
+ if (!(file=maria_open(filename,2,HA_OPEN_ABORT_IF_LOCKED)))
+ goto err;
+ maria_begin(file);
+ if (opt_versioning)
+ maria_versioning(file, 1);
+ if (testflag == 1)
+ goto end;
+ if (checkpoint == 1 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+ if (!silent)
+ printf("- Writing key:s\n");
+ if (do_locking)
+ maria_lock_database(file,F_WRLCK);
+ if (write_cacheing)
+ maria_extra(file,HA_EXTRA_WRITE_CACHE,0);
+ if (opt_quick_mode)
+ maria_extra(file,HA_EXTRA_QUICK,0);
+
+ for (i=0 ; i < recant ; i++)
+ {
+ ulong blob_length;
+ n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
+ sprintf((char*) record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
+ int4store(record+STANDARD_LENGTH-4,(long) i);
+ fix_length(record,(uint) STANDARD_LENGTH+rnd(60));
+ put_blob_in_record(record+blob_pos,&blob_buffer, &blob_length);
+ DBUG_PRINT("test",("record: %d blob_length: %lu", i, blob_length));
+
+ if (maria_write(file,record))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("Error: %d in write at record: %d\n",my_errno,i);
+ goto err;
+ }
+ if (verbose) printf(" Double key: %d at record# %d\n", n3, i);
+ }
+ else
+ {
+ if (key3[n3] == 1 && first_key <3 && first_key+keys >= 3)
+ {
+ printf("Error: Didn't get error when writing second key: '%8d'\n",n3);
+ goto err;
+ }
+ write_count++; key1[n1]++; key3[n3]=1;
+ }
+
+ /* Check if we can find key without flushing database */
+ if (i % 10 == 0)
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (!j)
+ for (j=999 ; j>0 && key1[j] == 0 ; j--) ;
+ sprintf((char*) key,"%6d",j);
+ if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
+ {
+ printf("Test in loop: Can't find key: \"%s\"\n",key);
+ goto err;
+ }
+ }
+ }
+ if (checkpoint == 2 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (write_cacheing)
+ {
+ if (maria_extra(file,HA_EXTRA_NO_CACHE,0))
+ {
+ puts("got error from maria_extra(HA_EXTRA_NO_CACHE)");
+ goto err;
+ }
+ }
+
+ if (testflag == 2)
+ goto end;
+
+#ifdef REMOVE_WHEN_WE_HAVE_RESIZE
+ if (pagecacheing)
+ resize_pagecache(maria_pagecache, maria_block_size,
+ pagecache_size * 2, 0, 0);
+#endif
+ if (!silent)
+ printf("- Delete\n");
+ if (srand_arg)
+ srand(srand_arg);
+ if (!update_count)
+ update_count= recant/10;
+
+ for (i=0 ; i < update_count ; i++)
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf((char*) key,"%6d",j);
+ if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ if (bcmp(read_record+keyinfo[0].seg[0].start,
+ key, keyinfo[0].seg[0].length))
+ {
+ printf("Found wrong record when searching for key: \"%s\"\n",key);
+ goto err;
+ }
+ if (opt_delete == (uint) remove_count) /* While testing */
+ goto end;
+ if (maria_delete(file,read_record))
+ {
+ printf("error: %d; can't delete record: \"%s\"\n", my_errno,read_record);
+ goto err;
+ }
+ opt_delete++;
+ key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--;
+ key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0;
+ }
+ else
+ puts("Warning: Skipping delete test because no dupplicate keys");
+ }
+ if (testflag == 3)
+ goto end;
+ if (checkpoint == 3 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (!silent)
+ printf("- Update\n");
+ if (srand_arg)
+ srand(srand_arg);
+ if (!update_count)
+ update_count= recant/10;
+
+ for (i=0 ; i < update_count ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(5000);
+ sprintf((char*) record2,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
+ int4store(record2+STANDARD_LENGTH-4,(long) i);
+ fix_length(record2,(uint) STANDARD_LENGTH+rnd(60));
+
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf((char*) key,"%6d",j);
+ if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
+ {
+ printf("can't find key1: \"%s\"\n", (char*) key);
+ goto err;
+ }
+ if (bcmp(read_record+keyinfo[0].seg[0].start,
+ key, keyinfo[0].seg[0].length))
+ {
+ printf("Found wrong record when searching for key: \"%s\"; Found \"%.*s\"\n",
+ key, keyinfo[0].seg[0].length,
+ read_record+keyinfo[0].seg[0].start);
+ goto err;
+ }
+ if (use_blob)
+ {
+ ulong blob_length;
+ if (i & 1)
+ put_blob_in_record(record2+blob_pos,&blob_buffer, &blob_length);
+ else
+ bmove(record2+blob_pos, read_record+blob_pos, 4 + sizeof(char*));
+ }
+ if (skip_update)
+ continue;
+ if (maria_update(file,read_record,record2))
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY || key3[n3] == 0)
+ {
+ printf("error: %d; can't update:\nFrom: \"%s\"\nTo: \"%s\"\n",
+ my_errno,read_record,record2);
+ goto err;
+ }
+ if (verbose)
+ printf("Double key when tried to update:\nFrom: \"%s\"\nTo: \"%s\"\n",record,record2);
+ }
+ else
+ {
+ key1[atoi((char*) read_record+keyinfo[0].seg[0].start)]--;
+ key3[atoi((char*) read_record+keyinfo[2].seg[0].start)]=0;
+ key1[n1]++; key3[n3]=1;
+ update++;
+ }
+ }
+ }
+ if (testflag == 4)
+ goto end;
+ if (checkpoint == 4 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ for (i=999, dupp_keys=j=0 ; i>0 ; i--)
+ {
+ if (key1[i] > dupp_keys)
+ {
+ dupp_keys=key1[i]; j=i;
+ }
+ }
+ sprintf((char*) key,"%6d",j);
+ start=keyinfo[0].seg[0].start;
+ length=keyinfo[0].seg[0].length;
+ if (dupp_keys)
+ {
+ if (!silent)
+ printf("- Same key: first - next -> last - prev -> first\n");
+ DBUG_PRINT("progpos",("first - next -> last - prev -> first"));
+ if (verbose) printf(" Using key: \"%s\" Keys: %d\n",key,dupp_keys);
+
+ if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
+ goto err;
+ if (maria_rsame(file,read_record2,-1))
+ goto err;
+ if (memcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("maria_rsame didn't find same record\n");
+ goto err;
+ }
+ info.recpos=maria_position(file);
+ if (maria_rfirst(file,read_record2,0) ||
+ maria_rsame_with_pos(file,read_record2,0,info.recpos) ||
+ memcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("maria_rsame_with_pos didn't find same record\n");
+ goto err;
+ }
+ {
+ int skr;
+ info.recpos= maria_position(file);
+ skr= maria_rnext(file,read_record2,0);
+ if ((skr && my_errno != HA_ERR_END_OF_FILE) ||
+ maria_rprev(file,read_record2,0) ||
+ memcmp(read_record,read_record2,reclength) != 0 ||
+ info.recpos != maria_position(file))
+ {
+ printf("maria_rsame_with_pos lost position\n");
+ goto err;
+ }
+ }
+ ant=1;
+ while (maria_rnext(file,read_record2,0) == 0 &&
+ memcmp(read_record2+start,key,length) == 0) ant++;
+ if (ant != dupp_keys)
+ {
+ printf("next: Found: %d keys of %d\n",ant,dupp_keys);
+ goto err;
+ }
+ ant=0;
+ while (maria_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys)
+ {
+ printf("prev: Found: %d records of %d\n",ant,dupp_keys);
+ goto err;
+ }
+
+ /* Check of maria_rnext_same */
+ if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
+ goto err;
+ ant=1;
+ while (!maria_rnext_same(file,read_record3) && ant < dupp_keys+10)
+ ant++;
+ if (ant != dupp_keys || my_errno != HA_ERR_END_OF_FILE)
+ {
+ printf("maria_rnext_same: Found: %d records of %d\n",ant,dupp_keys);
+ goto err;
+ }
+ }
+
+ if (!silent)
+ printf("- All keys: first - next -> last - prev -> first\n");
+ DBUG_PRINT("progpos",("All keys: first - next -> last - prev -> first"));
+ ant=1;
+ if (maria_rfirst(file,read_record,0))
+ {
+ printf("Can't find first record\n");
+ goto err;
+ }
+ while ((error=maria_rnext(file,read_record3,0)) == 0 && ant < write_count+10)
+ ant++;
+ if (ant != write_count - opt_delete || error != HA_ERR_END_OF_FILE)
+ {
+ printf("next: I found: %d records of %d (error: %d)\n",
+ ant, write_count - opt_delete, error);
+ goto err;
+ }
+ if (maria_rlast(file,read_record2,0) ||
+ bcmp(read_record2,read_record3,reclength))
+ {
+ printf("Can't find last record\n");
+ DBUG_DUMP("record2",(uchar*) read_record2,reclength);
+ DBUG_DUMP("record3",(uchar*) read_record3,reclength);
+ goto err;
+ }
+ ant=1;
+ while (maria_rprev(file,read_record3,0) == 0 && ant < write_count+10)
+ ant++;
+ if (ant != write_count - opt_delete)
+ {
+ printf("prev: I found: %d records of %d\n",ant,write_count);
+ goto err;
+ }
+ if (bcmp(read_record,read_record3,reclength))
+ {
+ printf("Can't find first record\n");
+ goto err;
+ }
+
+ if (!silent)
+ printf("- Test if: Read first - next - prev - prev - next == first\n");
+ DBUG_PRINT("progpos",("- Read first - next - prev - prev - next == first"));
+ if (maria_rfirst(file,read_record,0) ||
+ maria_rnext(file,read_record3,0) ||
+ maria_rprev(file,read_record3,0) ||
+ maria_rprev(file,read_record3,0) == 0 ||
+ maria_rnext(file,read_record3,0))
+ goto err;
+ if (bcmp(read_record,read_record3,reclength) != 0)
+ printf("Can't find first record\n");
+
+ if (!silent)
+ printf("- Test if: Read last - prev - next - next - prev == last\n");
+ DBUG_PRINT("progpos",("Read last - prev - next - next - prev == last"));
+ if (maria_rlast(file,read_record2,0) ||
+ maria_rprev(file,read_record3,0) ||
+ maria_rnext(file,read_record3,0) ||
+ maria_rnext(file,read_record3,0) == 0 ||
+ maria_rprev(file,read_record3,0))
+ goto err;
+ if (bcmp(read_record2,read_record3,reclength))
+ printf("Can't find last record\n");
+#ifdef NOT_ANYMORE
+ if (!silent)
+ puts("- Test read key-part");
+ strmov(key2,key);
+ for(i=strlen(key2) ; i-- > 1 ;)
+ {
+ key2[i]=0;
+
+ /* The following row is just to catch some bugs in the key code */
+ bzero((char*) file->lastkey,file->s->base.max_key_length*2);
+ if (maria_rkey(file,read_record,0,key2,(uint) i,HA_READ_PREFIX))
+ goto err;
+ if (bcmp(read_record+start,key,(uint) i))
+ {
+ puts("Didn't find right record");
+ goto err;
+ }
+ }
+#endif
+ if (dupp_keys > 2)
+ {
+ if (!silent)
+ printf("- Read key (first) - next - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - next - delete - next -> last"));
+ if (maria_rkey(file,read_record,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
+ goto err;
+ if (maria_rnext(file,read_record3,0)) goto err;
+ if (maria_delete(file,read_record3)) goto err;
+ opt_delete++;
+ ant=1;
+ while (maria_rnext(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-1)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-1);
+ goto err;
+ }
+ }
+ if (dupp_keys>4)
+ {
+ if (!silent)
+ printf("- Read last of key - prev - delete - prev -> first\n");
+ DBUG_PRINT("progpos",("last - prev - delete - prev -> first"));
+ if (maria_rprev(file,read_record3,0)) goto err;
+ if (maria_rprev(file,read_record3,0)) goto err;
+ if (maria_delete(file,read_record3)) goto err;
+ opt_delete++;
+ ant=1;
+ while (maria_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-2)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-2);
+ goto err;
+ }
+ }
+ if (dupp_keys > 6)
+ {
+ if (!silent)
+ printf("- Read first - delete - next -> last\n");
+ DBUG_PRINT("progpos",("first - delete - next -> last"));
+ if (maria_rkey(file,read_record3,0,key,HA_WHOLE_KEY,HA_READ_KEY_EXACT))
+ goto err;
+ if (maria_delete(file,read_record3)) goto err;
+ opt_delete++;
+ ant=1;
+ if (maria_rnext(file,read_record,0))
+ goto err; /* Skall finnas poster */
+ while (maria_rnext(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-3)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-3);
+ goto err;
+ }
+
+ if (!silent)
+ printf("- Read last - delete - prev -> first\n");
+ DBUG_PRINT("progpos",("last - delete - prev -> first"));
+ if (maria_rprev(file,read_record3,0)) goto err;
+ if (maria_delete(file,read_record3)) goto err;
+ opt_delete++;
+ ant=0;
+ while (maria_rprev(file,read_record3,0) == 0 &&
+ bcmp(read_record3+start,key,length) == 0) ant++;
+ if (ant != dupp_keys-4)
+ {
+ printf("next: I can only find: %d keys of %d\n",ant,dupp_keys-4);
+ goto err;
+ }
+ }
+
+ if (!silent)
+ puts("- Test if: Read rrnd - same");
+ DBUG_PRINT("progpos",("Read rrnd - same"));
+ assert(maria_scan_init(file) == 0);
+ for (i=0 ; i < write_count ; i++)
+ {
+ int tmp;
+ if ((tmp= maria_scan(file,read_record)) &&
+ tmp != HA_ERR_END_OF_FILE &&
+ tmp != HA_ERR_RECORD_DELETED)
+ {
+ printf("Got error %d when scanning table\n", tmp);
+ break;
+ }
+ if (!tmp)
+ {
+ /* Remember position to last found row */
+ info.recpos= maria_position(file);
+ bmove(read_record2,read_record,reclength);
+ }
+ }
+ maria_scan_end(file);
+ if (i != write_count && i != write_count - opt_delete)
+ {
+ printf("Found wrong number of rows while scanning table\n");
+ goto err;
+ }
+
+ if (maria_rsame_with_pos(file,read_record,0,info.recpos))
+ goto err;
+ if (bcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("maria_rsame_with_pos didn't find same record\n");
+ goto err;
+ }
+
+ for (i=min(2,keys) ; i-- > 0 ;)
+ {
+ if (maria_rsame(file,read_record2,(int) i)) goto err;
+ if (bcmp(read_record,read_record2,reclength) != 0)
+ {
+ printf("maria_rsame didn't find same record\n");
+ goto err;
+ }
+ }
+ if (!silent)
+ puts("- Test maria_records_in_range");
+ maria_status(file,&info,HA_STATUS_VARIABLE);
+ for (i=0 ; i < info.keys ; i++)
+ {
+ key_range min_key, max_key;
+ if (maria_rfirst(file,read_record,(int) i) ||
+ maria_rlast(file,read_record2,(int) i))
+ goto err;
+ copy_key(file,(uint) i,(uchar*) read_record,(uchar*) key);
+ copy_key(file,(uint) i,(uchar*) read_record2,(uchar*) key2);
+ min_key.key= key;
+ min_key.keypart_map= HA_WHOLE_KEY;
+ min_key.flag= HA_READ_KEY_EXACT;
+ max_key.key= key2;
+ max_key.keypart_map= HA_WHOLE_KEY;
+ max_key.flag= HA_READ_AFTER_KEY;
+
+ range_records= maria_records_in_range(file,(int) i, &min_key, &max_key);
+ if (range_records < info.records*8/10 ||
+ range_records > info.records*12/10)
+ {
+ printf("maria_records_range returned %ld; Should be about %ld\n",
+ (long) range_records,(long) info.records);
+ goto err;
+ }
+ if (verbose)
+ {
+ printf("maria_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n",
+ (long) range_records, (long) info.records,
+ labs((long) range_records - (long) info.records)*100.0/
+ info.records);
+ }
+ }
+ for (i=0 ; i < 5 ; i++)
+ {
+ for (j=rnd(1000)+1 ; j>0 && key1[j] == 0 ; j--) ;
+ for (k=rnd(1000)+1 ; k>0 && key1[k] == 0 ; k--) ;
+ if (j != 0 && k != 0)
+ {
+ key_range min_key, max_key;
+ if (j > k)
+ swap_variables(int, j, k);
+ sprintf((char*) key,"%6d",j);
+ sprintf((char*) key2,"%6d",k);
+
+ min_key.key= key;
+ min_key.keypart_map= HA_WHOLE_KEY;
+ min_key.flag= HA_READ_AFTER_KEY;
+ max_key.key= key2;
+ max_key.keypart_map= HA_WHOLE_KEY;
+ max_key.flag= HA_READ_BEFORE_KEY;
+ range_records= maria_records_in_range(file, 0, &min_key, &max_key);
+ records=0;
+ for (j++ ; j < k ; j++)
+ records+=key1[j];
+ if ((long) range_records < (long) records*7/10-2 ||
+ (long) range_records > (long) records*14/10+2)
+ {
+ printf("maria_records_range for key: %d returned %lu; Should be about %lu\n",
+ i, (ulong) range_records, (ulong) records);
+ goto err;
+ }
+ if (verbose && records)
+ {
+ printf("maria_records_range returned %lu; Exact is %lu (diff: %4.2g %%)\n",
+ (ulong) range_records, (ulong) records,
+ labs((long) range_records-(long) records)*100.0/records);
+
+ }
+ }
+ }
+
+ if (!silent)
+ printf("- maria_info\n");
+ maria_status(file,&info,HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (info.records != write_count-opt_delete || info.deleted > opt_delete + update
+ || info.keys != keys)
+ {
+ puts("Wrong info from maria_info");
+ printf("Got: records: %lu delete: %lu i_keys: %d\n",
+ (ulong) info.records, (ulong) info.deleted, info.keys);
+ goto err;
+ }
+ if (verbose)
+ {
+ char buff[80];
+ get_date(buff,3,info.create_time);
+ printf("info: Created %s\n",buff);
+ get_date(buff,3,info.check_time);
+ printf("info: checked %s\n",buff);
+ get_date(buff,3,info.update_time);
+ printf("info: Modified %s\n",buff);
+ }
+
+ maria_panic(HA_PANIC_WRITE);
+ maria_panic(HA_PANIC_READ);
+ if (maria_is_changed(file))
+ puts("Warning: maria_is_changed reported that datafile was changed");
+
+ if (!silent)
+ printf("- maria_extra(CACHE) + maria_rrnd.... + maria_extra(NO_CACHE)\n");
+ if (maria_reset(file) || maria_extra(file,HA_EXTRA_CACHE,0))
+ {
+ if (do_locking || (!use_blob && !pack_fields))
+ {
+ puts("got error from maria_extra(HA_EXTRA_CACHE)");
+ goto err;
+ }
+ }
+ ant=0;
+ assert(maria_scan_init(file) == 0);
+ while ((error= maria_scan(file,record)) != HA_ERR_END_OF_FILE &&
+ ant < write_count + 10)
+ ant+= error ? 0 : 1;
+ maria_scan_end(file);
+ if (ant != write_count-opt_delete)
+ {
+ printf("scan with cache: I can only find: %d records of %d\n",
+ ant,write_count-opt_delete);
+ maria_scan_end(file);
+ goto err;
+ }
+ if (maria_extra(file,HA_EXTRA_NO_CACHE,0))
+ {
+ puts("got error from maria_extra(HA_EXTRA_NO_CACHE)");
+ maria_scan_end(file);
+ goto err;
+ }
+ maria_scan_end(file);
+
+ ant=0;
+ maria_scan_init(file);
+ while ((error=maria_scan(file,record)) != HA_ERR_END_OF_FILE &&
+ ant < write_count + 10)
+ ant+= error ? 0 : 1;
+ if (ant != write_count-opt_delete)
+ {
+ printf("scan with cache: I can only find: %d records of %d\n",
+ ant,write_count-opt_delete);
+ maria_scan_end(file);
+ goto err;
+ }
+ maria_scan_end(file);
+
+ if (testflag == 5)
+ goto end;
+ if (checkpoint == 5 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+ if (!silent)
+ printf("- Removing keys\n");
+ DBUG_PRINT("progpos",("Removing keys"));
+ lastpos = HA_OFFSET_ERROR;
+ /* DBUG_POP(); */
+ maria_reset(file);
+ found_parts=0;
+ maria_scan_init(file);
+ while ((error= maria_scan(file,read_record)) != HA_ERR_END_OF_FILE)
+ {
+ info.recpos=maria_position(file);
+ if (lastpos >= info.recpos && lastpos != HA_OFFSET_ERROR)
+ {
+ printf("maria_rrnd didn't advance filepointer; old: %ld, new: %ld\n",
+ (long) lastpos, (long) info.recpos);
+ goto err;
+ }
+ lastpos=info.recpos;
+ if (error == 0)
+ {
+ if (opt_delete == (uint) remove_count) /* While testing */
+ goto end;
+ if (rnd(2) == 1 && maria_rsame(file,read_record,-1))
+ {
+ printf("can't find record %lx\n",(long) info.recpos);
+ goto err;
+ }
+ if (use_blob)
+ {
+ ulong blob_length,pos;
+ uchar *ptr;
+ memcpy_fixed(&ptr, read_record+blob_pos+4, sizeof(ptr));
+ blob_length= uint4korr(read_record+blob_pos);
+ for (pos=0 ; pos < blob_length ; pos++)
+ {
+ if (ptr[pos] != (uchar) (blob_length+pos))
+ {
+ printf("Found blob with wrong info at %ld\n",(long) lastpos);
+ maria_scan_end(file);
+ my_errno= 0;
+ goto err;
+ }
+ }
+ }
+ if (maria_delete(file,read_record))
+ {
+ printf("can't delete record: %6.6s, delete_count: %d\n",
+ read_record, opt_delete);
+ maria_scan_end(file);
+ goto err;
+ }
+ opt_delete++;
+ }
+ else
+ found_parts++;
+ }
+ if (my_errno != HA_ERR_END_OF_FILE && my_errno != HA_ERR_RECORD_DELETED)
+ printf("error: %d from maria_rrnd\n",my_errno);
+ if (write_count != opt_delete)
+ {
+ printf("Deleted only %d of %d records (%d parts)\n",opt_delete,write_count,
+ found_parts);
+ maria_scan_end(file);
+ goto err;
+ }
+ if (testflag == 6)
+ goto end;
+ if (checkpoint == 6 && ma_checkpoint_execute(CHECKPOINT_MEDIUM, FALSE))
+ goto err;
+
+end:
+ maria_scan_end(file);
+ if (die_in_middle_of_transaction)
+ {
+ /* As commit record is not done, UNDO entries needs to be rolled back */
+ switch (die_in_middle_of_transaction) {
+ case 1:
+ /*
+ Flush changed data and index pages go to disk
+ That will also flush log. Recovery will skip REDOs and apply UNDOs.
+ */
+ _ma_flush_table_files(file, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
+ FLUSH_RELEASE, FLUSH_RELEASE);
+ break;
+ case 2:
+ /*
+ Just flush log. Pages are likely to not be on disk. Recovery will
+ then execute REDOs and UNDOs.
+ */
+ if (translog_flush(file->trn->undo_lsn))
+ goto err;
+ break;
+ case 3:
+ /*
+ Flush nothing. Pages and log are likely to not be on disk. Recovery
+ will then do nothing.
+ */
+ break;
+ case 4:
+ /*
+ Flush changed data pages go to disk. Changed index pages are not
+ flushed. Recovery will skip some REDOs and apply UNDOs.
+ */
+ _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE,
+ FLUSH_RELEASE);
+ /*
+ We have to flush log separately as the redo for the last key page
+ may not be flushed
+ */
+ if (translog_flush(file->trn->undo_lsn))
+ goto err;
+ break;
+ }
+ printf("Dying on request without maria_commit()/maria_close()\n");
+ exit(0);
+ }
+ if (maria_commit(file))
+ goto err;
+ if (maria_close(file))
+ {
+ file= 0;
+ goto err;
+ }
+ file= 0;
+ maria_panic(HA_PANIC_CLOSE); /* Should close log */
+ if (!silent)
+ {
+ printf("\nFollowing test have been made:\n");
+ printf("Write records: %d\nUpdate records: %d\nSame-key-read: %d\nDelete records: %d\n", write_count,update,dupp_keys,opt_delete);
+ if (rec_pointer_size)
+ printf("Record pointer size: %d\n",rec_pointer_size);
+ printf("maria_block_size: %lu\n", maria_block_size);
+ if (write_cacheing)
+ puts("Key cache resized");
+ if (write_cacheing)
+ puts("Write cacheing used");
+ if (write_cacheing)
+ puts("quick mode");
+ if (async_io && do_locking)
+ puts("Asyncron io with locking used");
+ else if (do_locking)
+ puts("Locking used");
+ if (use_blob)
+ puts("blobs used");
+ printf("key cache status: \n\
+blocks used:%10lu\n\
+not flushed:%10lu\n\
+w_requests: %10lu\n\
+writes: %10lu\n\
+r_requests: %10lu\n\
+reads: %10lu\n",
+ maria_pagecache->blocks_used,
+ maria_pagecache->global_blocks_changed,
+ (ulong) maria_pagecache->global_cache_w_requests,
+ (ulong) maria_pagecache->global_cache_write,
+ (ulong) maria_pagecache->global_cache_r_requests,
+ (ulong) maria_pagecache->global_cache_read);
+ }
+ maria_end();
+ my_free(blob_buffer, MYF(MY_ALLOW_ZERO_PTR));
+ my_end(silent ? MY_CHECK_ERROR : MY_CHECK_ERROR | MY_GIVE_INFO);
+ return(0);
+err:
+ printf("got error: %d when using MARIA-database\n",my_errno);
+ if (file)
+ {
+ if (maria_commit(file))
+ goto err;
+ VOID(maria_close(file));
+ }
+ maria_end();
+ return(1);
+} /* main */
+
+
+/* Read options */
+
+static void get_options(int argc, char **argv)
+{
+ char *pos,*progname;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'B':
+ pack_type= HA_BINARY_PACK_KEY;
+ break;
+ case 'b':
+ use_blob= 1000;
+ if (*++pos)
+ use_blob= atol(pos);
+ break;
+ case 'K': /* Use key cacheing */
+ pagecacheing=1;
+ if (*++pos)
+ pagecache_size=atol(pos);
+ break;
+ case 'W': /* Use write cacheing */
+ write_cacheing=1;
+ if (*++pos)
+ my_default_record_cache_size=atoi(pos);
+ break;
+ case 'd':
+ remove_count= atoi(++pos);
+ break;
+ case 'i':
+ if (*++pos)
+ srand(srand_arg= atoi(pos));
+ break;
+ case 'L':
+ do_locking=1;
+ break;
+ case 'a': /* use asyncron io */
+ async_io=1;
+ if (*++pos)
+ my_default_record_cache_size=atoi(pos);
+ break;
+ case 'v': /* verbose */
+ verbose=1;
+ break;
+ case 'm': /* records */
+ if ((recant=atoi(++pos)) < 10 && testflag > 2)
+ {
+ fprintf(stderr,"record count must be >= 10 (if testflag > 2)\n");
+ exit(1);
+ }
+ break;
+ case 'e': /* maria_block_length */
+ case 'E':
+ if ((maria_block_size= atoi(++pos)) < MARIA_MIN_KEY_BLOCK_LENGTH ||
+ maria_block_size > MARIA_MAX_KEY_BLOCK_LENGTH)
+ {
+ fprintf(stderr,"Wrong maria_block_length\n");
+ exit(1);
+ }
+ maria_block_size= my_round_up_to_next_power(maria_block_size);
+ break;
+ case 'f':
+ if ((first_key=atoi(++pos)) < 0 || first_key >= MARIA_KEYS)
+ first_key=0;
+ break;
+ case 'H':
+ checkpoint= atoi(++pos);
+ break;
+ case 'k':
+ if ((keys=(uint) atoi(++pos)) < 1 ||
+ keys > (uint) (MARIA_KEYS-first_key))
+ keys=MARIA_KEYS-first_key;
+ break;
+ case 'M':
+ record_type= BLOCK_RECORD;
+ break;
+ case 'P':
+ pack_type=0; /* Don't use DIFF_LENGTH */
+ pack_seg=0;
+ break;
+ case 'R': /* Length of record pointer */
+ rec_pointer_size=atoi(++pos);
+ if (rec_pointer_size > 7)
+ rec_pointer_size=0;
+ break;
+ case 'S':
+ pack_fields=0; /* Static-length-records */
+ record_type= STATIC_RECORD;
+ break;
+ case 's':
+ silent=1;
+ break;
+ case 't':
+ testflag=atoi(++pos); /* testmod */
+ break;
+ case 'T':
+ transactional= 1;
+ break;
+ case 'A':
+ die_in_middle_of_transaction= atoi(++pos);
+ break;
+ case 'u':
+ update_count=atoi(++pos);
+ if (!update_count)
+ skip_update= 1;
+ break;
+ case 'q':
+ opt_quick_mode=1;
+ break;
+ case 'c':
+ create_flag|= HA_CREATE_CHECKSUM | HA_CREATE_PAGE_CHECKSUM;
+ break;
+ case 'D':
+ create_flag|=HA_CREATE_DELAY_KEY_WRITE;
+ break;
+ case 'g':
+ skip_update= TRUE;
+ break;
+ case 'C':
+ opt_versioning= 1;
+ break;
+ case '?':
+ case 'I':
+ case 'V':
+ printf("%s Ver 1.2 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("By Monty, for testing Maria\n");
+ printf("Usage: %s [-?AbBcCDIKLPRqSsTVWltv] [-k#] [-f#] [-m#] [-e#] [-E#] [-t#]\n",
+ progname);
+ exit(0);
+ case '#':
+ DBUG_PUSH (++pos);
+ break;
+ default:
+ printf("Illegal option: '%c'\n",*pos);
+ break;
+ }
+ }
+ return;
+} /* get options */
+
+ /* Get a random value 0 <= x <= n */
+
+static uint rnd(uint max_value)
+{
+ return (uint) ((rand() & 32767)/32767.0*max_value);
+} /* rnd */
+
+
+ /* Create a variable length record */
+
+static void fix_length(uchar *rec, uint length)
+{
+ bmove(rec+STANDARD_LENGTH,
+ "0123456789012345678901234567890123456789012345678901234567890",
+ length-STANDARD_LENGTH);
+ strfill((char*) rec+length,STANDARD_LENGTH+60-length,' ');
+} /* fix_length */
+
+
+/* Put maybe a blob in record */
+
+static int first_entry;
+
+static void put_blob_in_record(uchar *blob_pos, char **blob_buffer,
+ ulong *blob_length)
+{
+ ulong i,length;
+ *blob_length= 0;
+ if (use_blob)
+ {
+ if (! *blob_buffer &&
+ !(*blob_buffer=my_malloc((uint) use_blob,MYF(MY_WME))))
+ {
+ use_blob= 0;
+ return;
+ }
+ if (rnd(10) == 0)
+ {
+ if (first_entry++ == 0)
+ {
+ /* Ensure we have at least one blob of max length in file */
+ length= use_blob;
+ }
+ else
+ length=rnd(use_blob);
+ for (i=0 ; i < length ; i++)
+ (*blob_buffer)[i]=(char) (length+i);
+ int4store(blob_pos,length);
+ memcpy_fixed(blob_pos+4,(char*) blob_buffer,sizeof(char*));
+ *blob_length= length;
+ }
+ else
+ {
+ int4store(blob_pos,0);
+ }
+ }
+ return;
+}
+
+
+static void copy_key(MARIA_HA *info,uint inx,uchar *rec,uchar *key_buff)
+{
+ HA_KEYSEG *keyseg;
+
+ for (keyseg=info->s->keyinfo[inx].seg ; keyseg->type ; keyseg++)
+ {
+ memcpy(key_buff,rec+keyseg->start,(size_t) keyseg->length);
+ key_buff+=keyseg->length;
+ }
+ return;
+}
diff --git a/storage/maria/ma_test3.c b/storage/maria/ma_test3.c
new file mode 100644
index 00000000000..8dd631380a0
--- /dev/null
+++ b/storage/maria/ma_test3.c
@@ -0,0 +1,501 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Test av locking */
+
+#if !(defined (__NETWARE_) || defined (_WIN32)) /*no fork() in Windows*/
+
+#include "maria.h"
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+
+#if defined(HAVE_LRAND48)
+#define rnd(X) (lrand48() % X)
+#define rnd_init(X) srand48(X)
+#else
+#define rnd(X) (random() % X)
+#define rnd_init(X) srandom(X)
+#endif
+
+
+const char *filename= "test3";
+uint tests=10,forks=10,pagecacheing=0;
+
+static void get_options(int argc, char *argv[]);
+void start_test(int id);
+int test_read(MARIA_HA *,int),test_write(MARIA_HA *,int,int),
+ test_update(MARIA_HA *,int,int),test_rrnd(MARIA_HA *,int);
+
+struct record {
+ uchar id[8];
+ uchar nr[4];
+ uchar text[10];
+} record;
+
+
+int main(int argc,char **argv)
+{
+ int status,wait_ret;
+ uint i=0;
+ MARIA_KEYDEF keyinfo[10];
+ MARIA_COLUMNDEF recinfo[10];
+ HA_KEYSEG keyseg[10][2];
+ MY_INIT(argv[0]);
+ get_options(argc,argv);
+
+ fprintf(stderr, "WARNING! this program is to test 'external locking'"
+ " (when several processes share a table through file locking)"
+ " which is not supported by Maria at all; expect errors."
+ " We may soon remove this program.\n");
+ maria_init();
+ bzero((char*) keyinfo,sizeof(keyinfo));
+ bzero((char*) recinfo,sizeof(recinfo));
+ bzero((char*) keyseg,sizeof(keyseg));
+ keyinfo[0].seg= &keyseg[0][0];
+ keyinfo[0].seg[0].start=0;
+ keyinfo[0].seg[0].length=8;
+ keyinfo[0].seg[0].type=HA_KEYTYPE_TEXT;
+ keyinfo[0].seg[0].flag=HA_SPACE_PACK;
+ keyinfo[0].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[0].keysegs=1;
+ keyinfo[0].flag = (uint8) HA_PACK_KEY;
+ keyinfo[0].block_length= 0; /* Default block length */
+ keyinfo[1].seg= &keyseg[1][0];
+ keyinfo[1].seg[0].start=8;
+ keyinfo[1].seg[0].length=4; /* Long is always 4 in maria */
+ keyinfo[1].seg[0].type=HA_KEYTYPE_LONG_INT;
+ keyinfo[1].seg[0].flag=0;
+ keyinfo[1].key_alg=HA_KEY_ALG_BTREE;
+ keyinfo[1].keysegs=1;
+ keyinfo[1].flag =HA_NOSAME;
+ keyinfo[1].block_length= 0; /* Default block length */
+
+ recinfo[0].type=0;
+ recinfo[0].length=sizeof(record.id);
+ recinfo[1].type=0;
+ recinfo[1].length=sizeof(record.nr);
+ recinfo[2].type=0;
+ recinfo[2].length=sizeof(record.text);
+
+ puts("- Creating maria-file");
+ my_delete(filename,MYF(0)); /* Remove old locks under gdb */
+ if (maria_create(filename,BLOCK_RECORD, 2, &keyinfo[0],2,&recinfo[0],0,
+ (MARIA_UNIQUEDEF*) 0, (MARIA_CREATE_INFO*) 0,0))
+ exit(1);
+
+ rnd_init(0);
+ printf("- Starting %d processes\n",forks); fflush(stdout);
+ for (i=0 ; i < forks; i++)
+ {
+ if (!fork())
+ {
+ start_test(i+1);
+ sleep(1);
+ return 0;
+ }
+ VOID(rnd(1));
+ }
+
+ for (i=0 ; i < forks ; i++)
+ while ((wait_ret=wait(&status)) && wait_ret == -1);
+ maria_end();
+ return 0;
+}
+
+
+static void get_options(int argc, char **argv)
+{
+ char *pos,*progname;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'f':
+ forks=atoi(++pos);
+ break;
+ case 't':
+ tests=atoi(++pos);
+ break;
+ case 'K': /* Use key cacheing */
+ pagecacheing=1;
+ break;
+ case 'A': /* All flags */
+ pagecacheing=1;
+ break;
+ case '?':
+ case 'I':
+ case 'V':
+ printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("By Monty, for your professional use\n");
+ puts("Test av locking with threads\n");
+ printf("Usage: %s [-?lKA] [-f#] [-t#]\n",progname);
+ exit(0);
+ case '#':
+ DBUG_PUSH (++pos);
+ break;
+ default:
+ printf("Illegal option: '%c'\n",*pos);
+ break;
+ }
+ }
+ return;
+}
+
+
+void start_test(int id)
+{
+ uint i;
+ int error,lock_type;
+ MARIA_INFO isam_info;
+ MARIA_HA *file,*file1,*file2=0,*lock;
+
+ if (!(file1=maria_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)) ||
+ !(file2=maria_open(filename,O_RDWR,HA_OPEN_WAIT_IF_LOCKED)))
+ {
+ fprintf(stderr,"Can't open isam-file: %s\n",filename);
+ exit(1);
+ }
+ if (pagecacheing && rnd(2) == 0)
+ init_pagecache(maria_pagecache, 65536L, 0, 0, MARIA_KEY_BLOCK_LENGTH,
+ MY_WME);
+ printf("Process %d, pid: %d\n",id,getpid()); fflush(stdout);
+
+ for (error=i=0 ; i < tests && !error; i++)
+ {
+ file= (rnd(2) == 1) ? file1 : file2;
+ lock=0 ; lock_type=0;
+ if (rnd(10) == 0)
+ {
+ if (maria_lock_database(lock=(rnd(2) ? file1 : file2),
+ lock_type=(rnd(2) == 0 ? F_RDLCK : F_WRLCK)))
+ {
+ fprintf(stderr,"%2d: start: Can't lock table %d\n",id,my_errno);
+ error=1;
+ break;
+ }
+ }
+ switch (rnd(4)) {
+ case 0: error=test_read(file,id); break;
+ case 1: error=test_rrnd(file,id); break;
+ case 2: error=test_write(file,id,lock_type); break;
+ case 3: error=test_update(file,id,lock_type); break;
+ }
+ if (lock)
+ maria_lock_database(lock,F_UNLCK);
+ }
+ if (!error)
+ {
+ maria_status(file1,&isam_info,HA_STATUS_VARIABLE);
+ printf("%2d: End of test. Records: %ld Deleted: %ld\n",
+ id,(long) isam_info.records, (long) isam_info.deleted);
+ fflush(stdout);
+ }
+
+ maria_close(file1);
+ maria_close(file2);
+ if (error)
+ {
+ printf("%2d: Aborted\n",id); fflush(stdout);
+ exit(1);
+ }
+}
+
+
+int test_read(MARIA_HA *file,int id)
+{
+ uint i,lock,found,next,prev;
+ ulong find;
+
+ lock=0;
+ if (rnd(2) == 0)
+ {
+ lock=1;
+ if (maria_lock_database(file,F_RDLCK))
+ {
+ fprintf(stderr,"%2d: Can't lock table %d\n",id,my_errno);
+ return 1;
+ }
+ }
+
+ found=next=prev=0;
+ for (i=0 ; i < 100 ; i++)
+ {
+ find=rnd(100000);
+ if (!maria_rkey(file,record.id,1,(uchar*) &find, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
+ found++;
+ else
+ {
+ if (my_errno != HA_ERR_KEY_NOT_FOUND)
+ {
+ fprintf(stderr,"%2d: Got error %d from read in read\n",id,my_errno);
+ return 1;
+ }
+ else if (!maria_rnext(file,record.id,1))
+ next++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in read\n",id,my_errno);
+ return 1;
+ }
+ else if (!maria_rprev(file,record.id,1))
+ prev++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in read\n",
+ id,my_errno);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ if (lock)
+ {
+ if (maria_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ return 1;
+ }
+ }
+ printf("%2d: read: found: %5d next: %5d prev: %5d\n",
+ id,found,next,prev);
+ fflush(stdout);
+ return 0;
+}
+
+
+int test_rrnd(MARIA_HA *file,int id)
+{
+ uint count,lock;
+
+ lock=0;
+ if (rnd(2) == 0)
+ {
+ lock=1;
+ if (maria_lock_database(file,F_RDLCK))
+ {
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ maria_close(file);
+ return 1;
+ }
+ if (rnd(2) == 0)
+ maria_extra(file,HA_EXTRA_CACHE,0);
+ }
+
+ count=0;
+ if (maria_rrnd(file,record.id,0L))
+ {
+ if (my_errno == HA_ERR_END_OF_FILE)
+ goto end;
+ fprintf(stderr,"%2d: Can't read first record (%d)\n",id,my_errno);
+ return 1;
+ }
+ for (count=1 ; !maria_rrnd(file,record.id,HA_OFFSET_ERROR) ;count++) ;
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rrnd\n",id,my_errno);
+ return 1;
+ }
+
+end:
+ if (lock)
+ {
+ maria_extra(file,HA_EXTRA_NO_CACHE,0);
+ if (maria_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ exit(0);
+ }
+ }
+ printf("%2d: rrnd: %5d\n",id,count); fflush(stdout);
+ return 0;
+}
+
+
+int test_write(MARIA_HA *file,int id,int lock_type)
+{
+ uint i,tries,count,lock;
+
+ lock=0;
+ if (rnd(2) == 0 || lock_type == F_RDLCK)
+ {
+ lock=1;
+ if (maria_lock_database(file,F_WRLCK))
+ {
+ if (lock_type == F_RDLCK && my_errno == EDEADLK)
+ {
+ printf("%2d: write: deadlock\n",id); fflush(stdout);
+ return 0;
+ }
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ maria_close(file);
+ return 1;
+ }
+ if (rnd(2) == 0)
+ maria_extra(file,HA_EXTRA_WRITE_CACHE,0);
+ }
+
+ sprintf((char*) record.id,"%7d",getpid());
+ strnmov((char*) record.text,"Testing...", sizeof(record.text));
+
+ tries=(uint) rnd(100)+10;
+ for (i=count=0 ; i < tries ; i++)
+ {
+ uint32 tmp=rnd(80000)+20000;
+ int4store(record.nr,tmp);
+ if (!maria_write(file,record.id))
+ count++;
+ else
+ {
+ if (my_errno != HA_ERR_FOUND_DUPP_KEY)
+ {
+ fprintf(stderr,"%2d: Got error %d (errno %d) from write\n",id,my_errno,
+ errno);
+ return 1;
+ }
+ }
+ }
+ if (lock)
+ {
+ maria_extra(file,HA_EXTRA_NO_CACHE,0);
+ if (maria_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"%2d: Can't unlock table\n",id);
+ exit(0);
+ }
+ }
+ printf("%2d: write: %5d\n",id,count); fflush(stdout);
+ return 0;
+}
+
+
+int test_update(MARIA_HA *file,int id,int lock_type)
+{
+ uint i,lock,found,next,prev,update;
+ uint32 tmp;
+ char find[4];
+ struct record new_record;
+
+ lock=0;
+ if (rnd(2) == 0 || lock_type == F_RDLCK)
+ {
+ lock=1;
+ if (maria_lock_database(file,F_WRLCK))
+ {
+ if (lock_type == F_RDLCK && my_errno == EDEADLK)
+ {
+ printf("%2d: write: deadlock\n",id); fflush(stdout);
+ return 0;
+ }
+ fprintf(stderr,"%2d: Can't lock table (%d)\n",id,my_errno);
+ return 1;
+ }
+ }
+ bzero((char*) &new_record,sizeof(new_record));
+ strmov((char*) new_record.text,"Updated");
+
+ found=next=prev=update=0;
+ for (i=0 ; i < 100 ; i++)
+ {
+ tmp=rnd(100000);
+ int4store(find,tmp);
+ if (!maria_rkey(file,record.id,1,(uchar*) find, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
+ found++;
+ else
+ {
+ if (my_errno != HA_ERR_KEY_NOT_FOUND)
+ {
+ fprintf(stderr,"%2d: Got error %d from read in update\n",id,my_errno);
+ return 1;
+ }
+ else if (!maria_rnext(file,record.id,1))
+ next++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in update\n",
+ id,my_errno);
+ return 1;
+ }
+ else if (!maria_rprev(file,record.id,1))
+ prev++;
+ else
+ {
+ if (my_errno != HA_ERR_END_OF_FILE)
+ {
+ fprintf(stderr,"%2d: Got error %d from rnext in update\n",
+ id,my_errno);
+ return 1;
+ }
+ continue;
+ }
+ }
+ }
+ memcpy_fixed(new_record.id,record.id,sizeof(record.id));
+ tmp=rnd(20000)+40000;
+ int4store(new_record.nr,tmp);
+ if (!maria_update(file,record.id,new_record.id))
+ update++;
+ else
+ {
+ if (my_errno != HA_ERR_RECORD_CHANGED &&
+ my_errno != HA_ERR_RECORD_DELETED &&
+ my_errno != HA_ERR_FOUND_DUPP_KEY)
+ {
+ fprintf(stderr,"%2d: Got error %d from update\n",id,my_errno);
+ return 1;
+ }
+ }
+ }
+ if (lock)
+ {
+ if (maria_lock_database(file,F_UNLCK))
+ {
+ fprintf(stderr,"Can't unlock table,id, error%d\n",my_errno);
+ return 1;
+ }
+ }
+ printf("%2d: update: %5d\n",id,update); fflush(stdout);
+ return 0;
+}
+
+#else /* __NETWARE__ || __WIN__ */
+
+#include <stdio.h>
+
+int main()
+{
+ fprintf(stderr,"this test has not been ported to Netware or Windows\n");
+ return 0;
+}
+
+#endif /* __NETWARE__|| __WIN__ */
diff --git a/storage/maria/ma_test_all.res b/storage/maria/ma_test_all.res
new file mode 100644
index 00000000000..586aaf68020
--- /dev/null
+++ b/storage/maria/ma_test_all.res
@@ -0,0 +1,14 @@
+Running tests with dynamic row format
+Running tests with static row format
+Running tests with block row format
+Running tests with block row format and transactions
+ma_test2 -s -L -K -R1 -m2000 ; Should give error 135
+Error: 135 in write at record: 1099
+got error: 135 when using MARIA-database
+./maria_chk -sm test2 will warn that 'Datafile is almost full'
+maria_chk: MARIA file test2
+maria_chk: warning: Datafile is almost full, 65516 of 65534 used
+MARIA-table 'test2' is usable but should be fixed
+MARIA RECOVERY TESTS
+ALL RECOVERY TESTS OK
+!!!!!!!! BUT REMEMBER to FIX this BLOB issue !!!!!!!
diff --git a/storage/maria/ma_test_all.sh b/storage/maria/ma_test_all.sh
new file mode 100755
index 00000000000..041fbf3abe6
--- /dev/null
+++ b/storage/maria/ma_test_all.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# This file is now deprecated and has been replaced by
+# unittest/ma_test_all-t
+#
+#
+#
+#
+
+if test -n "$1"; then
+
+ # unit.pl can't pass options to ma_test_all-t, so if anything
+ # was passed as an argument, assume the purpose was to pass
+ # them to ma_test_all-t and call it directly
+
+ unittest/ma_test_all-t $@
+else
+ perl ../../unittest/unit.pl run unittest/ma_test_all-t
+fi
diff --git a/storage/maria/ma_test_big.sh b/storage/maria/ma_test_big.sh
new file mode 100644
index 00000000000..6419d05e3a4
--- /dev/null
+++ b/storage/maria/ma_test_big.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# This tests is good to find bugs in the redo/undo handling and in
+# finding bugs in blob handling
+#
+
+set -e
+a=15
+while test $a -le 5000
+do
+ echo $a
+ rm -f maria_log*
+ ma_test2 -s -L -K -W -P -M -T -c -b32768 -t4 -A1 -m$a > /dev/null
+ maria_read_log -a -s >& /dev/null
+ maria_chk -es test2
+ maria_read_log -a -s >& /dev/null
+ maria_chk -es test2
+ rm test2.MA?
+ maria_read_log -a -s >& /dev/null
+ maria_chk -es test2
+ a=$((a+1))
+done
diff --git a/storage/maria/ma_test_force_start.pl b/storage/maria/ma_test_force_start.pl
new file mode 100755
index 00000000000..3aa6da5f5dc
--- /dev/null
+++ b/storage/maria/ma_test_force_start.pl
@@ -0,0 +1,237 @@
+#!/usr/bin/env perl
+
+
+use strict;
+use warnings;
+
+my $usage= <<EOF;
+This program tests that the options
+--maria-force-start-after-recovery-failures --maria-recover work as
+expected.
+It has to be run from directory mysql-test, and works with non-debug
+and debug binaries.
+Pass it option -d or -i (to test corruption of data or index file).
+EOF
+
+# -d currently exhibits BUG#36578
+# "Maria: maria-recover may fail to autorepair a table"
+
+die($usage) if (@ARGV == 0);
+
+my $corrupt_index;
+
+if ($ARGV[0] eq '-d')
+ {
+ $corrupt_index= 0;
+ }
+elsif ($ARGV[0] eq '-i')
+ {
+ $corrupt_index= 1;
+ }
+else
+ {
+ die($usage);
+ }
+
+my $force_after= 3;
+my $corrupt_file= $corrupt_index ? "MAI" : "MAD";
+my $corrupt_message=
+ "\\[ERROR\\] mysqld(.exe)*: Table '..test.t1' is marked as crashed and should be repaired";
+
+my $sql_name= "./var/tmp/create_table.sql";
+my $error_log_name= "./var/log/master.err";
+my @cmd_output;
+my $whatever; # garbage data
+my $base_server_cmd= "perl mysql-test-run.pl --mysqld=--maria-force-start-after-recovery-failures=$force_after maria-recover ";
+if ($^O =~ /^mswin/i)
+ {
+ print <<EOF;
+WARNING: with Activestate Perl, mysql-test-run.pl --start-and-exit has a bug:
+it does not exit; cygwin perl recommended
+EOF
+ }
+my $iswindows= ( $^O =~ /win/i && $^O !~ /darwin/i );
+$base_server_cmd.= ($iswindows ? "--mysqld=--console" : "--mem");
+my $server_cmd;
+my $server_pid_name="./var/run/master.pid";
+my $server_pid;
+my $i; # count of server restarts
+sub kill_server;
+
+my $suffix= ($iswindows ? ".exe" : "");
+my $client_exe_path= "../client/release";
+# we use -f, sometimes -x is unexpectedly false in Cygwin
+if ( ! -f "$client_exe_path/mysql$suffix" )
+ {
+ $client_exe_path= "../client/relwithdebinfo";
+ if ( ! -f "$client_exe_path/mysql$suffix" )
+ {
+ $client_exe_path= "../client/debug";
+ if ( ! -f "$client_exe_path/mysql$suffix" )
+ {
+ $client_exe_path= "../client";
+ if ( ! -f "$client_exe_path/mysql$suffix" )
+ {
+ die("Cannot find 'mysql' executable\n");
+ }
+ }
+ }
+ }
+
+print "starting mysqld\n";
+$server_cmd= $base_server_cmd . " --start-and-exit 2>&1";
+@cmd_output=`$server_cmd`;
+die if $?;
+my $master_port= (grep (/Using MASTER_MYPORT .*= (\d+)$/, @cmd_output))[0];
+$master_port =~ s/.*= //;
+chomp $master_port;
+die unless $master_port > 0;
+
+my $client_cmd= "$client_exe_path/mysql -u root -h 127.0.0.1 -P $master_port test < $sql_name";
+
+open(FILE, ">", $sql_name) or die;
+
+# To exhibit BUG#36578 with -d, we don't create an index if -d. This is
+# because the presence of an index will cause repair-by-sort to be used,
+# where sort_get_next_record() is only called inside
+#_ma_create_index_by_sort(), so the latter function fails and in this
+# case retry_repair is set, so bug does not happen. Whereas without
+# an index, repair-with-key-cache is called, which calls
+# sort_get_next_record() whose failure itself does not cause a retry.
+
+print FILE "create table t1 (a varchar(1000)".
+ ($corrupt_index ? ", index(a)" : "") .") engine=maria;\n";
+print FILE <<EOF;
+insert into t1 values("ThursdayMorningsMarket");
+# If Recovery executes REDO_INDEX_NEW_PAGE it will overwrite our
+# intentional corruption; we make Recovery skip this record by bumping
+# create_rename_lsn using OPTIMIZE TABLE. This also makes sure to put
+# the pages on disk, so that we can corrupt them.
+optimize table t1;
+# mark table open, so that --maria-recover repairs it
+insert into t1 select concat(a,'b') from t1 limit 1;
+EOF
+close FILE;
+
+print "creating table\n";
+`$client_cmd`;
+die if $?;
+
+print "killing mysqld hard\n";
+kill_server(9);
+
+print "ruining " .
+ ($corrupt_index ? "first page of keys" : "bitmap page") .
+ " in table to test maria-recover\n";
+open(FILE, "+<", "./var/master-data/test/t1.$corrupt_file") or die;
+$whatever= ("\xAB" x 100);
+sysseek (FILE, $corrupt_index ? 8192 : (8192-100-100), 0) or die;
+syswrite (FILE, $whatever) or die;
+close FILE;
+
+print "ruining log to make recovery fail; mysqld should fail the $force_after first restarts\n";
+open(FILE, "+<", "./var/tmp/maria_log.00000001") or die;
+$whatever= ("\xAB" x 8192);
+sysseek (FILE, 99, 0) or die;
+syswrite (FILE, $whatever) or die;
+close FILE;
+
+$server_cmd= $base_server_cmd . " --start-dirty 2>&1";
+for($i= 1; $i <= $force_after; $i= $i + 1)
+ {
+ print "mysqld restart number $i... ";
+ unlink($error_log_name) or die;
+ `$server_cmd`;
+ # mysqld should return 1 when can't read log
+ die unless (($? >> 8) == 1);
+ open(FILE, "<", $error_log_name) or die;
+ @cmd_output= <FILE>;
+ close FILE;
+ die unless grep(/\[ERROR\] mysqld(.exe)*: Maria engine: log initialization failed/, @cmd_output);
+ die unless grep(/\[ERROR\] Plugin 'MARIA' init function returned error./, @cmd_output);
+ print "failed - ok\n";
+ }
+
+print "mysqld restart number $i... ";
+unlink($error_log_name) or die;
+@cmd_output=`$server_cmd`;
+die if $?;
+open(FILE, "<", $error_log_name) or die;
+@cmd_output= <FILE>;
+close FILE;
+die unless grep(/\[Warning\] mysqld(.exe)*: Maria engine: removed all logs after [\d]+ consecutive failures of recovery from logs/, @cmd_output);
+die unless grep(/\[ERROR\] mysqld(.exe)*: File '.*tmp.maria_log.00000001' not found \(Errcode: 2\)/, @cmd_output);
+print "success - ok\n";
+
+open(FILE, ">", $sql_name) or die;
+print FILE <<EOF;
+set global maria_recover=normal;
+insert into t1 values('aaa');
+EOF
+close FILE;
+
+# verify corruption has not yet been noticed
+open(FILE, "<", $error_log_name) or die;
+@cmd_output= <FILE>;
+close FILE;
+die if grep(/$corrupt_message/, @cmd_output);
+
+print "inserting in table\n";
+`$client_cmd`;
+die if $?;
+print "table is usable - ok\n";
+
+open(FILE, "<", $error_log_name) or die;
+@cmd_output= <FILE>;
+close FILE;
+die unless grep(/$corrupt_message/, @cmd_output);
+die unless grep(/\[Warning\] Recovering table: '..test.t1'/, @cmd_output);
+print "was corrupted and automatically repaired - ok\n";
+
+# remove our traces
+kill_server(15);
+
+print "TEST ALL OK\n";
+
+# kills mysqld with signal given in parameter
+sub kill_server
+ {
+ my ($sig)= @_;
+ my $wait_count= 0;
+ my $kill_cmd;
+ my @kill_output;
+ open(FILE, "<", $server_pid_name) or die;
+ @cmd_output= <FILE>;
+ close FILE;
+ $server_pid= $cmd_output[0];
+ chomp $server_pid;
+ die unless $server_pid > 0;
+ if ($iswindows)
+ {
+ # On Windows, server_pid_name is not the "main" process id
+ # so perl's kill() does not see this process id.
+ # But taskkill works, though only with /F ("-9"-style kill).
+ $kill_cmd= "taskkill /F /PID $server_pid 2>&1";
+ @kill_output= `$kill_cmd`;
+ die unless grep(/has been terminated/, @kill_output);
+ }
+ else
+ {
+ kill($sig, $server_pid) or die;
+ }
+ while (1) # wait until mysqld process gone
+ {
+ if ($iswindows)
+ {
+ @kill_output= `$kill_cmd`;
+ last if grep(/not found/, @kill_output);
+ }
+ else
+ {
+ kill (0, $server_pid) or last;
+ }
+ print "waiting for mysqld to die\n" if ($wait_count > 30);
+ $wait_count= $wait_count + 1;
+ select(undef, undef, undef, 0.1);
+ }
+ }
diff --git a/storage/maria/ma_test_recovery b/storage/maria/ma_test_recovery
new file mode 100755
index 00000000000..0b20264c434
--- /dev/null
+++ b/storage/maria/ma_test_recovery
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# Remove comment from next line if this script fails and you need more
+# information of what's going on
+
+# This file is deprecated and has been replaced with ma_test_recovery.pl
+
+unittest/ma_test_recovery.pl $@
diff --git a/storage/maria/ma_unique.c b/storage/maria/ma_unique.c
new file mode 100644
index 00000000000..bae58fd70cd
--- /dev/null
+++ b/storage/maria/ma_unique.c
@@ -0,0 +1,245 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Functions to check if a row is unique */
+
+#include "maria_def.h"
+#include <m_ctype.h>
+
+/**
+ Check if there exist a row with the same hash
+
+ @notes
+ This function is not versioning safe. For the moment this is not a problem
+ as it's only used for internal temporary tables in MySQL for which there
+ isn't any versioning information.
+*/
+
+my_bool _ma_check_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, uchar *record,
+ ha_checksum unique_hash, my_off_t disk_pos)
+{
+ my_off_t lastpos=info->cur_row.lastpos;
+ MARIA_KEYDEF *keyinfo= &info->s->keyinfo[def->key];
+ uchar *key_buff= info->lastkey_buff2;
+ MARIA_KEY key;
+ DBUG_ENTER("_ma_check_unique");
+ DBUG_PRINT("enter",("unique_hash: %lu", (ulong) unique_hash));
+
+ maria_unique_store(record+keyinfo->seg->start, unique_hash);
+ /* Can't be spatial so it's ok to call _ma_make_key directly here */
+ _ma_make_key(info, &key, def->key, key_buff, record, 0, 0);
+
+ /* The above changed info->lastkey_buff2. Inform maria_rnext_same(). */
+ info->update&= ~HA_STATE_RNEXT_SAME;
+
+ DBUG_ASSERT(key.data_length == MARIA_UNIQUE_HASH_LENGTH);
+ if (_ma_search(info, &key, SEARCH_FIND, info->s->state.key_root[def->key]))
+ {
+ info->page_changed=1; /* Can't optimize read next */
+ info->cur_row.lastpos= lastpos;
+ DBUG_RETURN(0); /* No matching rows */
+ }
+
+ for (;;)
+ {
+ if (info->cur_row.lastpos != disk_pos &&
+ !(*info->s->compare_unique)(info,def,record,info->cur_row.lastpos))
+ {
+ my_errno=HA_ERR_FOUND_DUPP_UNIQUE;
+ info->errkey= (int) def->key;
+ info->dup_key_pos= info->cur_row.lastpos;
+ info->page_changed= 1; /* Can't optimize read next */
+ info->cur_row.lastpos= lastpos;
+ DBUG_PRINT("info",("Found duplicate"));
+ DBUG_RETURN(1); /* Found identical */
+ }
+ DBUG_ASSERT(info->last_key.data_length == MARIA_UNIQUE_HASH_LENGTH);
+ if (_ma_search_next(info, &info->last_key, SEARCH_BIGGER,
+ info->s->state.key_root[def->key]) ||
+ bcmp((char*) info->last_key.data, (char*) key_buff,
+ MARIA_UNIQUE_HASH_LENGTH))
+ {
+ info->page_changed= 1; /* Can't optimize read next */
+ info->cur_row.lastpos= lastpos;
+ DBUG_RETURN(0); /* end of tree */
+ }
+ }
+}
+
+
+/*
+ Calculate a hash for a row
+
+ TODO
+ Add support for bit fields
+*/
+
+ha_checksum _ma_unique_hash(MARIA_UNIQUEDEF *def, const uchar *record)
+{
+ const uchar *pos, *end;
+ ha_checksum crc= 0;
+ ulong seed1=0, seed2= 4;
+ HA_KEYSEG *keyseg;
+
+ for (keyseg=def->seg ; keyseg < def->end ; keyseg++)
+ {
+ enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
+ uint length=keyseg->length;
+
+ if (keyseg->null_bit)
+ {
+ if (record[keyseg->null_pos] & keyseg->null_bit)
+ {
+ /*
+ Change crc in a way different from an empty string or 0.
+ (This is an optimisation; The code will work even if this isn't
+ done)
+ */
+ crc=((crc << 8) + 511+
+ (crc >> (8*sizeof(ha_checksum)-8)));
+ continue;
+ }
+ }
+ pos= record+keyseg->start;
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
+ {
+ uint pack_length= keyseg->bit_start;
+ uint tmp_length= (pack_length == 1 ? (uint) *pos :
+ uint2korr(pos));
+ pos+= pack_length; /* Skip VARCHAR length */
+ set_if_smaller(length,tmp_length);
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ uint tmp_length= _ma_calc_blob_length(keyseg->bit_start,pos);
+ memcpy_fixed((uchar*) &pos,pos+keyseg->bit_start,sizeof(char*));
+ if (!length || length > tmp_length)
+ length=tmp_length; /* The whole blob */
+ }
+ end= pos+length;
+ if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 ||
+ type == HA_KEYTYPE_VARTEXT2)
+ {
+ keyseg->charset->coll->hash_sort(keyseg->charset,
+ (const uchar*) pos, length, &seed1,
+ &seed2);
+ crc^= seed1;
+ }
+ else
+ while (pos != end)
+ crc=((crc << 8) +
+ (((uchar) *pos++))) +
+ (crc >> (8*sizeof(ha_checksum)-8));
+ }
+ return crc;
+}
+
+
+/*
+ compare unique key for two rows
+
+ TODO
+ Add support for bit fields
+
+ RETURN
+ 0 if both rows have equal unique value
+ 1 Rows are different
+*/
+
+my_bool _ma_unique_comp(MARIA_UNIQUEDEF *def, const uchar *a, const uchar *b,
+ my_bool null_are_equal)
+{
+ const uchar *pos_a, *pos_b, *end;
+ HA_KEYSEG *keyseg;
+
+ for (keyseg=def->seg ; keyseg < def->end ; keyseg++)
+ {
+ enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
+ uint a_length, b_length;
+ a_length= b_length= keyseg->length;
+
+ /* If part is NULL it's regarded as different */
+ if (keyseg->null_bit)
+ {
+ uint tmp;
+ if ((tmp=(a[keyseg->null_pos] & keyseg->null_bit)) !=
+ (uint) (b[keyseg->null_pos] & keyseg->null_bit))
+ return 1;
+ if (tmp)
+ {
+ if (!null_are_equal)
+ return 1;
+ continue;
+ }
+ }
+ pos_a= a+keyseg->start;
+ pos_b= b+keyseg->start;
+ if (keyseg->flag & HA_VAR_LENGTH_PART)
+ {
+ uint pack_length= keyseg->bit_start;
+ if (pack_length == 1)
+ {
+ a_length= (uint) *pos_a++;
+ b_length= (uint) *pos_b++;
+ }
+ else
+ {
+ a_length= uint2korr(pos_a);
+ b_length= uint2korr(pos_b);
+ pos_a+= 2; /* Skip VARCHAR length */
+ pos_b+= 2;
+ }
+ set_if_smaller(a_length, keyseg->length); /* Safety */
+ set_if_smaller(b_length, keyseg->length); /* safety */
+ }
+ else if (keyseg->flag & HA_BLOB_PART)
+ {
+ /* Only compare 'length' characters if length != 0 */
+ a_length= _ma_calc_blob_length(keyseg->bit_start,pos_a);
+ b_length= _ma_calc_blob_length(keyseg->bit_start,pos_b);
+ /* Check that a and b are of equal length */
+ if (keyseg->length)
+ {
+ /*
+ This is used in some cases when we are not interested in comparing
+ the whole length of the blob.
+ */
+ set_if_smaller(a_length, keyseg->length);
+ set_if_smaller(b_length, keyseg->length);
+ }
+ memcpy_fixed((uchar*) &pos_a,pos_a+keyseg->bit_start,sizeof(char*));
+ memcpy_fixed((uchar*) &pos_b,pos_b+keyseg->bit_start,sizeof(char*));
+ }
+ if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 ||
+ type == HA_KEYTYPE_VARTEXT2)
+ {
+ if (ha_compare_text(keyseg->charset, pos_a, a_length,
+ pos_b, b_length, 0, 1))
+ return 1;
+ }
+ else
+ {
+ if (a_length != b_length)
+ return 1;
+ end= pos_a+a_length;
+ while (pos_a != end)
+ {
+ if (*pos_a++ != *pos_b++)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/storage/maria/ma_update.c b/storage/maria/ma_update.c
new file mode 100644
index 00000000000..7b9e006ec43
--- /dev/null
+++ b/storage/maria/ma_update.c
@@ -0,0 +1,253 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "ma_fulltext.h"
+#include "ma_rt_index.h"
+#include "trnman.h"
+
+/**
+ Update an old row in a MARIA table
+*/
+
+int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
+{
+ int flag,key_changed,save_errno;
+ reg3 my_off_t pos;
+ uint i;
+ uchar old_key_buff[MARIA_MAX_KEY_BUFF],*new_key_buff;
+ my_bool auto_key_changed= 0;
+ ulonglong changed;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo;
+ DBUG_ENTER("maria_update");
+ LINT_INIT(new_key_buff);
+ LINT_INIT(changed);
+
+ DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ DBUG_RETURN(my_errno= HA_ERR_CRASHED););
+ if (!(info->update & HA_STATE_AKTIV))
+ {
+ DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND);
+ }
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ if (share->state.state.key_file_length >= share->base.margin_key_file_length)
+ {
+ DBUG_RETURN(my_errno=HA_ERR_INDEX_FILE_FULL);
+ }
+ pos= info->cur_row.lastpos;
+ if (_ma_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+
+ if ((*share->compare_record)(info,oldrec))
+ {
+ save_errno= my_errno;
+ DBUG_PRINT("warning", ("Got error from compare record"));
+ goto err_end; /* Record has changed */
+ }
+
+ /* Calculate and check all unique constraints */
+ key_changed=0;
+ for (i=0 ; i < share->state.header.uniques ; i++)
+ {
+ MARIA_UNIQUEDEF *def=share->uniqueinfo+i;
+ if (_ma_unique_comp(def, newrec, oldrec,1) &&
+ _ma_check_unique(info, def, newrec, _ma_unique_hash(def, newrec),
+ pos))
+ {
+ save_errno=my_errno;
+ goto err_end;
+ }
+ }
+ if (_ma_mark_file_changed(info))
+ {
+ save_errno=my_errno;
+ goto err_end;
+ }
+
+ /* Ensure we don't try to restore auto_increment if it doesn't change */
+ info->last_auto_increment= ~(ulonglong) 0;
+
+ /* Check which keys changed from the original row */
+
+ new_key_buff= info->lastkey_buff2;
+ changed=0;
+ for (i=0, keyinfo= share->keyinfo ; i < share->base.keys ; i++, keyinfo++)
+ {
+ if (maria_is_key_active(share->state.key_map, i))
+ {
+ if (keyinfo->flag & HA_FULLTEXT )
+ {
+ if (_ma_ft_cmp(info,i,oldrec, newrec))
+ {
+ if ((int) i == info->lastinx)
+ {
+ /*
+ We are changeing the index we are reading on. Mark that
+ the index data has changed and we need to do a full search
+ when doing read-next
+ */
+ key_changed|=HA_STATE_WRITTEN;
+ }
+ changed|=((ulonglong) 1 << i);
+ if (_ma_ft_update(info,i,old_key_buff,oldrec,newrec,pos))
+ goto err;
+ }
+ }
+ else
+ {
+ MARIA_KEY new_key, old_key;
+
+ (*keyinfo->make_key)(info,&new_key, i, new_key_buff, newrec,
+ pos, info->trn->trid);
+ (*keyinfo->make_key)(info,&old_key, i, old_key_buff,
+ oldrec, pos, info->cur_row.trid);
+
+ /* The above changed info->lastkey2. Inform maria_rnext_same(). */
+ info->update&= ~HA_STATE_RNEXT_SAME;
+
+ if (new_key.data_length != old_key.data_length ||
+ memcmp(old_key.data, new_key.data, new_key.data_length))
+ {
+ if ((int) i == info->lastinx)
+ key_changed|=HA_STATE_WRITTEN; /* Mark that keyfile changed */
+ changed|=((ulonglong) 1 << i);
+ keyinfo->version++;
+ if (keyinfo->ck_delete(info,&old_key))
+ goto err;
+ if (keyinfo->ck_insert(info,&new_key))
+ goto err;
+ if (share->base.auto_key == i+1)
+ auto_key_changed=1;
+ }
+ }
+ }
+ }
+
+ if (share->calc_checksum)
+ {
+ /*
+ We can't use the row based checksum as this doesn't have enough
+ precision (one byte, while the table's is more bytes).
+ At least _ma_check_unique() modifies the 'newrec' record, so checksum
+ has to be computed _after_ it. Nobody apparently modifies 'oldrec'.
+ We need to pass the old row's checksum down to (*update_record)(), we do
+ this via info->new_row.checksum (not intuitive but existing code
+ mandated that cur_row is the new row).
+ If (*update_record)() fails, table will be marked corrupted so no need
+ to revert the live checksum change.
+ */
+ info->cur_row.checksum= (*share->calc_checksum)(info, newrec);
+ info->new_row.checksum= (*share->calc_checksum)(info, oldrec);
+ info->state->checksum+= info->cur_row.checksum - info->new_row.checksum;
+ }
+
+ if ((*share->update_record)(info, pos, oldrec, newrec))
+ goto err;
+
+ if (auto_key_changed & !share->now_transactional)
+ {
+ const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
+ const uchar *key= newrec + keyseg->start;
+ set_if_bigger(share->state.auto_increment,
+ ma_retrieve_auto_increment(key, keyseg->type));
+ }
+
+ /*
+ We can't yet have HA_STATE_AKTIV here, as block_record dosn't support it
+ */
+ info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | key_changed);
+ share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED;
+ info->state->changed= 1;
+
+ /*
+ Every Maria function that updates Maria table must end with
+ call to _ma_writeinfo(). If operation (second param of
+ _ma_writeinfo()) is not 0 it sets share->changed to 1, that is
+ flags that data has changed. If operation is 0, this function
+ equals to no-op in this case.
+
+ ma_update() must always pass !0 value as operation, since even if
+ there is no index change there could be data change.
+ */
+ VOID(_ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (update)",
+ share->open_file_name.str));
+ (*info->invalidator)(share->open_file_name.str);
+ info->invalidator=0;
+ }
+ DBUG_RETURN(0);
+
+err:
+ DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
+ save_errno= my_errno;
+ DBUG_ASSERT(save_errno);
+ if (!save_errno)
+ save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
+
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_OUT_OF_MEM ||
+ my_errno == HA_ERR_RECORD_FILE_FULL)
+ {
+ info->errkey= (int) i;
+ flag=0;
+ do
+ {
+ if (((ulonglong) 1 << i) & changed)
+ {
+ if (share->keyinfo[i].flag & HA_FULLTEXT)
+ {
+ if ((flag++ && _ma_ft_del(info,i,new_key_buff,newrec,pos)) ||
+ _ma_ft_add(info,i,old_key_buff,oldrec,pos))
+ break;
+ }
+ else
+ {
+ MARIA_KEY new_key, old_key;
+ (*share->keyinfo[i].make_key)(info, &new_key, i, new_key_buff,
+ newrec, pos,
+ info->trn->trid);
+ (*share->keyinfo[i].make_key)(info, &old_key, i, old_key_buff,
+ oldrec, pos, info->cur_row.trid);
+ if ((flag++ && _ma_ck_delete(info, &new_key)) ||
+ _ma_ck_write(info, &old_key))
+ break;
+ }
+ }
+ } while (i-- != 0);
+ }
+ else
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ maria_mark_crashed(info);
+ }
+ info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED |
+ key_changed);
+
+ err_end:
+ VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ if (save_errno == HA_ERR_KEY_NOT_FOUND)
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ save_errno=HA_ERR_CRASHED;
+ }
+ DBUG_RETURN(my_errno=save_errno);
+} /* maria_update */
diff --git a/storage/maria/ma_write.c b/storage/maria/ma_write.c
new file mode 100644
index 00000000000..bfbeb813627
--- /dev/null
+++ b/storage/maria/ma_write.c
@@ -0,0 +1,2330 @@
+/* Copyright (C) 2004-2008 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ Copyright (C) 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Write a row to a MARIA table */
+
+#include "ma_fulltext.h"
+#include "ma_rt_index.h"
+#include "trnman.h"
+#include "ma_key_recover.h"
+#include "ma_blockrec.h"
+
+#define MAX_POINTER_LENGTH 8
+
+ /* Functions declared in this file */
+
+static int w_search(register MARIA_HA *info, uint32 comp_flag,
+ MARIA_KEY *key, my_off_t page,
+ my_off_t father_page, uchar *father_buff,
+ MARIA_PINNED_PAGE *father_page_link, uchar *father_keypos,
+ my_bool insert_last);
+static int _ma_balance_page(MARIA_HA *info,MARIA_KEYDEF *keyinfo,
+ MARIA_KEY *key, uchar *curr_buff, my_off_t page,
+ my_off_t father_page, uchar *father_buff,
+ uchar *father_keypos,
+ MARIA_KEY_PARAM *s_temp);
+static uchar *_ma_find_last_pos(MARIA_HA *info, MARIA_KEY *int_key,
+ uchar *page, uchar **after_key);
+static my_bool _ma_ck_write_tree(register MARIA_HA *info, MARIA_KEY *key);
+static my_bool _ma_ck_write_btree(register MARIA_HA *info, MARIA_KEY *key);
+static int _ma_ck_write_btree_with_log(MARIA_HA *, MARIA_KEY *, my_off_t *,
+ uint32);
+static my_bool _ma_log_split(MARIA_HA *info, my_off_t page, const uchar *buff,
+ uint org_length, uint new_length,
+ const uchar *key_pos,
+ uint key_length, int move_length,
+ enum en_key_op prefix_or_suffix,
+ const uchar *data, uint data_length,
+ uint changed_length);
+static my_bool _ma_log_del_prefix(MARIA_HA *info, my_off_t page,
+ const uchar *buff,
+ uint org_length, uint new_length,
+ const uchar *key_pos, uint key_length,
+ int move_length);
+static my_bool _ma_log_key_middle(MARIA_HA *info, my_off_t page,
+ const uchar *buff,
+ uint new_length,
+ uint data_added_first,
+ uint data_changed_first,
+ uint data_deleted_last,
+ const uchar *key_pos,
+ uint key_length, int move_length);
+
+/*
+ @brief Default handler for returing position to new row
+
+ @note
+ This is only called for non transactional tables and not for block format
+ which is why we use info->state here.
+*/
+
+MARIA_RECORD_POS _ma_write_init_default(MARIA_HA *info,
+ const uchar *record
+ __attribute__((unused)))
+{
+ return ((info->s->state.dellink != HA_OFFSET_ERROR &&
+ !info->append_insert_at_end) ?
+ info->s->state.dellink :
+ info->state->data_file_length);
+}
+
+my_bool _ma_write_abort_default(MARIA_HA *info __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/* Write new record to a table */
+
+int maria_write(MARIA_HA *info, uchar *record)
+{
+ MARIA_SHARE *share= info->s;
+ uint i;
+ int save_errno;
+ MARIA_RECORD_POS filepos;
+ uchar *buff;
+ my_bool lock_tree= share->lock_key_trees;
+ my_bool fatal_error;
+ MARIA_KEYDEF *keyinfo;
+ DBUG_ENTER("maria_write");
+ DBUG_PRINT("enter",("index_file: %d data_file: %d",
+ share->kfile.file, info->dfile.file));
+
+ DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ DBUG_RETURN(my_errno= HA_ERR_CRASHED););
+ if (share->options & HA_OPTION_READ_ONLY_DATA)
+ {
+ DBUG_RETURN(my_errno=EACCES);
+ }
+ if (_ma_readinfo(info,F_WRLCK,1))
+ DBUG_RETURN(my_errno);
+ dont_break(); /* Dont allow SIGHUP or SIGINT */
+
+ if (share->base.reloc == (ha_rows) 1 &&
+ share->base.records == (ha_rows) 1 &&
+ share->state.state.records == (ha_rows) 1)
+ { /* System file */
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ goto err2;
+ }
+ if (share->state.state.key_file_length >= share->base.margin_key_file_length)
+ {
+ my_errno=HA_ERR_INDEX_FILE_FULL;
+ goto err2;
+ }
+ if (_ma_mark_file_changed(info))
+ goto err2;
+
+ /* Calculate and check all unique constraints */
+ for (i=0 ; i < share->state.header.uniques ; i++)
+ {
+ if (_ma_check_unique(info,share->uniqueinfo+i,record,
+ _ma_unique_hash(share->uniqueinfo+i,record),
+ HA_OFFSET_ERROR))
+ goto err2;
+ }
+
+ /* Ensure we don't try to restore auto_increment if it doesn't change */
+ info->last_auto_increment= ~(ulonglong) 0;
+
+ if ((info->opt_flag & OPT_NO_ROWS))
+ filepos= HA_OFFSET_ERROR;
+ else
+ {
+ /*
+ This may either calculate a record or, or write the record and return
+ the record id
+ */
+ if ((filepos= (*share->write_record_init)(info, record)) ==
+ HA_OFFSET_ERROR)
+ goto err2;
+ }
+
+ /* Write all keys to indextree */
+ buff= info->lastkey_buff2;
+ for (i=0, keyinfo= share->keyinfo ; i < share->base.keys ; i++, keyinfo++)
+ {
+ MARIA_KEY int_key;
+ if (maria_is_key_active(share->state.key_map, i))
+ {
+ my_bool local_lock_tree= (lock_tree &&
+ !(info->bulk_insert &&
+ is_tree_inited(&info->bulk_insert[i])));
+ if (local_lock_tree)
+ {
+ rw_wrlock(&keyinfo->root_lock);
+ keyinfo->version++;
+ }
+ if (keyinfo->flag & HA_FULLTEXT )
+ {
+ if (_ma_ft_add(info,i, buff,record,filepos))
+ {
+ if (local_lock_tree)
+ rw_unlock(&keyinfo->root_lock);
+ DBUG_PRINT("error",("Got error: %d on write",my_errno));
+ goto err;
+ }
+ }
+ else
+ {
+ while (keyinfo->ck_insert(info,
+ (*keyinfo->make_key)(info, &int_key, i, buff, record,
+ filepos, info->trn->trid)))
+ {
+ TRN *blocker;
+ DBUG_PRINT("error",("Got error: %d on write",my_errno));
+ /*
+ explicit check to filter out temp tables, they aren't
+ transactional and don't have a proper TRN so the code
+ below doesn't work for them.
+ Also, filter out non-thread maria use, and table modified in
+ the same transaction.
+ At last, filter out non-dup-unique errors.
+ */
+ if (!local_lock_tree)
+ goto err;
+ if (info->dup_key_trid == info->trn->trid ||
+ my_errno != HA_ERR_FOUND_DUPP_KEY)
+ {
+ rw_unlock(&keyinfo->root_lock);
+ goto err;
+ }
+ /* Different TrIDs: table must be transactional */
+ DBUG_ASSERT(share->base.born_transactional);
+ /*
+ If transactions are disabled, and dup_key_trid is different from
+ our TrID, it must be ALTER TABLE with dup_key_trid==0 (no
+ transaction). ALTER TABLE does have MARIA_HA::TRN not dummy but
+ puts TrID=0 in rows/keys.
+ */
+ DBUG_ASSERT(share->now_transactional ||
+ (info->dup_key_trid == 0));
+ blocker= trnman_trid_to_trn(info->trn, info->dup_key_trid);
+ /*
+ if blocker TRN was not found, it means that the conflicting
+ transaction was committed long time ago. It could not be
+ aborted, as it would have to wait on the key tree lock
+ to remove the conflicting key it has inserted.
+ */
+ if (!blocker || blocker->commit_trid != ~(TrID)0)
+ { /* committed */
+ if (blocker)
+ pthread_mutex_unlock(& blocker->state_lock);
+ rw_unlock(&keyinfo->root_lock);
+ goto err;
+ }
+ rw_unlock(&keyinfo->root_lock);
+ {
+ /* running. now we wait */
+ WT_RESOURCE_ID rc;
+ int res;
+ const char *old_proc_info;
+
+ rc.type= &ma_rc_dup_unique;
+ /* TODO savepoint id when we'll have them */
+ rc.value= (intptr)blocker;
+ res= wt_thd_will_wait_for(info->trn->wt, blocker->wt, & rc);
+ if (res != WT_OK)
+ {
+ pthread_mutex_unlock(& blocker->state_lock);
+ my_errno= HA_ERR_LOCK_DEADLOCK;
+ goto err;
+ }
+ old_proc_info= proc_info_hook(0,
+ "waiting for a resource",
+ __func__, __FILE__, __LINE__);
+ res= wt_thd_cond_timedwait(info->trn->wt, & blocker->state_lock);
+ proc_info_hook(0, old_proc_info, __func__, __FILE__, __LINE__);
+
+ pthread_mutex_unlock(& blocker->state_lock);
+ if (res != WT_OK)
+ {
+ my_errno= res == WT_TIMEOUT ? HA_ERR_LOCK_WAIT_TIMEOUT
+ : HA_ERR_LOCK_DEADLOCK;
+ goto err;
+ }
+ }
+ rw_wrlock(&keyinfo->root_lock);
+#ifndef MARIA_CANNOT_ROLLBACK
+ keyinfo->version++;
+#endif
+ }
+ }
+
+ /* The above changed info->lastkey2. Inform maria_rnext_same(). */
+ info->update&= ~HA_STATE_RNEXT_SAME;
+
+ if (local_lock_tree)
+ rw_unlock(&keyinfo->root_lock);
+ }
+ }
+ if (share->calc_write_checksum)
+ info->cur_row.checksum= (*share->calc_write_checksum)(info,record);
+ if (filepos != HA_OFFSET_ERROR)
+ {
+ if ((*share->write_record)(info,record))
+ goto err;
+ info->state->checksum+= info->cur_row.checksum;
+ }
+ if (!share->now_transactional)
+ {
+ if (share->base.auto_key != 0)
+ {
+ const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
+ const uchar *key= record + keyseg->start;
+ set_if_bigger(share->state.auto_increment,
+ ma_retrieve_auto_increment(key, keyseg->type));
+ }
+ }
+ info->state->records++;
+ info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
+ HA_STATE_ROW_CHANGED);
+ share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED;
+ info->state->changed= 1;
+
+ info->cur_row.lastpos= filepos;
+ VOID(_ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
+ if (info->invalidator != 0)
+ {
+ DBUG_PRINT("info", ("invalidator... '%s' (update)",
+ share->open_file_name.str));
+ (*info->invalidator)(share->open_file_name.str);
+ info->invalidator=0;
+ }
+
+ /*
+ Update status of the table. We need to do so after each row write
+ for the log tables, as we want the new row to become visible to
+ other threads as soon as possible. We don't lock mutex here
+ (as it is required by pthread memory visibility rules) as (1) it's
+ not critical to use outdated share->is_log_table value (2) locking
+ mutex here for every write is too expensive.
+ */
+ if (share->is_log_table)
+ _ma_update_status((void*) info);
+
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(0);
+
+err:
+ save_errno= my_errno;
+ fatal_error= 0;
+ if (my_errno == HA_ERR_FOUND_DUPP_KEY ||
+ my_errno == HA_ERR_RECORD_FILE_FULL ||
+ my_errno == HA_ERR_LOCK_DEADLOCK ||
+ my_errno == HA_ERR_LOCK_WAIT_TIMEOUT ||
+ my_errno == HA_ERR_NULL_IN_SPATIAL ||
+ my_errno == HA_ERR_OUT_OF_MEM)
+ {
+ if (info->bulk_insert)
+ {
+ uint j;
+ for (j=0 ; j < share->base.keys ; j++)
+ maria_flush_bulk_insert(info, j);
+ }
+ info->errkey= (int) i;
+ /*
+ We delete keys in the reverse order of insertion. This is the order that
+ a rollback would do and is important for CLR_ENDs generated by
+ _ma_ft|ck_delete() and write_record_abort() to work (with any other
+ order they would cause wrong jumps in the chain).
+ */
+ while ( i-- > 0)
+ {
+ if (maria_is_key_active(share->state.key_map, i))
+ {
+ my_bool local_lock_tree= (lock_tree &&
+ !(info->bulk_insert &&
+ is_tree_inited(&info->bulk_insert[i])));
+ keyinfo= share->keyinfo + i;
+ if (local_lock_tree)
+ rw_wrlock(&keyinfo->root_lock);
+ /**
+ @todo RECOVERY BUG
+ The key deletes below should generate CLR_ENDs
+ */
+ if (keyinfo->flag & HA_FULLTEXT)
+ {
+ if (_ma_ft_del(info,i,buff,record,filepos))
+ {
+ if (local_lock_tree)
+ rw_unlock(&keyinfo->root_lock);
+ break;
+ }
+ }
+ else
+ {
+ MARIA_KEY key;
+ if (_ma_ck_delete(info,
+ (*keyinfo->make_key)(info, &key, i, buff, record,
+ filepos, info->trn->trid)))
+ {
+ if (local_lock_tree)
+ rw_unlock(&keyinfo->root_lock);
+ break;
+ }
+ }
+ if (local_lock_tree)
+ rw_unlock(&keyinfo->root_lock);
+ }
+ }
+ }
+ else
+ fatal_error= 1;
+
+ if ((*share->write_record_abort)(info))
+ fatal_error= 1;
+ if (fatal_error)
+ {
+ maria_print_error(info->s, HA_ERR_CRASHED);
+ maria_mark_crashed(info);
+ }
+
+ info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
+ my_errno=save_errno;
+err2:
+ save_errno=my_errno;
+ DBUG_ASSERT(save_errno);
+ if (!save_errno)
+ save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
+ DBUG_PRINT("error", ("got error: %d", save_errno));
+ VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
+ allow_break(); /* Allow SIGHUP & SIGINT */
+ DBUG_RETURN(my_errno=save_errno);
+} /* maria_write */
+
+
+/*
+ Write one key to btree
+
+ TODO
+ Remove this function and have bulk insert change keyinfo->ck_insert
+ to point to the right function
+*/
+
+my_bool _ma_ck_write(MARIA_HA *info, MARIA_KEY *key)
+{
+ DBUG_ENTER("_ma_ck_write");
+
+ if (info->bulk_insert &&
+ is_tree_inited(&info->bulk_insert[key->keyinfo->key_nr]))
+ {
+ DBUG_RETURN(_ma_ck_write_tree(info, key));
+ }
+ DBUG_RETURN(_ma_ck_write_btree(info, key));
+} /* _ma_ck_write */
+
+
+/**********************************************************************
+ Insert key into btree (normal case)
+**********************************************************************/
+
+static my_bool _ma_ck_write_btree(MARIA_HA *info, MARIA_KEY *key)
+{
+ int error;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ my_off_t *root= &info->s->state.key_root[keyinfo->key_nr];
+ DBUG_ENTER("_ma_ck_write_btree");
+
+ error= _ma_ck_write_btree_with_log(info, key, root,
+ keyinfo->write_comp_flag | key->flag);
+ if (info->ft1_to_ft2)
+ {
+ if (!error)
+ error= _ma_ft_convert_to_ft2(info, key);
+ delete_dynamic(info->ft1_to_ft2);
+ my_free((uchar*)info->ft1_to_ft2, MYF(0));
+ info->ft1_to_ft2=0;
+ }
+ DBUG_RETURN(error != 0);
+} /* _ma_ck_write_btree */
+
+
+/**
+ @brief Write a key to the b-tree
+
+ @retval -1 error
+ @retval 0 ok
+*/
+
+static int _ma_ck_write_btree_with_log(MARIA_HA *info, MARIA_KEY *key,
+ my_off_t *root, uint32 comp_flag)
+{
+ MARIA_SHARE *share= info->s;
+ LSN lsn= LSN_IMPOSSIBLE;
+ int error;
+ my_off_t new_root= *root;
+ uchar key_buff[MARIA_MAX_KEY_BUFF];
+ MARIA_KEY org_key;
+ DBUG_ENTER("_ma_ck_write_btree_with_log");
+
+ LINT_INIT_STRUCT(org_key);
+ if (share->now_transactional)
+ {
+ /* Save original value as the key may change */
+ org_key= *key;
+ memcpy(key_buff, key->data, key->data_length + key->ref_length);
+ }
+
+ error= _ma_ck_real_write_btree(info, key, &new_root, comp_flag);
+ if (!error && share->now_transactional)
+ {
+ /* Log the original value */
+ *key= org_key;
+ key->data= key_buff;
+ error= _ma_write_undo_key_insert(info, key, root, new_root, &lsn);
+ }
+ else
+ {
+ *root= new_root;
+ _ma_fast_unlock_key_del(info);
+ }
+ _ma_unpin_all_pages_and_finalize_row(info, lsn);
+
+ DBUG_RETURN(error);
+} /* _ma_ck_write_btree_with_log */
+
+
+/**
+ @brief Write a key to the b-tree
+
+ @retval -1 error
+ @retval 0 ok
+*/
+
+int _ma_ck_real_write_btree(MARIA_HA *info, MARIA_KEY *key, my_off_t *root,
+ uint32 comp_flag)
+{
+ int error;
+ DBUG_ENTER("_ma_ck_real_write_btree");
+
+ /* key_length parameter is used only if comp_flag is SEARCH_FIND */
+ if (*root == HA_OFFSET_ERROR ||
+ (error= w_search(info, comp_flag, key, *root, (my_off_t) 0, (uchar*) 0,
+ (MARIA_PINNED_PAGE *) 0, (uchar*) 0, 1)) > 0)
+ error= _ma_enlarge_root(info, key, root);
+ DBUG_RETURN(error);
+} /* _ma_ck_real_write_btree */
+
+
+/**
+ @brief Make a new root with key as only pointer
+
+ @retval -1 error
+ @retval 0 ok
+*/
+
+int _ma_enlarge_root(MARIA_HA *info, MARIA_KEY *key, my_off_t *root)
+{
+ uint t_length, page_flag, nod_flag, page_length;
+ MARIA_KEY_PARAM s_temp;
+ MARIA_SHARE *share= info->s;
+ MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ int res= 0;
+ DBUG_ENTER("_ma_enlarge_root");
+
+ nod_flag= (*root != HA_OFFSET_ERROR) ? share->base.key_reflength : 0;
+ /* Store pointer to prev page if nod */
+ _ma_kpointer(info, info->buff + share->keypage_header, *root);
+ t_length= (*keyinfo->pack_key)(key, nod_flag, (uchar*) 0,
+ (uchar*) 0, (uchar*) 0, &s_temp);
+ page_length= share->keypage_header + t_length + nod_flag;
+
+ bzero(info->buff, share->keypage_header);
+ _ma_store_keynr(share, info->buff, keyinfo->key_nr);
+ _ma_store_page_used(share, info->buff, page_length);
+ page_flag= 0;
+ if (nod_flag)
+ page_flag|= KEYPAGE_FLAG_ISNOD;
+ if (key->flag & (SEARCH_USER_KEY_HAS_TRANSID | SEARCH_PAGE_KEY_HAS_TRANSID))
+ page_flag|= KEYPAGE_FLAG_HAS_TRANSID;
+ _ma_store_keypage_flag(share, info->buff, page_flag);
+ (*keyinfo->store_key)(keyinfo, info->buff + share->keypage_header +
+ nod_flag, &s_temp);
+
+ /* Mark that info->buff was used */
+ info->keyread_buff_used= info->page_changed= 1;
+ if ((*root= _ma_new(info, PAGECACHE_PRIORITY_HIGH, &page_link)) ==
+ HA_OFFSET_ERROR)
+ DBUG_RETURN(-1);
+
+ /*
+ Clear unitialized part of page to avoid valgrind/purify warnings
+ and to get a clean page that is easier to compress and compare with
+ pages generated with redo
+ */
+ bzero(info->buff + page_length, share->block_size - page_length);
+
+ if (share->now_transactional &&
+ _ma_log_new(info, *root, info->buff, page_length, keyinfo->key_nr, 1))
+ res= -1;
+ if (_ma_write_keypage(info, keyinfo, *root, page_link->write_lock,
+ PAGECACHE_PRIORITY_HIGH, info->buff))
+ res= -1;
+
+ DBUG_RETURN(res);
+} /* _ma_enlarge_root */
+
+
+/*
+ Search after a position for a key and store it there
+
+ @return
+ @retval -1 error
+ @retval 0 ok
+ @retval > 0 Key should be stored in higher tree
+*/
+
+static int w_search(register MARIA_HA *info, uint32 comp_flag, MARIA_KEY *key,
+ my_off_t page, my_off_t father_page, uchar *father_buff,
+ MARIA_PINNED_PAGE *father_page_link, uchar *father_keypos,
+ my_bool insert_last)
+{
+ int error,flag;
+ uint page_flag, nod_flag;
+ uchar *temp_buff,*keypos;
+ uchar keybuff[MARIA_MAX_KEY_BUFF];
+ my_bool was_last_key;
+ my_off_t next_page, dup_key_pos;
+ MARIA_PINNED_PAGE *page_link;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("w_search");
+ DBUG_PRINT("enter",("page: %ld", (long) page));
+
+ if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
+ MARIA_MAX_KEY_BUFF*2)))
+ DBUG_RETURN(-1);
+ if (!_ma_fetch_keypage(info, keyinfo, page, PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, temp_buff, 0, &page_link))
+ goto err;
+
+ flag= (*keyinfo->bin_search)(key, temp_buff, comp_flag, &keypos,
+ keybuff, &was_last_key);
+ page_flag= _ma_get_keypage_flag(share, temp_buff);
+ nod_flag= _ma_test_if_nod(share, temp_buff);
+ if (flag == 0)
+ {
+ MARIA_KEY tmp_key;
+ /* get position to record with duplicated key */
+
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= keybuff;
+
+ if ((*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &keypos))
+ dup_key_pos= _ma_row_pos_from_key(&tmp_key);
+ else
+ dup_key_pos= HA_OFFSET_ERROR;
+
+ if (keyinfo->flag & HA_FULLTEXT)
+ {
+ uint off;
+ int subkeys;
+
+ get_key_full_length_rdonly(off, keybuff);
+ subkeys=ft_sintXkorr(keybuff+off);
+ comp_flag=SEARCH_SAME;
+ if (subkeys >= 0)
+ {
+ /* normal word, one-level tree structure */
+ flag=(*keyinfo->bin_search)(key, temp_buff, comp_flag,
+ &keypos, keybuff, &was_last_key);
+ }
+ else
+ {
+ /* popular word. two-level tree. going down */
+ my_off_t root=dup_key_pos;
+ keyinfo= &share->ft2_keyinfo;
+ get_key_full_length_rdonly(off, key);
+ key+=off;
+ /* we'll modify key entry 'in vivo' */
+ keypos-= keyinfo->keylength + nod_flag;
+ error= _ma_ck_real_write_btree(info, key, &root, comp_flag);
+ _ma_dpointer(share, keypos+HA_FT_WLEN, root);
+ subkeys--; /* should there be underflow protection ? */
+ DBUG_ASSERT(subkeys < 0);
+ ft_intXstore(keypos, subkeys);
+ if (!error)
+ {
+ page_link->changed= 1;
+ error= _ma_write_keypage(info, keyinfo, page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, temp_buff);
+ }
+ my_afree((uchar*) temp_buff);
+ DBUG_RETURN(error);
+ }
+ }
+ else /* not HA_FULLTEXT, normal HA_NOSAME key */
+ {
+ DBUG_PRINT("warning", ("Duplicate key"));
+ /*
+ TODO
+ When the index will support true versioning - with multiple
+ identical values in the UNIQUE index, invisible to each other -
+ the following should be changed to "continue inserting keys, at the
+ end (of the row or statement) wait". We need to wait on *all*
+ unique conflicts at once, not one-at-a-time, because we need to
+ know all blockers in advance, otherwise we'll have incomplete wait-for
+ graph.
+ */
+ /*
+ transaction that has inserted the conflicting key may be in progress.
+ the caller will wait for it to be committed or aborted.
+ */
+ info->dup_key_trid= _ma_trid_from_key(&tmp_key);
+ info->dup_key_pos= dup_key_pos;
+ my_afree((uchar*) temp_buff);
+ my_errno= HA_ERR_FOUND_DUPP_KEY;
+ DBUG_RETURN(-1);
+ }
+ }
+ if (flag == MARIA_FOUND_WRONG_KEY)
+ DBUG_RETURN(-1);
+ if (!was_last_key)
+ insert_last=0;
+ next_page= _ma_kpos(nod_flag,keypos);
+ if (next_page == HA_OFFSET_ERROR ||
+ (error= w_search(info, comp_flag, key, next_page,
+ page, temp_buff, page_link, keypos, insert_last)) > 0)
+ {
+ error= _ma_insert(info, key, temp_buff, keypos, page, keybuff,
+ father_page, father_buff, father_page_link,
+ father_keypos, insert_last);
+ page_link->changed= 1;
+ if (_ma_write_keypage(info, keyinfo, page, PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS,temp_buff))
+ goto err;
+ }
+ my_afree((uchar*) temp_buff);
+ DBUG_RETURN(error);
+err:
+ my_afree((uchar*) temp_buff);
+ DBUG_PRINT("exit",("Error: %d",my_errno));
+ DBUG_RETURN (-1);
+} /* w_search */
+
+
+/*
+ Insert new key.
+
+ SYNOPSIS
+ _ma_insert()
+ info Open table information.
+ keyinfo Key definition information.
+ key New key
+ anc_buff Key page (beginning).
+ key_pos Position in key page where to insert.
+ anc_page Page number for anc_buff
+ key_buff Copy of previous key if keys where packed.
+ father_page position of parent key page in file.
+ father_buff parent key page for balancing.
+ father_page_link Link to father page for marking page changed
+ father_key_pos position in parent key page for balancing.
+ insert_last If to append at end of page.
+
+ DESCRIPTION
+ Insert new key at right of key_pos.
+ Note that caller must save anc_buff
+
+ This function writes log records for all changed pages
+ (Including anc_buff and father page)
+
+ RETURN
+ < 0 Error.
+ 0 OK
+ 1 If key contains key to upper level (from balance page)
+ 2 If key contains key to upper level (from split space)
+*/
+
+int _ma_insert(register MARIA_HA *info, MARIA_KEY *key, uchar *anc_buff,
+ uchar *key_pos, my_off_t anc_page, uchar *key_buff,
+ my_off_t father_page, uchar *father_buff,
+ MARIA_PINNED_PAGE *father_page_link,
+ uchar *father_key_pos, my_bool insert_last)
+{
+ uint a_length, nod_flag, org_anc_length;
+ int t_length;
+ uchar *endpos, *prev_key;
+ MARIA_KEY_PARAM s_temp;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_insert");
+ DBUG_PRINT("enter",("key_pos: 0x%lx", (ulong) key_pos));
+ DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, key););
+
+ _ma_get_used_and_nod(share, anc_buff, a_length, nod_flag);
+ org_anc_length= a_length;
+ endpos= anc_buff+ a_length;
+ prev_key= (key_pos == anc_buff + share->keypage_header + nod_flag ?
+ (uchar*) 0 : key_buff);
+ t_length= (*keyinfo->pack_key)(key, nod_flag,
+ (key_pos == endpos ? (uchar*) 0 : key_pos),
+ prev_key, prev_key, &s_temp);
+#ifndef DBUG_OFF
+ if (prev_key && (keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
+ {
+ DBUG_DUMP("prev_key",(uchar*) prev_key, _ma_keylength(keyinfo,prev_key));
+ }
+ if (keyinfo->flag & HA_PACK_KEY)
+ {
+ DBUG_PRINT("test",("t_length: %d ref_len: %d",
+ t_length,s_temp.ref_length));
+ DBUG_PRINT("test",("n_ref_len: %d n_length: %d key_pos: 0x%lx",
+ s_temp.n_ref_length, s_temp.n_length, (long) s_temp.key));
+ }
+#endif
+ if (t_length > 0)
+ {
+ if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(-1);
+ }
+ bmove_upp((uchar*) endpos+t_length,(uchar*) endpos,
+ (uint) (endpos-key_pos));
+ }
+ else
+ {
+ if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
+ {
+ maria_print_error(share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(-1);
+ }
+ bmove(key_pos,key_pos-t_length,(uint) (endpos-key_pos)+t_length);
+ }
+ (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
+ a_length+=t_length;
+
+ if (key->flag & (SEARCH_USER_KEY_HAS_TRANSID | SEARCH_PAGE_KEY_HAS_TRANSID))
+ _ma_mark_page_with_transid(share, anc_buff);
+ _ma_store_page_used(share, anc_buff, a_length);
+
+ /*
+ Check if the new key fits totally into the the page
+ (anc_buff is big enough to contain a full page + one key)
+ */
+ if (a_length <= (uint) keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)
+ {
+ if (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE - a_length < 32 &&
+ (keyinfo->flag & HA_FULLTEXT) && key_pos == endpos &&
+ share->base.key_reflength <= share->base.rec_reflength &&
+ share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
+ {
+ /*
+ Normal word. One-level tree. Page is almost full.
+ Let's consider converting.
+ We'll compare 'key' and the first key at anc_buff
+ */
+ const uchar *a= key->data;
+ const uchar *b= anc_buff + share->keypage_header + nod_flag;
+ uint alen, blen, ft2len= share->ft2_keyinfo.keylength;
+ /* the very first key on the page is always unpacked */
+ DBUG_ASSERT((*b & 128) == 0);
+#if HA_FT_MAXLEN >= 127
+ blen= mi_uint2korr(b); b+=2;
+ When you enable this code, as part of the MyISAM->Maria merge of
+ChangeSet@1.2562, 2008-04-09 07:41:40+02:00, serg@janus.mylan +9 -0
+ restore ft2 functionality, fix bugs.
+ Then this will enable two-level fulltext index, which is not totally
+ recoverable yet.
+ So remove this text and inform Guilhem so that he fixes the issue.
+#else
+ blen= *b++;
+#endif
+ get_key_length(alen,a);
+ DBUG_ASSERT(info->ft1_to_ft2==0);
+ if (alen == blen &&
+ ha_compare_text(keyinfo->seg->charset, a, alen,
+ b, blen, 0, 0) == 0)
+ {
+ /* Yup. converting */
+ info->ft1_to_ft2=(DYNAMIC_ARRAY *)
+ my_malloc(sizeof(DYNAMIC_ARRAY), MYF(MY_WME));
+ my_init_dynamic_array(info->ft1_to_ft2, ft2len, 300, 50);
+
+ /*
+ Now, adding all keys from the page to dynarray
+ if the page is a leaf (if not keys will be deleted later)
+ */
+ if (!nod_flag)
+ {
+ /*
+ Let's leave the first key on the page, though, because
+ we cannot easily dispatch an empty page here
+ */
+ b+=blen+ft2len+2;
+ for (a=anc_buff+a_length ; b < a ; b+=ft2len+2)
+ insert_dynamic(info->ft1_to_ft2, b);
+
+ /* fixing the page's length - it contains only one key now */
+ _ma_store_page_used(share, anc_buff, share->keypage_header + blen +
+ ft2len + 2);
+ }
+ /* the rest will be done when we're back from recursion */
+ }
+ }
+ else
+ {
+ if (share->now_transactional &&
+ _ma_log_add(info, anc_page, anc_buff, (uint) (endpos - anc_buff),
+ key_pos, s_temp.changed_length, t_length, 0))
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0); /* There is room on page */
+ }
+ /* Page is full */
+ if (nod_flag)
+ insert_last=0;
+ /*
+ TODO:
+ Remove 'born_transactional' here.
+ The only reason for having it here is that the current
+ _ma_balance_page_ can't handle variable length keys.
+ */
+ if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
+ father_buff && !insert_last && !info->quick_mode &&
+ !info->s->base.born_transactional)
+ {
+ s_temp.key_pos= key_pos;
+ father_page_link->changed= 1;
+ DBUG_RETURN(_ma_balance_page(info, keyinfo, key, anc_buff, anc_page,
+ father_page, father_buff, father_key_pos,
+ &s_temp));
+ }
+ DBUG_RETURN(_ma_split_page(info, key, anc_page,
+ anc_buff, org_anc_length,
+ key_pos, s_temp.changed_length, t_length,
+ key_buff, insert_last));
+} /* _ma_insert */
+
+
+/**
+ @brief split a full page in two and assign emerging item to key
+
+ @fn _ma_split_page()
+ info Maria handler
+ keyinfo Key handler
+ key Buffer for middle key
+ split_page Address on disk for split_buff
+ split_buff Page buffer for page that should be split
+ org_split_length Original length of split_buff before key was inserted
+ inserted_key_pos Address in buffer where key was inserted
+ changed_length Number of bytes changed at 'inserted_key_pos'
+ move_length Number of bytes buffer was moved when key was inserted
+ key_buff Key buffer to use for temporary storage of key
+ insert_last_key If we are insert key on rightmost key page
+
+ @note
+ split_buff is not stored on disk (caller has to do this)
+
+ @return
+ @retval 2 ok (Middle key up from _ma_insert())
+ @retval -1 error
+*/
+
+int _ma_split_page(MARIA_HA *info, MARIA_KEY *key, my_off_t split_page,
+ uchar *split_buff,
+ uint org_split_length,
+ uchar *inserted_key_pos, uint changed_length,
+ int move_length,
+ uchar *key_buff, my_bool insert_last_key)
+{
+ uint length,a_length,key_ref_length,t_length,nod_flag,key_length;
+ uint page_length, split_length, page_flag;
+ uchar *key_pos,*pos, *after_key, *new_buff;
+ my_off_t new_pos;
+ MARIA_KEY_PARAM s_temp;
+ MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ MARIA_KEY tmp_key;
+ int res;
+ DBUG_ENTER("_ma_split_page");
+
+ LINT_INIT(after_key);
+ DBUG_DUMP("buff", split_buff, _ma_get_page_used(share, split_buff));
+
+ info->page_changed=1; /* Info->buff is used */
+ info->keyread_buff_used=1;
+ new_buff= info->buff;
+ page_flag= _ma_get_keypage_flag(share, split_buff);
+ nod_flag= _ma_test_if_nod(share, split_buff);
+ key_ref_length= share->keypage_header + nod_flag;
+
+ tmp_key.data= key_buff;
+ tmp_key.keyinfo= keyinfo;
+ if (insert_last_key)
+ key_pos= _ma_find_last_pos(info, &tmp_key, split_buff, &after_key);
+ else
+ key_pos= _ma_find_half_pos(info, &tmp_key, nod_flag, split_buff,
+ &after_key);
+ if (!key_pos)
+ DBUG_RETURN(-1);
+
+ key_length= tmp_key.data_length + tmp_key.ref_length;
+ split_length= (uint) (key_pos - split_buff);
+ a_length= _ma_get_page_used(share, split_buff);
+ _ma_store_page_used(share, split_buff, split_length);
+
+ key_pos=after_key;
+ if (nod_flag)
+ {
+ DBUG_PRINT("test",("Splitting nod"));
+ pos=key_pos-nod_flag;
+ memcpy((uchar*) new_buff + share->keypage_header, (uchar*) pos,
+ (size_t) nod_flag);
+ }
+
+ /* Move middle item to key and pointer to new page */
+ if ((new_pos= _ma_new(info, PAGECACHE_PRIORITY_HIGH, &page_link)) ==
+ HA_OFFSET_ERROR)
+ DBUG_RETURN(-1);
+
+ _ma_copy_key(key, &tmp_key);
+ _ma_kpointer(info, key->data + key_length, new_pos);
+
+ /* Store new page */
+ if (!(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &key_pos))
+ DBUG_RETURN(-1);
+
+ t_length=(*keyinfo->pack_key)(&tmp_key, nod_flag, (uchar *) 0,
+ (uchar*) 0, (uchar*) 0, &s_temp);
+ length=(uint) ((split_buff + a_length) - key_pos);
+ memcpy((uchar*) new_buff+key_ref_length+t_length,(uchar*) key_pos,
+ (size_t) length);
+ (*keyinfo->store_key)(keyinfo,new_buff+key_ref_length,&s_temp);
+ page_length= length + t_length + key_ref_length;
+
+ bzero(new_buff, share->keypage_header);
+ /* Copy KEYFLAG_FLAG_ISNODE and KEYPAGE_FLAG_HAS_TRANSID from parent page */
+ _ma_store_keypage_flag(share, new_buff, page_flag);
+ _ma_store_page_used(share, new_buff, page_length);
+ /* Copy key number */
+ new_buff[share->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_KEYID_SIZE -
+ KEYPAGE_FLAG_SIZE]=
+ split_buff[share->keypage_header - KEYPAGE_USED_SIZE -
+ KEYPAGE_KEYID_SIZE - KEYPAGE_FLAG_SIZE];
+
+ res= 2; /* Middle key up */
+ if (share->now_transactional &&
+ _ma_log_new(info, new_pos, new_buff, page_length, keyinfo->key_nr, 0))
+ res= -1;
+ bzero(new_buff + page_length, share->block_size - page_length);
+
+ if (_ma_write_keypage(info, keyinfo, new_pos, page_link->write_lock,
+ DFLT_INIT_HITS, new_buff))
+ res= -1;
+
+ /* Save changes to split pages */
+ if (share->now_transactional &&
+ _ma_log_split(info, split_page, split_buff, org_split_length,
+ split_length,
+ inserted_key_pos, changed_length, move_length,
+ KEY_OP_NONE, (uchar*) 0, 0, 0))
+ res= -1;
+
+ DBUG_DUMP_KEY("middle_key", key);
+ DBUG_RETURN(res);
+} /* _ma_split_page */
+
+
+/*
+ Calculate how to much to move to split a page in two
+
+ Returns pointer to start of key.
+ key will contain the key.
+ return_key_length will contain the length of key
+ after_key will contain the position to where the next key starts
+*/
+
+uchar *_ma_find_half_pos(MARIA_HA *info, MARIA_KEY *key, uint nod_flag,
+ uchar *page, uchar **after_key)
+{
+ uint keys, length, key_ref_length, page_flag;
+ uchar *end,*lastpos;
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ DBUG_ENTER("_ma_find_half_pos");
+
+ key_ref_length= share->keypage_header + nod_flag;
+ page_flag= _ma_get_keypage_flag(share, page);
+ length= _ma_get_page_used(share, page) - key_ref_length;
+ page+= key_ref_length; /* Point to first key */
+ if (!(keyinfo->flag &
+ (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
+ HA_BINARY_PACK_KEY)) && !(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ {
+ key_ref_length= keyinfo->keylength+nod_flag;
+ key->data_length= keyinfo->keylength - info->s->rec_reflength;
+ key->ref_length= info->s->rec_reflength;
+ key->flag= 0;
+ keys=length/(key_ref_length*2);
+ end=page+keys*key_ref_length;
+ *after_key=end+key_ref_length;
+ memcpy(key->data, end, key_ref_length);
+ DBUG_RETURN(end);
+ }
+
+ end=page+length/2-key_ref_length; /* This is aprox. half */
+ key->data[0]= 0; /* Safety */
+ do
+ {
+ lastpos=page;
+ if (!(length= (*keyinfo->get_key)(key, page_flag, nod_flag, &page)))
+ DBUG_RETURN(0);
+ } while (page < end);
+ *after_key= page;
+ DBUG_PRINT("exit",("returns: 0x%lx page: 0x%lx half: 0x%lx",
+ (long) lastpos, (long) page, (long) end));
+ DBUG_RETURN(lastpos);
+} /* _ma_find_half_pos */
+
+
+/**
+ Find second to last key on leaf page
+
+ @notes
+ Used to split buffer at last key. In this case the next to last
+ key will be moved to parent page and last key will be on it's own page.
+
+ @TODO
+ Add one argument for 'last key value' to get_key so that one can
+ do the loop without having to copy the found key the whole time
+
+ @return
+ @retval Pointer to the start of the key before the last key
+ @retval int_key will contain the last key
+*/
+
+static uchar *_ma_find_last_pos(MARIA_HA *info, MARIA_KEY *int_key,
+ uchar *page, uchar **after_key)
+{
+ uint keys, length, key_ref_length, page_flag;
+ uchar *end, *lastpos, *prevpos;
+ uchar key_buff[MARIA_MAX_KEY_BUFF];
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= int_key->keyinfo;
+ MARIA_KEY tmp_key;
+ DBUG_ENTER("_ma_find_last_pos");
+
+ key_ref_length= share->keypage_header;
+ page_flag= _ma_get_keypage_flag(share, page);
+ length= _ma_get_page_used(share, page) - key_ref_length;
+ page+=key_ref_length;
+ if (!(keyinfo->flag &
+ (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
+ HA_BINARY_PACK_KEY)) && !(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
+ {
+ keys= length / keyinfo->keylength - 2;
+ length= keyinfo->keylength;
+ int_key->data_length= length - info->s->rec_reflength;
+ int_key->ref_length= info->s->rec_reflength;
+ int_key->flag= 0;
+ end=page+keys*length;
+ *after_key=end+length;
+ memcpy(int_key->data, end, length);
+ DBUG_RETURN(end);
+ }
+
+ end=page+length-key_ref_length;
+ lastpos=page;
+ tmp_key.data= key_buff;
+ tmp_key.keyinfo= int_key->keyinfo;
+ key_buff[0]= 0; /* Safety */
+
+ /* We know that there are at least 2 keys on the page */
+
+ if (!(length=(*keyinfo->get_key)(&tmp_key, page_flag, 0, &page)))
+ {
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
+ }
+
+ do
+ {
+ prevpos=lastpos; lastpos=page;
+ int_key->data_length= tmp_key.data_length;
+ int_key->ref_length= tmp_key.ref_length;
+ int_key->flag= tmp_key.flag;
+ memcpy(int_key->data, key_buff, length); /* previous key */
+ if (!(length=(*keyinfo->get_key)(&tmp_key, page_flag, 0, &page)))
+ {
+ maria_print_error(keyinfo->share, HA_ERR_CRASHED);
+ my_errno=HA_ERR_CRASHED;
+ DBUG_RETURN(0);
+ }
+ } while (page < end);
+
+ *after_key=lastpos;
+ DBUG_PRINT("exit",("returns: 0x%lx page: 0x%lx end: 0x%lx",
+ (long) prevpos,(long) page,(long) end));
+ DBUG_RETURN(prevpos);
+} /* _ma_find_last_pos */
+
+
+/**
+ @brief Balance page with static size keys with page on right/left
+
+ @param key Middle key will be stored here
+
+ @notes
+ Father_buff will always be changed
+ Caller must handle saving of curr_buff
+
+ @return
+ @retval 0 Balance was done (father buff is saved)
+ @retval 1 Middle key up (father buff is not saved)
+ @retval -1 Error
+*/
+
+static int _ma_balance_page(register MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ MARIA_KEY *key, uchar *curr_buff,
+ my_off_t curr_page,
+ my_off_t father_page, uchar *father_buff,
+ uchar *father_key_pos, MARIA_KEY_PARAM *s_temp)
+{
+ MARIA_PINNED_PAGE *next_page_link;
+ MARIA_PINNED_PAGE tmp_page_link, *new_page_link= &tmp_page_link;
+ MARIA_SHARE *share= info->s;
+ my_bool right;
+ uint k_length,father_length,father_keylength,nod_flag,curr_keylength;
+ uint right_length,left_length,new_right_length,new_left_length,extra_length;
+ uint keys, tmp_length, extra_buff_length;
+ uchar *pos,*buff,*extra_buff, *parting_key;
+ my_off_t next_page,new_pos;
+ uchar tmp_part_key[MARIA_MAX_KEY_BUFF];
+ DBUG_ENTER("_ma_balance_page");
+
+ k_length=keyinfo->keylength;
+ father_length= _ma_get_page_used(share, father_buff);
+ father_keylength= k_length + share->base.key_reflength;
+ nod_flag= _ma_test_if_nod(share, curr_buff);
+ curr_keylength=k_length+nod_flag;
+ info->page_changed=1;
+
+ if ((father_key_pos != father_buff+father_length &&
+ (info->state->records & 1)) ||
+ father_key_pos == father_buff+ share->keypage_header +
+ share->base.key_reflength)
+ {
+ right=1;
+ next_page= _ma_kpos(share->base.key_reflength,
+ father_key_pos+father_keylength);
+ buff=info->buff;
+ DBUG_PRINT("info", ("use right page: %lu", (ulong) next_page));
+ }
+ else
+ {
+ right=0;
+ father_key_pos-=father_keylength;
+ next_page= _ma_kpos(share->base.key_reflength,father_key_pos);
+ /* Move curr_buff so that it's on the left */
+ buff= curr_buff;
+ curr_buff= info->buff;
+ DBUG_PRINT("info", ("use left page: %lu", (ulong) next_page));
+ } /* father_key_pos ptr to parting key */
+
+ if (!_ma_fetch_keypage(info,keyinfo, next_page, PAGECACHE_LOCK_WRITE,
+ DFLT_INIT_HITS, info->buff, 0, &next_page_link))
+ goto err;
+ next_page_link->changed= 1;
+ DBUG_DUMP("next", info->buff, _ma_get_page_used(share, info->buff));
+
+ /* Test if there is room to share keys */
+ left_length= _ma_get_page_used(share, curr_buff);
+ right_length= _ma_get_page_used(share, buff);
+ keys= ((left_length+right_length-share->keypage_header*2-nod_flag*2)/
+ curr_keylength);
+
+ if ((right ? right_length : left_length) + curr_keylength <=
+ (uint) keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)
+ {
+ /* Enough space to hold all keys in the two buffers ; Balance bufferts */
+ new_left_length= share->keypage_header+nod_flag+(keys/2)*curr_keylength;
+ new_right_length=share->keypage_header+nod_flag+(((keys+1)/2)*
+ curr_keylength);
+ _ma_store_page_used(share, curr_buff, new_left_length);
+ _ma_store_page_used(share, buff, new_right_length);
+
+ DBUG_PRINT("info", ("left_length: %u -> %u right_length: %u -> %u",
+ left_length, new_left_length,
+ right_length, new_right_length));
+ if (left_length < new_left_length)
+ {
+ uint length;
+ DBUG_PRINT("info", ("move keys to end of buff"));
+
+ /* Move keys buff -> curr_buff */
+ pos=curr_buff+left_length;
+ memcpy(pos,father_key_pos, (size_t) k_length);
+ memcpy(pos+k_length, buff + share->keypage_header,
+ (size_t) (length=new_left_length - left_length - k_length));
+ pos= buff + share->keypage_header + length;
+ memcpy(father_key_pos, pos, (size_t) k_length);
+ bmove(buff + share->keypage_header, pos + k_length, new_right_length);
+
+ if (share->now_transactional)
+ {
+ if (right)
+ {
+ /*
+ Log changes to page on left
+ The original page is on the left and stored in curr_buff
+ We have on the page the newly inserted key and data
+ from buff added last on the page
+ */
+ if (_ma_log_split(info, curr_page, curr_buff,
+ left_length - s_temp->move_length,
+ new_left_length,
+ s_temp->key_pos, s_temp->changed_length,
+ s_temp->move_length,
+ KEY_OP_ADD_SUFFIX,
+ curr_buff + left_length,
+ new_left_length - left_length,
+ new_left_length - left_length+ k_length))
+ goto err;
+ /*
+ Log changes to page on right
+ This contains the original data with some keys deleted from
+ start of page
+ */
+ if (_ma_log_prefix(info, next_page, buff, 0,
+ ((int) new_right_length - (int) right_length)))
+ goto err;
+ }
+ else
+ {
+ /*
+ Log changes to page on right (the original page) which is in buff
+ Data is removed from start of page
+ The inserted key may be in buff or moved to curr_buff
+ */
+ if (_ma_log_del_prefix(info, curr_page, buff,
+ right_length - s_temp->changed_length,
+ new_right_length,
+ s_temp->key_pos, s_temp->changed_length,
+ s_temp->move_length))
+ goto err;
+ /*
+ Log changes to page on left, which has new data added last
+ */
+ if (_ma_log_suffix(info, next_page, curr_buff,
+ left_length, new_left_length))
+ goto err;
+ }
+ }
+ }
+ else
+ {
+ uint length;
+ DBUG_PRINT("info", ("move keys to start of buff"));
+
+ bmove_upp(buff + new_right_length, buff + right_length,
+ right_length - share->keypage_header);
+ length= new_right_length -right_length - k_length;
+ memcpy(buff + share->keypage_header + length, father_key_pos,
+ (size_t) k_length);
+ pos=curr_buff+new_left_length;
+ memcpy(father_key_pos, pos, (size_t) k_length);
+ memcpy(buff + share->keypage_header, pos+k_length, (size_t) length);
+
+ if (share->now_transactional)
+ {
+ if (right)
+ {
+ /*
+ Log changes to page on left
+ The original page is on the left and stored in curr_buff
+ The page is shortened from end and the key may be on the page
+ */
+ if (_ma_log_split(info, curr_page, curr_buff,
+ left_length - s_temp->move_length,
+ new_left_length,
+ s_temp->key_pos, s_temp->changed_length,
+ s_temp->move_length,
+ KEY_OP_NONE, (uchar*) 0, 0, 0))
+ goto err;
+ /*
+ Log changes to page on right
+ This contains the original data, with some data from cur_buff
+ added first
+ */
+ if (_ma_log_prefix(info, next_page, buff,
+ (uint) (new_right_length - right_length),
+ (int) (new_right_length - right_length)))
+ goto err;
+ }
+ else
+ {
+ /*
+ Log changes to page on right (the original page) which is in buff
+ We have on the page the newly inserted key and data
+ from buff added first on the page
+ */
+ uint diff_length= new_right_length - right_length;
+ if (_ma_log_split(info, curr_page, buff,
+ left_length - s_temp->move_length,
+ new_right_length,
+ s_temp->key_pos + diff_length,
+ s_temp->changed_length,
+ s_temp->move_length,
+ KEY_OP_ADD_PREFIX,
+ buff + share->keypage_header,
+ diff_length, diff_length + k_length))
+ goto err;
+ /*
+ Log changes to page on left, which is shortened from end
+ */
+ if (_ma_log_suffix(info, next_page, curr_buff,
+ left_length, new_left_length))
+ goto err;
+ }
+ }
+ }
+
+ /* Log changes to father (one level up) page */
+
+ if (share->now_transactional &&
+ _ma_log_change(info, father_page, father_buff, father_key_pos,
+ k_length))
+ goto err;
+
+ /*
+ next_page_link->changed is marked as true above and fathers
+ page_link->changed is marked as true in caller
+ */
+ if (_ma_write_keypage(info, keyinfo, next_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ DFLT_INIT_HITS, info->buff) ||
+ _ma_write_keypage(info, keyinfo, father_page,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS,
+ father_buff))
+ goto err;
+ DBUG_RETURN(0);
+ }
+
+ /* curr_buff[] and buff[] are full, lets split and make new nod */
+
+ extra_buff= info->buff+share->base.max_key_block_length;
+ new_left_length= new_right_length= (share->keypage_header + nod_flag +
+ (keys+1) / 3 * curr_keylength);
+ /*
+ 5 is the minum number of keys we can have here. This comes from
+ the fact that each full page can store at least 2 keys and in this case
+ we have a 'split' key, ie 2+2+1 = 5
+ */
+ if (keys == 5) /* Too few keys to balance */
+ new_left_length-=curr_keylength;
+ extra_length= (nod_flag + left_length + right_length -
+ new_left_length - new_right_length - curr_keylength);
+ extra_buff_length= extra_length + share->keypage_header;
+ DBUG_PRINT("info",("left_length: %d right_length: %d new_left_length: %d new_right_length: %d extra_length: %d",
+ left_length, right_length,
+ new_left_length, new_right_length,
+ extra_length));
+ _ma_store_page_used(share, curr_buff, new_left_length);
+ _ma_store_page_used(share, buff, new_right_length);
+
+ bzero(extra_buff, share->keypage_header);
+ if (nod_flag)
+ _ma_store_keypage_flag(share, extra_buff, KEYPAGE_FLAG_ISNOD);
+ /* Copy key number */
+ extra_buff[share->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_KEYID_SIZE -
+ KEYPAGE_FLAG_SIZE]=
+ buff[share->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_KEYID_SIZE -
+ KEYPAGE_FLAG_SIZE];
+ _ma_store_page_used(share, extra_buff, extra_buff_length);
+
+ /* move first largest keys to new page */
+ pos=buff+right_length-extra_length;
+ memcpy(extra_buff + share->keypage_header, pos, extra_length);
+ /* Zero old data from buffer */
+ bzero(extra_buff + extra_buff_length,
+ share->block_size - extra_buff_length);
+
+ /* Save new parting key between buff and extra_buff */
+ memcpy(tmp_part_key, pos-k_length,k_length);
+ /* Make place for new keys */
+ bmove_upp(buff+ new_right_length, pos - k_length,
+ right_length - extra_length - k_length - share->keypage_header);
+ /* Copy keys from left page */
+ pos= curr_buff+new_left_length;
+ memcpy(buff + share->keypage_header, pos + k_length,
+ (size_t) (tmp_length= left_length - new_left_length - k_length));
+ /* Copy old parting key */
+ parting_key= buff + share->keypage_header + tmp_length;
+ memcpy(parting_key, father_key_pos, (size_t) k_length);
+
+ /* Move new parting keys up to caller */
+ memcpy((right ? key->data : father_key_pos),pos,(size_t) k_length);
+ memcpy((right ? father_key_pos : key->data),tmp_part_key, k_length);
+
+ if ((new_pos= _ma_new(info, DFLT_INIT_HITS, &new_page_link))
+ == HA_OFFSET_ERROR)
+ goto err;
+ _ma_kpointer(info,key->data+k_length,new_pos);
+ /* This is safe as long we are using not keys with transid */
+ key->data_length= k_length - info->s->rec_reflength;
+ key->ref_length= info->s->rec_reflength;
+
+ if (share->now_transactional)
+ {
+ if (right)
+ {
+ /*
+ Page order according to key values:
+ orignal_page (curr_buff), next_page (buff), extra_buff
+
+ cur_buff is shortened,
+ buff is getting new keys at start and shortened from end.
+ extra_buff is new page
+
+ Note that extra_buff (largest key parts) will be stored at the
+ place of the original 'right' page (next_page) and right page (buff)
+ will be stored at new_pos.
+
+ This makes the log entries smaller as right_page contains all
+ data to generate the data extra_buff
+ */
+
+ /*
+ Log changes to page on left (page shortened page at end)
+ */
+ if (_ma_log_split(info, curr_page, curr_buff,
+ left_length - s_temp->move_length, new_left_length,
+ s_temp->key_pos, s_temp->changed_length,
+ s_temp->move_length,
+ KEY_OP_NONE, (uchar*) 0, 0, 0))
+ goto err;
+ /*
+ Log changes to right page (stored at next page)
+ This contains the last 'extra_buff' from 'buff'
+ */
+ if (_ma_log_prefix(info, next_page, extra_buff,
+ 0, (int) (extra_buff_length - right_length)))
+ goto err;
+
+ /*
+ Log changes to middle page, which is stored at the new page
+ position
+ */
+ if (_ma_log_new(info, new_pos, buff, new_right_length,
+ keyinfo->key_nr, 0))
+ goto err;
+ }
+ else
+ {
+ /*
+ Log changes to page on right (the original page) which is in buff
+ This contains the original data, with some data from curr_buff
+ added first and shortened at end
+ */
+ int data_added_first= left_length - new_left_length;
+ if (_ma_log_key_middle(info, curr_page, buff,
+ new_right_length,
+ data_added_first,
+ data_added_first,
+ extra_length,
+ s_temp->key_pos,
+ s_temp->changed_length,
+ s_temp->move_length))
+ goto err;
+
+ /* Log changes to page on left, which is shortened from end */
+ if (_ma_log_suffix(info, next_page, curr_buff,
+ left_length, new_left_length))
+ goto err;
+
+ /* Log change to rightmost (new) page */
+ if (_ma_log_new(info, new_pos, extra_buff,
+ extra_buff_length, keyinfo->key_nr, 0))
+ goto err;
+ }
+
+ /* Log changes to father (one level up) page */
+ if (share->now_transactional &&
+ _ma_log_change(info, father_page, father_buff, father_key_pos,
+ k_length))
+ goto err;
+ }
+
+ if (_ma_write_keypage(info, keyinfo, (right ? new_pos : next_page),
+ (right ? new_page_link->write_lock :
+ PAGECACHE_LOCK_LEFT_WRITELOCKED),
+ DFLT_INIT_HITS, info->buff) ||
+ _ma_write_keypage(info, keyinfo, (right ? next_page : new_pos),
+ (!right ? new_page_link->write_lock :
+ PAGECACHE_LOCK_LEFT_WRITELOCKED),
+ DFLT_INIT_HITS, extra_buff))
+ goto err;
+
+ DBUG_RETURN(1); /* Middle key up */
+
+err:
+ DBUG_RETURN(-1);
+} /* _ma_balance_page */
+
+
+/**********************************************************************
+ * Bulk insert code *
+ **********************************************************************/
+
+typedef struct {
+ MARIA_HA *info;
+ uint keynr;
+} bulk_insert_param;
+
+
+static my_bool _ma_ck_write_tree(register MARIA_HA *info, MARIA_KEY *key)
+{
+ my_bool error;
+ uint keynr= key->keyinfo->key_nr;
+ DBUG_ENTER("_ma_ck_write_tree");
+
+ /* Store ref_length as this is always constant */
+ info->bulk_insert_ref_length= key->ref_length;
+ error= tree_insert(&info->bulk_insert[keynr], key->data,
+ key->data_length + key->ref_length,
+ info->bulk_insert[keynr].custom_arg) == 0;
+ DBUG_RETURN(error);
+} /* _ma_ck_write_tree */
+
+
+/* typeof(_ma_keys_compare)=qsort_cmp2 */
+
+static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2)
+{
+ uint not_used[2];
+ return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
+ key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
+ not_used);
+}
+
+
+static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
+{
+ /*
+ Probably I can use info->lastkey here, but I'm not sure,
+ and to be safe I'd better use local lastkey.
+ */
+ MARIA_SHARE *share= param->info->s;
+ uchar lastkey[MARIA_MAX_KEY_BUFF];
+ uint keylen;
+ MARIA_KEYDEF *keyinfo= share->keyinfo + param->keynr;
+ MARIA_KEY tmp_key;
+
+ switch (mode) {
+ case free_init:
+ if (share->lock_key_trees)
+ {
+ rw_wrlock(&keyinfo->root_lock);
+ keyinfo->version++;
+ }
+ return 0;
+ case free_free:
+ /* Note: keylen doesn't contain transid lengths */
+ keylen= _ma_keylength(keyinfo, key);
+ tmp_key.data= lastkey;
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data_length= keylen - share->rec_reflength;
+ tmp_key.ref_length= param->info->bulk_insert_ref_length;
+ tmp_key.flag= (param->info->bulk_insert_ref_length ==
+ share->rec_reflength ? 0 : SEARCH_USER_KEY_HAS_TRANSID);
+ /*
+ We have to copy key as ma_ck_write_btree may need the buffer for
+ copying middle key up if tree is growing
+ */
+ memcpy(lastkey, key, tmp_key.data_length + tmp_key.ref_length);
+ return _ma_ck_write_btree(param->info, &tmp_key);
+ case free_end:
+ if (share->lock_key_trees)
+ rw_unlock(&keyinfo->root_lock);
+ return 0;
+ }
+ return 1;
+}
+
+
+int maria_init_bulk_insert(MARIA_HA *info, ulong cache_size, ha_rows rows)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *key=share->keyinfo;
+ bulk_insert_param *params;
+ uint i, num_keys, total_keylength;
+ ulonglong key_map;
+ DBUG_ENTER("_ma_init_bulk_insert");
+ DBUG_PRINT("enter",("cache_size: %lu", cache_size));
+
+ DBUG_ASSERT(!info->bulk_insert &&
+ (!rows || rows >= MARIA_MIN_ROWS_TO_USE_BULK_INSERT));
+
+ maria_clear_all_keys_active(key_map);
+ for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
+ {
+ if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) &&
+ maria_is_key_active(share->state.key_map, i))
+ {
+ num_keys++;
+ maria_set_key_active(key_map, i);
+ total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
+ }
+ }
+
+ if (num_keys==0 ||
+ num_keys * MARIA_MIN_SIZE_BULK_INSERT_TREE > cache_size)
+ DBUG_RETURN(0);
+
+ if (rows && rows*total_keylength < cache_size)
+ cache_size= (ulong)rows;
+ else
+ cache_size/=total_keylength*16;
+
+ info->bulk_insert=(TREE *)
+ my_malloc((sizeof(TREE)*share->base.keys+
+ sizeof(bulk_insert_param)*num_keys),MYF(0));
+
+ if (!info->bulk_insert)
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+ params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
+ for (i=0 ; i < share->base.keys ; i++)
+ {
+ if (maria_is_key_active(key_map, i))
+ {
+ params->info=info;
+ params->keynr=i;
+ /* Only allocate a 16'th of the buffer at a time */
+ init_tree(&info->bulk_insert[i],
+ cache_size * key[i].maxlength,
+ cache_size * key[i].maxlength, 0,
+ (qsort_cmp2)keys_compare, 0,
+ (tree_element_free) keys_free, (void *)params++);
+ }
+ else
+ info->bulk_insert[i].root=0;
+ }
+
+ DBUG_RETURN(0);
+}
+
+void maria_flush_bulk_insert(MARIA_HA *info, uint inx)
+{
+ if (info->bulk_insert)
+ {
+ if (is_tree_inited(&info->bulk_insert[inx]))
+ reset_tree(&info->bulk_insert[inx]);
+ }
+}
+
+void maria_end_bulk_insert(MARIA_HA *info, my_bool abort)
+{
+ DBUG_ENTER("maria_end_bulk_insert");
+ if (info->bulk_insert)
+ {
+ uint i;
+ for (i=0 ; i < info->s->base.keys ; i++)
+ {
+ if (is_tree_inited(&info->bulk_insert[i]))
+ {
+ if (abort)
+ reset_free_element(&info->bulk_insert[i]);
+ delete_tree(&info->bulk_insert[i]);
+ }
+ }
+ my_free(info->bulk_insert, MYF(0));
+ info->bulk_insert= 0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/****************************************************************************
+ Dedicated functions that generate log entries
+****************************************************************************/
+
+
+int _ma_write_undo_key_insert(MARIA_HA *info, const MARIA_KEY *key,
+ my_off_t *root, my_off_t new_root, LSN *res_lsn)
+{
+ MARIA_SHARE *share= info->s;
+ MARIA_KEYDEF *keyinfo= key->keyinfo;
+ uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
+ KEY_NR_STORE_SIZE];
+ const uchar *key_value;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ struct st_msg_to_write_hook_for_undo_key msg;
+ uint key_length;
+
+ /* Save if we need to write a clr record */
+ lsn_store(log_data, info->trn->undo_lsn);
+ key_nr_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
+ keyinfo->key_nr);
+ key_length= key->data_length + key->ref_length;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key->data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= key_length;
+
+ msg.root= root;
+ msg.value= new_root;
+ msg.auto_increment= 0;
+ key_value= key->data;
+ if (share->base.auto_key == ((uint) keyinfo->key_nr + 1))
+ {
+ const HA_KEYSEG *keyseg= keyinfo->seg;
+ uchar reversed[MARIA_MAX_KEY_BUFF];
+ if (keyseg->flag & HA_SWAP_KEY)
+ {
+ /* We put key from log record to "data record" packing format... */
+ const uchar *key_ptr= key->data, *key_end= key->data + keyseg->length;
+ uchar *to= reversed + keyseg->length;
+ do
+ {
+ *--to= *key_ptr++;
+ } while (key_ptr != key_end);
+ key_value= to;
+ }
+ /* ... so that we can read it with: */
+ msg.auto_increment=
+ ma_retrieve_auto_increment(key_value, keyseg->type);
+ /* and write_hook_for_undo_key_insert() will pick this. */
+ }
+
+ return translog_write_record(res_lsn, LOGREC_UNDO_KEY_INSERT,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length +
+ key_length,
+ TRANSLOG_INTERNAL_PARTS + 2, log_array,
+ log_data + LSN_STORE_SIZE, &msg) ? -1 : 0;
+}
+
+
+/**
+ @brief Log creation of new page
+
+ @note
+ We don't have to store the page_length into the log entry as we can
+ calculate this from the length of the log entry
+
+ @retval 1 error
+ @retval 0 ok
+*/
+
+my_bool _ma_log_new(MARIA_HA *info, my_off_t page, const uchar *buff,
+ uint page_length, uint key_nr, my_bool root_page)
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2 + KEY_NR_STORE_SIZE
+ +1];
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ MARIA_SHARE *share= info->s;
+ DBUG_ENTER("_ma_log_new");
+ DBUG_PRINT("enter", ("page: %lu", (ulong) page));
+
+ DBUG_ASSERT(share->now_transactional);
+
+ /* Store address of new root page */
+ page/= share->block_size;
+ page_store(log_data + FILEID_STORE_SIZE, page);
+
+ /* Store link to next unused page */
+ if (info->key_del_used == 2)
+ page= 0; /* key_del not changed */
+ else
+ page= ((share->key_del_current == HA_OFFSET_ERROR) ? IMPOSSIBLE_PAGE_NO :
+ share->key_del_current / share->block_size);
+
+ page_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, page);
+ key_nr_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE*2, key_nr);
+ log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE*2 + KEY_NR_STORE_SIZE]=
+ (uchar) root_page;
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
+
+ page_length-= LSN_STORE_SIZE;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= buff + LSN_STORE_SIZE;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= page_length;
+
+ if (translog_write_record(&lsn, LOGREC_REDO_INDEX_NEW_PAGE,
+ info->trn, info,
+ (translog_size_t) (sizeof(log_data) + page_length),
+ TRANSLOG_INTERNAL_PARTS + 2, log_array,
+ log_data, NULL))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief
+ Log when some part of the key page changes
+*/
+
+my_bool _ma_log_change(MARIA_HA *info, my_off_t page, const uchar *buff,
+ const uchar *key_pos, uint length)
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 6 + 7], *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
+ uint offset= (uint) (key_pos - buff), translog_parts, extra_length= 0;
+ DBUG_ENTER("_ma_log_change");
+ DBUG_PRINT("enter", ("page: %lu length: %u", (ulong) page, length));
+
+ DBUG_ASSERT(info->s->now_transactional);
+
+ /* Store address of new root page */
+ page/= info->s->block_size;
+ page_store(log_data + FILEID_STORE_SIZE, page);
+ log_pos= log_data+ FILEID_STORE_SIZE + PAGE_STORE_SIZE;
+ log_pos[0]= KEY_OP_OFFSET;
+ int2store(log_pos+1, offset);
+ log_pos[3]= KEY_OP_CHANGE;
+ int2store(log_pos+4, length);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data) - 7;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= length;
+ translog_parts= 2;
+
+#ifdef EXTRA_DEBUG_KEY_CHANGES
+ {
+ int page_length= _ma_get_page_used(info->s, buff);
+ ha_checksum crc;
+ crc= my_checksum(0, buff + LSN_STORE_SIZE, page_length - LSN_STORE_SIZE);
+ log_pos+= 6;
+ log_pos[0]= KEY_OP_CHECK;
+ int2store(log_pos+1, page_length);
+ int4store(log_pos+3, crc);
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= log_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= 7;
+ extra_length+= 7;
+ translog_parts++;
+ }
+#endif
+
+ if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t) (sizeof(log_data) - 7 + length +
+ extra_length),
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/**
+ @brief Write log entry for page splitting
+
+ @note
+ Write log entry for page that has got a key added to the page under
+ one and only one of the following senarios:
+ - Page is shortened from end
+ - Data is added to end of page
+ - Data added at front of page
+
+ @param prefix_or_suffix KEY_OP_NONE Ignored
+ KEY_OP_ADD_PREFIX Add data to start of page
+ KEY_OP_ADD_SUFFIX Add data to end of page
+
+*/
+
+static my_bool _ma_log_split(MARIA_HA *info, my_off_t page, const uchar *buff,
+ uint org_length, uint new_length,
+ const uchar *key_pos, uint key_length,
+ int move_length, enum en_key_op prefix_or_suffix,
+ const uchar *data, uint data_length,
+ uint changed_length)
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 3+3+3+3+3+2];
+ uchar *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
+ uint offset= (uint) (key_pos - buff);
+ uint translog_parts, extra_length;
+ DBUG_ENTER("_ma_log_split");
+ DBUG_PRINT("enter", ("page: %lu org_length: %u new_length: %u",
+ (ulong) page, org_length, new_length));
+
+ log_pos= log_data + FILEID_STORE_SIZE;
+ page/= info->s->block_size;
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+
+ if (new_length <= offset || !key_pos)
+ {
+ /*
+ Page was split before inserted key. Write redo entry where
+ we just cut current page at page_length
+ */
+ uint length_offset= org_length - new_length;
+ log_pos[0]= KEY_OP_DEL_SUFFIX;
+ int2store(log_pos+1, length_offset);
+ log_pos+= 3;
+ translog_parts= 1;
+ extra_length= 0;
+ }
+ else
+ {
+ /* Key was added to page which was split after the inserted key */
+ uint max_key_length;
+
+ /*
+ Handle case when split happened directly after the newly inserted key.
+ */
+ max_key_length= new_length - offset;
+ extra_length= min(key_length, max_key_length);
+
+ if ((int) new_length < (int) (org_length + move_length + data_length))
+ {
+ /* Shorten page */
+ uint diff= org_length + move_length + data_length - new_length;
+ log_pos[0]= KEY_OP_DEL_SUFFIX;
+ int2store(log_pos + 1, diff);
+ log_pos+= 3;
+ }
+ else
+ {
+ DBUG_ASSERT(new_length == org_length + move_length + data_length);
+ }
+
+ log_pos[0]= KEY_OP_OFFSET;
+ int2store(log_pos+1, offset);
+ log_pos+= 3;
+
+ if (move_length)
+ {
+ log_pos[0]= KEY_OP_SHIFT;
+ int2store(log_pos+1, move_length);
+ log_pos+= 3;
+ }
+
+ log_pos[0]= KEY_OP_CHANGE;
+ int2store(log_pos+1, extra_length);
+ log_pos+= 3;
+
+ /* Point to original inserted key data */
+ if (prefix_or_suffix == KEY_OP_ADD_PREFIX)
+ key_pos+= data_length;
+
+ translog_parts= 2;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= extra_length;
+ }
+
+ if (data_length)
+ {
+ /* Add prefix or suffix */
+ log_pos[0]= prefix_or_suffix;
+ int2store(log_pos+1, data_length);
+ log_pos+= 3;
+ if (prefix_or_suffix == KEY_OP_ADD_PREFIX)
+ {
+ int2store(log_pos+1, changed_length);
+ log_pos+= 2;
+ data_length= changed_length;
+ }
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= data;
+ log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= data_length;
+ translog_parts++;
+ extra_length+= data_length;
+ }
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
+ log_data);
+ DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + extra_length,
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL));
+}
+
+
+/**
+ @brief
+ Write log entry for page that has got a key added to the page
+ and page is shortened from start of page
+
+ @fn _ma_log_del_prefix()
+ @param info Maria handler
+ @param page Page number
+ @param buff Page buffer
+ @param org_length Length of buffer when read
+ @param new_length Final length
+ @param key_pos Where on page buffer key was added. This is position
+ before prefix was removed
+ @param key_length How many bytes was changed at 'key_pos'
+ @param move_length How many bytes was moved up when key was added
+
+ @return
+ @retval 0 ok
+ @retval 1 error
+*/
+
+static my_bool _ma_log_del_prefix(MARIA_HA *info, my_off_t page,
+ const uchar *buff,
+ uint org_length, uint new_length,
+ const uchar *key_pos, uint key_length,
+ int move_length)
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 12], *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ uint offset= (uint) (key_pos - buff);
+ uint diff_length= org_length + move_length - new_length;
+ uint translog_parts, extra_length;
+ DBUG_ENTER("_ma_log_del_prefix");
+ DBUG_PRINT("enter", ("page: %lu org_length: %u new_length: %u",
+ (ulong) page, org_length, new_length));
+
+ DBUG_ASSERT((int) diff_length > 0);
+
+ log_pos= log_data + FILEID_STORE_SIZE;
+ page/= info->s->block_size;
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+
+ translog_parts= 1;
+ extra_length= 0;
+
+ if (offset < diff_length + info->s->keypage_header)
+ {
+ /*
+ Key is not anymore on page. Move data down, but take into account that
+ the original page had grown with 'move_length bytes'
+ */
+ DBUG_ASSERT(offset + key_length <= diff_length + info->s->keypage_header);
+
+ log_pos[0]= KEY_OP_DEL_PREFIX;
+ int2store(log_pos+1, diff_length - move_length);
+ log_pos+= 3;
+ }
+ else
+ {
+ /*
+ Correct position to key, as data before key has been delete and key
+ has thus been moved down
+ */
+ offset-= diff_length;
+ key_pos-= diff_length;
+
+ /* Move data down */
+ log_pos[0]= KEY_OP_DEL_PREFIX;
+ int2store(log_pos+1, diff_length);
+ log_pos+= 3;
+
+ log_pos[0]= KEY_OP_OFFSET;
+ int2store(log_pos+1, offset);
+ log_pos+= 3;
+
+ if (move_length)
+ {
+ log_pos[0]= KEY_OP_SHIFT;
+ int2store(log_pos+1, move_length);
+ log_pos+= 3;
+ }
+ log_pos[0]= KEY_OP_CHANGE;
+ int2store(log_pos+1, key_length);
+ log_pos+= 3;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= key_length;
+ translog_parts= 2;
+ extra_length= key_length;
+ }
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
+ log_data);
+ DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + extra_length,
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL));
+}
+
+
+/**
+ @brief
+ Write log entry for page that has got data added first and
+ data deleted last. Old changed key may be part of page
+*/
+
+static my_bool _ma_log_key_middle(MARIA_HA *info, my_off_t page,
+ const uchar *buff,
+ uint new_length,
+ uint data_added_first,
+ uint data_changed_first,
+ uint data_deleted_last,
+ const uchar *key_pos,
+ uint key_length, int move_length)
+{
+ LSN lsn;
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 3+5+3+3+3];
+ uchar *log_pos;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 4];
+ uint key_offset;
+ uint translog_parts, extra_length;
+ DBUG_ENTER("_ma_log_key_middle");
+ DBUG_PRINT("enter", ("page: %lu", (ulong) page));
+
+ /* new place of key after changes */
+ key_pos+= data_added_first;
+ key_offset= (uint) (key_pos - buff);
+ if (key_offset < new_length)
+ {
+ /* key is on page; Calculate how much of the key is there */
+ uint max_key_length= new_length - key_offset;
+ if (max_key_length < key_length)
+ {
+ /* Key is last on page */
+ key_length= max_key_length;
+ move_length= 0;
+ }
+ /*
+ Take into account that new data was added as part of original key
+ that also needs to be removed from page
+ */
+ data_deleted_last+= move_length;
+ }
+
+ page/= info->s->block_size;
+
+ /* First log changes to page */
+ log_pos= log_data + FILEID_STORE_SIZE;
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+
+ log_pos[0]= KEY_OP_DEL_SUFFIX;
+ int2store(log_pos+1, data_deleted_last);
+ log_pos+= 3;
+
+ log_pos[0]= KEY_OP_ADD_PREFIX;
+ int2store(log_pos+1, data_added_first);
+ int2store(log_pos+3, data_changed_first);
+ log_pos+= 5;
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
+ log_data);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (buff +
+ info->s->keypage_header);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= data_changed_first;
+ translog_parts= 2;
+ extra_length= data_changed_first;
+
+ /* If changed key is on page, log those changes too */
+
+ if (key_offset < new_length)
+ {
+ uchar *start_log_pos= log_pos;
+
+ log_pos[0]= KEY_OP_OFFSET;
+ int2store(log_pos+1, key_offset);
+ log_pos+= 3;
+ if (move_length)
+ {
+ log_pos[0]= KEY_OP_SHIFT;
+ int2store(log_pos+1, move_length);
+ log_pos+= 3;
+ }
+ log_pos[0]= KEY_OP_CHANGE;
+ int2store(log_pos+1, key_length);
+ log_pos+= 3;
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 2].str= start_log_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + 2].length= (uint) (log_pos -
+ start_log_pos);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 3].str= key_pos;
+ log_array[TRANSLOG_INTERNAL_PARTS + 3].length= key_length;
+ translog_parts+=2;
+ extra_length+= (uint) (log_array[TRANSLOG_INTERNAL_PARTS + 2].length +
+ key_length);
+ }
+
+ DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ (log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + extra_length),
+ TRANSLOG_INTERNAL_PARTS + translog_parts,
+ log_array, log_data, NULL));
+}
+
+
+#ifdef NOT_NEEDED
+
+/**
+ @brief
+ Write log entry for page that has got data added first and
+ data deleted last
+*/
+
+static my_bool _ma_log_middle(MARIA_HA *info, my_off_t page,
+ const uchar *buff,
+ uint data_added_first, uint data_changed_first,
+ uint data_deleted_last)
+{
+ LSN lsn;
+ LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 3 + 5], *log_pos;
+ DBUG_ENTER("_ma_log_middle");
+ DBUG_PRINT("enter", ("page: %lu", (ulong) page));
+
+ page/= info->s->block_size;
+
+ log_pos= log_data + FILEID_STORE_SIZE;
+ page_store(log_pos, page);
+ log_pos+= PAGE_STORE_SIZE;
+
+ log_pos[0]= KEY_OP_DEL_PREFIX;
+ int2store(log_pos+1, data_deleted_last);
+ log_pos+= 3;
+
+ log_pos[0]= KEY_OP_ADD_PREFIX;
+ int2store(log_pos+1, data_added_first);
+ int2store(log_pos+3, data_changed_first);
+ log_pos+= 5;
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
+ log_data);
+
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= ((char*) buff +
+ info->s->keypage_header);
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= data_changed_first;
+ DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
+ info->trn, info,
+ (translog_size_t)
+ log_array[TRANSLOG_INTERNAL_PARTS +
+ 0].length + data_changed_first,
+ TRANSLOG_INTERNAL_PARTS + 2,
+ log_array, log_data, NULL));
+}
+#endif
diff --git a/storage/maria/maria_chk.c b/storage/maria/maria_chk.c
new file mode 100644
index 00000000000..372cfc55672
--- /dev/null
+++ b/storage/maria/maria_chk.c
@@ -0,0 +1,1964 @@
+/* Copyright (C) 2006-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Describe, check and repair of MARIA tables */
+
+#include "ma_fulltext.h"
+#include <myisamchk.h>
+#include <my_bit.h>
+#include <m_ctype.h>
+#include <stdarg.h>
+#include <my_getopt.h>
+#ifdef HAVE_SYS_VADVICE_H
+#include <sys/vadvise.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+SET_STACK_SIZE(9000) /* Minimum stack size for program */
+
+#ifndef USE_RAID
+#define my_raid_create(A,B,C,D,E,F,G) my_create(A,B,C,G)
+#define my_raid_delete(A,B,C) my_delete(A,B)
+#endif
+
+static uint decode_bits;
+static char **default_argv;
+static const char *load_default_groups[]= { "maria_chk", 0 };
+static const char *set_collation_name, *opt_tmpdir, *opt_log_dir;
+static CHARSET_INFO *set_collation;
+static int stopwords_inited= 0;
+static MY_TMPDIR maria_chk_tmpdir;
+static my_bool opt_transaction_logging, opt_debug, opt_require_control_file;
+
+static const char *type_names[]=
+{
+ "impossible","char","binary", "short", "long", "float",
+ "double","number","unsigned short",
+ "unsigned long","longlong","ulonglong","int24",
+ "uint24","int8","varchar", "varbin", "varchar2", "varbin2", "bit",
+ "?","?"
+};
+
+static const char *prefix_packed_txt="packed ",
+ *bin_packed_txt="prefix ",
+ *diff_txt="stripped ",
+ *null_txt="NULL",
+ *blob_txt="BLOB ";
+
+static const char *field_pack[]=
+{
+ "","no endspace", "no prespace",
+ "no zeros", "blob", "constant", "table-lockup",
+ "always zero","varchar","unique-hash","?","?"
+};
+
+static const char *record_formats[]=
+{
+ "Fixed length", "Packed", "Compressed", "Block", "?"
+};
+
+static const char *maria_stats_method_str="nulls_unequal";
+static char default_open_errmsg[]= "%d when opening MARIA-table '%s'";
+static char default_close_errmsg[]= "%d when closing MARIA-table '%s'";
+
+static void get_options(int *argc,char * * *argv);
+static void print_version(void);
+static void usage(void);
+static int maria_chk(HA_CHECK *param, char *filename);
+static void descript(HA_CHECK *param, register MARIA_HA *info, char *name);
+static int maria_sort_records(HA_CHECK *param, register MARIA_HA *info,
+ char *name, uint sort_key,
+ my_bool write_info, my_bool update_index);
+static int sort_record_index(MARIA_SORT_PARAM *sort_param, MARIA_HA *info,
+ MARIA_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff,uint sortkey,
+ File new_file, my_bool update_index);
+static my_bool write_log_record(HA_CHECK *param);
+
+HA_CHECK check_param;
+
+ /* Main program */
+
+int main(int argc, char **argv)
+{
+ int error;
+ MY_INIT(argv[0]);
+
+ opt_log_dir= maria_data_root= (char *)".";
+ maria_chk_init(&check_param);
+ check_param.opt_lock_memory= 1; /* Lock memory if possible */
+ check_param.using_global_keycache = 0;
+ get_options(&argc,(char***) &argv);
+ maria_quick_table_bits=decode_bits;
+ error=0;
+ maria_init();
+
+ if (ma_control_file_open(FALSE, opt_require_control_file) &&
+ (opt_require_control_file ||
+ (opt_transaction_logging && (check_param.testflag & T_REP_ANY))))
+ {
+ error= 1;
+ goto end;
+ }
+
+ /*
+ If we are doing a repair, user may want to store this repair into the log
+ so that the log has a complete history and can be used to replay.
+ */
+ if (opt_transaction_logging && (check_param.testflag & T_REP_ANY))
+ {
+ if (init_pagecache(maria_log_pagecache,
+ TRANSLOG_PAGECACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, MY_WME) == 0 ||
+ translog_init(opt_log_dir, TRANSLOG_FILE_SIZE,
+ 0, 0, maria_log_pagecache,
+ TRANSLOG_DEFAULT_FLAGS, 0))
+ {
+ _ma_check_print_error(&check_param,
+ "Can't initialize transaction logging. Run "
+ "recovery with switch --skip-transaction-log");
+ error= 1;
+ goto end;
+ }
+ }
+
+ while (--argc >= 0)
+ {
+ int new_error=maria_chk(&check_param, *(argv++));
+ if ((check_param.testflag & T_REP_ANY) != T_REP)
+ check_param.testflag&= ~T_REP;
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
+ if ((check_param.error_printed | check_param.warning_printed) &&
+ (check_param.testflag & T_FORCE_CREATE) &&
+ (!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
+ T_SORT_INDEX))))
+ {
+ ulonglong old_testflag=check_param.testflag;
+ if (!(check_param.testflag & T_REP))
+ check_param.testflag|= T_REP_BY_SORT;
+ check_param.testflag&= ~T_EXTEND; /* Not needed */
+ error|=maria_chk(&check_param, argv[-1]);
+ check_param.testflag= old_testflag;
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
+ }
+ else
+ error|=new_error;
+ if (argc && (!(check_param.testflag & T_SILENT) ||
+ check_param.testflag & T_INFO))
+ {
+ puts("\n---------\n");
+ VOID(fflush(stdout));
+ }
+ }
+end:
+ if (check_param.total_files > 1)
+ { /* Only if descript */
+ char buff[22],buff2[22];
+ if (!(check_param.testflag & T_SILENT) || check_param.testflag & T_INFO)
+ puts("\n---------");
+ printf("\nTotal of all %d MARIA-files:\nData records: %9s Deleted blocks: %9s\n",check_param.total_files,llstr(check_param.total_records,buff),
+ llstr(check_param.total_deleted,buff2));
+ }
+ free_defaults(default_argv);
+ free_tmpdir(&maria_chk_tmpdir);
+ maria_end();
+ my_end(check_param.testflag & T_INFO ?
+ MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error);
+#ifndef _lint
+ return 0; /* No compiler warning */
+#endif
+} /* main */
+
+enum options_mc {
+ OPT_CHARSETS_DIR=256, OPT_SET_COLLATION,OPT_START_CHECK_POS,
+ OPT_CORRECT_CHECKSUM, OPT_PAGE_BUFFER_SIZE,
+ OPT_KEY_CACHE_BLOCK_SIZE, OPT_MARIA_BLOCK_SIZE,
+ OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
+ OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
+ OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
+ OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD, OPT_TRANSACTION_LOG,
+ OPT_SKIP_SAFEMALLOC, OPT_ZEROFILL_KEEP_LSN, OPT_REQUIRE_CONTROL_FILE,
+ OPT_LOG_DIR, OPT_DATADIR
+};
+
+static struct my_option my_long_options[] =
+{
+ {"analyze", 'a',
+ "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef __NETWARE__
+ {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"block-search", 'b',
+ "No help available.",
+ 0, 0, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"backup", 'B',
+ "Make a backup of the .MAD file as 'filename-time.BAK'.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"character-sets-dir", OPT_CHARSETS_DIR,
+ "Directory where character sets are.",
+ (uchar**) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"check", 'c',
+ "Check table for errors.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"check-only-changed", 'C',
+ "Check only tables that have changed since last check. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"correct-checksum", OPT_CORRECT_CHECKSUM,
+ "Correct checksum information for table.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+ {"debug", '#',
+ "Output debug log. Often this is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"description", 'd',
+ "Prints some information about table.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"data-file-length", 'D',
+ "Max length of data file (when recreating data-file when it's full).",
+ (uchar**) &check_param.max_data_file_length,
+ (uchar**) &check_param.max_data_file_length,
+ 0, GET_LL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"extend-check", 'e',
+ "If used when checking a table, ensure that the table is 100 percent consistent, which will take a long time. If used when repairing a table, try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option with repair if you are not totally desperate.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"fast", 'F',
+ "Check only tables that haven't been closed properly. It also applies to other requested actions (e.g. --analyze will be ignored if the table is already analyzed).",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"force", 'f',
+ "Restart with -r if there are any errors in the table. States will be updated as with --update-state.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"HELP", 'H',
+ "Display this help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"help", '?',
+ "Display this help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"information", 'i',
+ "Print statistics information about table that is checked.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"keys-used", 'k',
+ "Tell MARIA to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts.",
+ (uchar**) &check_param.keys_in_use,
+ (uchar**) &check_param.keys_in_use,
+ 0, GET_ULL, REQUIRED_ARG, -1, 0, 0, 0, 0, 0},
+ {"datadir", OPT_DATADIR,
+ "Path for control file (and logs if --log-dir not used).",
+ (uchar**) &maria_data_root, 0, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0},
+ {"log-dir", OPT_LOG_DIR,
+ "Path for log files.",
+ (uchar**) &opt_log_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"max-record-length", OPT_MAX_RECORD_LENGTH,
+ "Skip rows bigger than this if maria_chk can't allocate memory to hold it",
+ (uchar**) &check_param.max_record_length,
+ (uchar**) &check_param.max_record_length,
+ 0, GET_ULL, REQUIRED_ARG, LONGLONG_MAX, 0, LONGLONG_MAX, 0, 0, 0},
+ {"medium-check", 'm',
+ "Faster than extend-check, but only finds 99.99% of all errors. Should be good enough for most cases.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"quick", 'q', "Faster repair by not modifying the data file.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"read-only", 'T',
+ "Don't mark table as checked.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"recover", 'r',
+ "Can fix almost anything except unique keys that aren't unique.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"parallel-recover", 'p',
+ "Same as '-r' but creates all the keys in parallel.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"safe-recover", 'o',
+ "Uses old recovery method; Slower than '-r' but can handle a couple of cases where '-r' reports that it can't fix the data file.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"sort-recover", 'n',
+ "Force recovering with sorting even if the temporary file was very big.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { "require-control-file", OPT_REQUIRE_CONTROL_FILE,
+ "Abort if cannot find control file",
+ (uchar**)&opt_require_control_file, 0, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+#ifdef DEBUG
+ {"start-check-pos", OPT_START_CHECK_POS,
+ "No help available.",
+ 0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"set-auto-increment", 'A',
+ "Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.",
+ (uchar**) &check_param.auto_increment_value,
+ (uchar**) &check_param.auto_increment_value,
+ 0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"set-collation", OPT_SET_COLLATION,
+ "Change the collation used by the index",
+ (uchar**) &set_collation_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"set-variable", 'O',
+ "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"silent", 's',
+ "Only print errors. One can use two -s to make maria_chk very silent.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+#ifdef SAFEMALLOC
+ {"skip-safemalloc", OPT_SKIP_SAFEMALLOC,
+ "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
+#endif
+#endif
+ {"sort-index", 'S',
+ "Sort index blocks. This speeds up 'read-next' in applications.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"sort-records", 'R',
+ "Sort records according to an index. This makes your data much more localized and may speed up things. (It may be VERY slow to do a sort the first time!)",
+ (uchar**) &check_param.opt_sort_key,
+ (uchar**) &check_param.opt_sort_key,
+ 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"tmpdir", 't',
+ "Path for temporary files.",
+ (uchar**) &opt_tmpdir,
+ 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"transaction-log", OPT_TRANSACTION_LOG,
+ "Log repair command to transaction log",
+ (uchar**) &opt_transaction_logging, (uchar**) &opt_transaction_logging,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"update-state", 'U',
+ "Mark tables as crashed if any errors were found.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"unpack", 'u',
+ "Unpack file packed with mariapack.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"verbose", 'v',
+ "Print more information. This can be used with --description and --check. Use many -v for more verbosity!",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"wait", 'w', "Wait if table is locked.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { "page_buffer_size", OPT_PAGE_BUFFER_SIZE,
+ "Size of page buffer. Used by --safe-repair",
+ (uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0,
+ GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, 1024L*1024L,
+ (long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
+ { "read_buffer_size", OPT_READ_BUFFER_SIZE, "",
+ (uchar**) &check_param.read_buffer_length,
+ (uchar**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
+ (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
+ (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
+ { "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "",
+ (uchar**) &check_param.write_buffer_length,
+ (uchar**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
+ (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
+ (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
+ { "sort_buffer_size", OPT_SORT_BUFFER_SIZE,
+ "Size of sort buffer. Used by --recover",
+ (uchar**) &check_param.sort_buffer_length,
+ (uchar**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG,
+ (long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD),
+ (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
+ { "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "",
+ (uchar**) &check_param.sort_key_blocks,
+ (uchar**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG,
+ BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
+ { "decode_bits", OPT_DECODE_BITS, "", (uchar**) &decode_bits,
+ (uchar**) &decode_bits, 0, GET_UINT, REQUIRED_ARG, 9L, 4L, 17L, 0L, 1L, 0},
+ { "ft_min_word_len", OPT_FT_MIN_WORD_LEN, "", (uchar**) &ft_min_word_len,
+ (uchar**) &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN,
+ 0, 1, 0},
+ { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "", (uchar**) &ft_max_word_len,
+ (uchar**) &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXCHARLEN, 10,
+ HA_FT_MAXCHARLEN, 0, 1, 0},
+ { "maria_ft_stopword_file", OPT_FT_STOPWORD_FILE,
+ "Use stopwords from this file instead of built-in list.",
+ (uchar**) &ft_stopword_file, (uchar**) &ft_stopword_file, 0, GET_STR,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ { "stats_method", OPT_STATS_METHOD,
+ "Specifies how index statistics collection code should treat NULLs. "
+ "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), "
+ "\"nulls_equal\" (emulate 4.0 behavior), and \"nulls_ignored\".",
+ (uchar**) &maria_stats_method_str, (uchar**) &maria_stats_method_str, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ { "zerofill", 'z',
+ "Fill empty space in data and index files with zeroes",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { "zerofill-keep-lsn", OPT_ZEROFILL_KEEP_LSN,
+ "Like --zerofill but does not zero out LSN of data/index pages;"
+ " used only for testing and debugging",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+#include <help_start.h>
+
+static void print_version(void)
+{
+ printf("%s Ver 1.0 for %s at %s\n", my_progname, SYSTEM_TYPE,
+ MACHINE_TYPE);
+ NETWARE_SET_SCREEN_MODE(1);
+}
+
+
+static void usage(void)
+{
+ print_version();
+ puts("By Monty, for your professional use");
+ puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
+ puts("Description, check and repair of MARIA tables.");
+ puts("Used without options all tables on the command will be checked for errors");
+ printf("Usage: %s [OPTIONS] tables[.MAI]\n", my_progname_short);
+ printf("\nGlobal options:\n");
+#ifndef DBUG_OFF
+ printf("\
+ -#, --debug=... Output debug log. Often this is 'd:t:o,filename'.\n");
+#endif
+ printf("\
+ -?, --help Display this help and exit.\n\
+ -O, --set-variable var=option.\n\
+ Change the value of a variable. Please note that\n\
+ this option is deprecated; you can set variables\n\
+ directly with '--variable-name=value'.\n\
+ -t, --tmpdir=path Path for temporary files. Multiple paths can be\n\
+ specified, separated by ");
+#if defined( __WIN__) || defined(__NETWARE__)
+ printf("semicolon (;)");
+#else
+ printf("colon (:)");
+#endif
+ printf(", they will be used\n\
+ in a round-robin fashion.\n\
+ --require-control-file Abort if we can't find/read the maria_log_control\n\
+ file\n\
+ -s, --silent Only print errors. One can use two -s to make\n\
+ maria_chk very silent.\n\
+ -v, --verbose Print more information. This can be used with\n\
+ --description and --check. Use many -v for more verbosity.\n\
+ -V, --version Print version and exit.\n\
+ -w, --wait Wait if table is locked.\n\n");
+#ifdef DEBUG
+ puts(" --start-check-pos=# Start reading file at given offset.\n");
+#endif
+
+ puts("Check options (check is the default action for maria_chk):\n\
+ -c, --check Check table for errors.\n\
+ -e, --extend-check Check the table VERY throughly. Only use this in\n\
+ extreme cases as maria_chk should normally be able to\n\
+ find out if the table is ok even without this switch.\n\
+ -F, --fast Check only tables that haven't been closed properly.\n\
+ -C, --check-only-changed\n\
+ Check only tables that have changed since last check.\n\
+ -f, --force Restart with '-r' if there are any errors in the table.\n\
+ States will be updated as with '--update-state'.\n\
+ -i, --information Print statistics information about table that is checked.\n\
+ -m, --medium-check Faster than extend-check, but only finds 99.99% of\n\
+ all errors. Should be good enough for most cases.\n\
+ -U --update-state Mark tables as crashed if you find any errors.\n\
+ -T, --read-only Don't mark table as checked.\n");
+
+ puts("Recover (repair)/ options (When using '-r' or '-o'):\n\
+ -B, --backup Make a backup of the .MAD file as 'filename-time.BAK'.\n\
+ --correct-checksum Correct checksum information for table.\n\
+ -D, --data-file-length=# Max length of data file (when recreating data\n\
+ file when it's full).\n\
+ -e, --extend-check Try to recover every possible row from the data file\n\
+ Normally this will also find a lot of garbage rows;\n\
+ Don't use this option if you are not totally desperate.\n\
+ -f, --force Overwrite old temporary files.\n\
+ -k, --keys-used=# Tell MARIA to update only some specific keys. # is a\n\
+ bit mask of which keys to use. This can be used to\n\
+ get faster inserts.\n\
+ --max-record-length=#\n\
+ Skip rows bigger than this if maria_chk can't allocate\n\
+ memory to hold it.\n\
+ -r, --recover Can fix almost anything except unique keys that aren't\n\
+ unique.\n\
+ -n, --sort-recover Forces recovering with sorting even if the temporary\n\
+ file would be very big.\n\
+ -p, --parallel-recover\n\
+ Uses the same technique as '-r' and '-n', but creates\n\
+ all the keys in parallel, in different threads.");
+ puts("\
+ -o, --safe-recover Uses old recovery method; Slower than '-r' but can\n \
+ handle a couple of cases where '-r' reports that it\n\
+ can't fix the data file.\n\
+ --transaction-log Log repair command to transaction log. This is needed\n\
+ if one wants to use the maria_read_log to repeat the \n\
+ repair\n\
+ --character-sets-dir=...\n\
+ Directory where character sets are.\n\
+ --set-collation=name\n\
+ Change the collation used by the index.\n\
+ -q, --quick Faster repair by not modifying the data file.\n\
+ One can give a second '-q' to force maria_chk to\n\
+ modify the original datafile in case of duplicate keys.\n\
+ NOTE: Tables where the data file is currupted can't be\n\
+ fixed with this option.\n\
+ -u, --unpack Unpack file packed with mariapack.\n\
+");
+
+ puts("Other actions:\n\
+ -a, --analyze Analyze distribution of keys. Will make some joins in\n\
+ MySQL faster. You can check the calculated distribution\n\
+ by using '--description --verbose table_name'.\n\
+ --stats_method=name Specifies how index statistics collection code should\n\
+ treat NULLs. Possible values of name are \"nulls_unequal\"\n\
+ (default for 4.1/5.0), \"nulls_equal\" (emulate 4.0), and \n\
+ \"nulls_ignored\".\n\
+ -d, --description Prints some information about table.\n\
+ -A, --set-auto-increment[=value]\n\
+ Force auto_increment to start at this or higher value\n\
+ If no value is given, then sets the next auto_increment\n\
+ value to the highest used value for the auto key + 1.\n\
+ -S, --sort-index Sort index blocks. This speeds up 'read-next' in\n\
+ applications.\n\
+ -R, --sort-records=#\n\
+ Sort records according to an index. This makes your\n\
+ data much more localized and may speed up things\n\
+ (It may be VERY slow to do a sort the first time!).\n\
+ -b, --block-search=#\n\
+ Find a record, a block at given offset belongs to.\n\
+ -z, --zerofill Fill empty space in data and index files with zeroes\n\
+ --zerofill-keep-lsn Like --zerofill but does not zero out LSN of\n\
+ data/index pages.");
+
+ print_defaults("my", load_default_groups);
+ my_print_variables(my_long_options);
+}
+
+#include <help_end.h>
+
+const char *maria_stats_method_names[] = {"nulls_unequal", "nulls_equal",
+ "nulls_ignored", NullS};
+TYPELIB maria_stats_method_typelib= {
+ array_elements(maria_stats_method_names) - 1, "",
+ maria_stats_method_names, NULL};
+
+ /* Read options */
+
+static my_bool
+get_one_option(int optid,
+ const struct my_option *opt __attribute__((unused)),
+ char *argument)
+{
+ switch (optid) {
+#ifdef __NETWARE__
+ case OPT_AUTO_CLOSE:
+ setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
+ break;
+#endif
+ case 'a':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_STATISTICS;
+ else
+ check_param.testflag|= T_STATISTICS;
+ break;
+ case 'A':
+ if (argument)
+ check_param.auto_increment_value= strtoull(argument, NULL, 0);
+ else
+ check_param.auto_increment_value= 0; /* Set to max used value */
+ check_param.testflag|= T_AUTO_INC;
+ break;
+ case 'b':
+ check_param.search_after_block= strtoul(argument, NULL, 10);
+ break;
+ case 'B':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_BACKUP_DATA;
+ else
+ check_param.testflag|= T_BACKUP_DATA;
+ break;
+ case 'c':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_CHECK;
+ else
+ check_param.testflag|= T_CHECK;
+ break;
+ case 'C':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~(T_CHECK | T_CHECK_ONLY_CHANGED);
+ else
+ check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
+ break;
+ case 'D':
+ check_param.max_data_file_length=strtoll(argument, NULL, 10);
+ break;
+ case 's': /* silent */
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~(T_SILENT | T_VERY_SILENT);
+ else
+ {
+ if (check_param.testflag & T_SILENT)
+ check_param.testflag|= T_VERY_SILENT;
+ check_param.testflag|= T_SILENT;
+ check_param.testflag&= ~T_WRITE_LOOP;
+ }
+ break;
+ case 'w':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_WAIT_FOREVER;
+ else
+ check_param.testflag|= T_WAIT_FOREVER;
+ break;
+ case 'd': /* description if isam-file */
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_DESCRIPT;
+ else
+ check_param.testflag|= T_DESCRIPT;
+ break;
+ case 'e': /* extend check */
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_EXTEND;
+ else
+ check_param.testflag|= T_EXTEND;
+ break;
+ case 'i':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_INFO;
+ else
+ check_param.testflag|= T_INFO;
+ break;
+ case 'f':
+ if (argument == disabled_my_option)
+ {
+ check_param.tmpfile_createflag= O_RDWR | O_TRUNC | O_EXCL;
+ check_param.testflag&= ~(T_FORCE_CREATE | T_UPDATE_STATE);
+ }
+ else
+ {
+ check_param.tmpfile_createflag= O_RDWR | O_TRUNC;
+ check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
+ }
+ break;
+ case 'F':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_FAST;
+ else
+ check_param.testflag|= T_FAST;
+ break;
+ case 'k':
+ check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
+ break;
+ case 'm':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_MEDIUM;
+ else
+ check_param.testflag|= T_MEDIUM; /* Medium check */
+ break;
+ case 'r': /* Repair table */
+ check_param.testflag&= ~T_REP_ANY;
+ if (argument != disabled_my_option)
+ check_param.testflag|= T_REP_BY_SORT;
+ break;
+ case 'p':
+ check_param.testflag&= ~T_REP_ANY;
+ if (argument != disabled_my_option)
+ check_param.testflag|= T_REP_PARALLEL;
+ break;
+ case 'o':
+ check_param.testflag&= ~T_REP_ANY;
+ check_param.force_sort= 0;
+ if (argument != disabled_my_option)
+ {
+ check_param.testflag|= T_REP;
+ my_disable_async_io= 1; /* More safety */
+ }
+ break;
+ case 'n':
+ check_param.testflag&= ~T_REP_ANY;
+ if (argument == disabled_my_option)
+ check_param.force_sort= 0;
+ else
+ {
+ check_param.testflag|= T_REP_BY_SORT;
+ check_param.force_sort= 1;
+ }
+ break;
+ case 'q':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~(T_QUICK | T_FORCE_UNIQUENESS);
+ else
+ check_param.testflag|=
+ (check_param.testflag & T_QUICK) ? T_FORCE_UNIQUENESS : T_QUICK;
+ break;
+ case 'u':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_UNPACK;
+ else
+ {
+ check_param.testflag|= T_UNPACK;
+ if (!(check_param.testflag & T_REP_ANY))
+ check_param.testflag|= T_REP_BY_SORT;
+ }
+ break;
+ case 'v': /* Verbose */
+ if (argument == disabled_my_option)
+ {
+ check_param.testflag&= ~T_VERBOSE;
+ check_param.verbose=0;
+ }
+ else
+ {
+ check_param.testflag|= T_VERBOSE;
+ check_param.verbose++;
+ }
+ break;
+ case 'R': /* Sort records */
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_SORT_RECORDS;
+ else
+ {
+ check_param.testflag|= T_SORT_RECORDS;
+ check_param.opt_sort_key= (uint) atoi(argument) - 1;
+ if (check_param.opt_sort_key >= MARIA_MAX_KEY)
+ {
+ fprintf(stderr,
+ "The value of the sort key is bigger than max key: %d.\n",
+ MARIA_MAX_KEY);
+ exit(1);
+ }
+ }
+ break;
+ case 'S': /* Sort index */
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_SORT_INDEX;
+ else
+ check_param.testflag|= T_SORT_INDEX;
+ break;
+ case 'T':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_READONLY;
+ else
+ check_param.testflag|= T_READONLY;
+ break;
+ case 'U':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_UPDATE_STATE;
+ else
+ check_param.testflag|= T_UPDATE_STATE;
+ break;
+ case '#':
+ DBUG_SET_INITIAL(argument ? argument : "d:t:o,/tmp/maria_chk.trace");
+ opt_debug= 1;
+ break;
+ case OPT_SKIP_SAFEMALLOC:
+#ifdef SAFEMALLOC
+ sf_malloc_quick=1;
+#endif
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ case OPT_CORRECT_CHECKSUM:
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_CALC_CHECKSUM;
+ else
+ check_param.testflag|= T_CALC_CHECKSUM;
+ break;
+ case OPT_STATS_METHOD:
+ {
+ int method;
+ enum_handler_stats_method method_conv;
+ LINT_INIT(method_conv);
+ maria_stats_method_str= argument;
+ if ((method=find_type(argument, &maria_stats_method_typelib, 2)) <= 0)
+ {
+ fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
+ exit(1);
+ }
+ switch (method-1) {
+ case 0:
+ method_conv= MI_STATS_METHOD_NULLS_EQUAL;
+ break;
+ case 1:
+ method_conv= MI_STATS_METHOD_NULLS_NOT_EQUAL;
+ break;
+ case 2:
+ method_conv= MI_STATS_METHOD_IGNORE_NULLS;
+ break;
+ default: assert(0); /* Impossible */
+ }
+ check_param.stats_method= method_conv;
+ break;
+ }
+#ifdef DEBUG /* Only useful if debugging */
+ case OPT_START_CHECK_POS:
+ check_param.start_check_pos= strtoull(argument, NULL, 0);
+ break;
+#endif
+ case 'z':
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~T_ZEROFILL;
+ else
+ check_param.testflag|= T_ZEROFILL;
+ break;
+ case OPT_ZEROFILL_KEEP_LSN:
+ if (argument == disabled_my_option)
+ check_param.testflag&= ~(T_ZEROFILL_KEEP_LSN | T_ZEROFILL);
+ else
+ check_param.testflag|= (T_ZEROFILL_KEEP_LSN | T_ZEROFILL);
+ break;
+ case 'H':
+ my_print_help(my_long_options);
+ exit(0);
+ case '?':
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+
+static void get_options(register int *argc,register char ***argv)
+{
+ int ho_error;
+
+ load_defaults("my", load_default_groups, argc, argv);
+ default_argv= *argv;
+ if (isatty(fileno(stdout)))
+ check_param.testflag|=T_WRITE_LOOP;
+
+ if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ /* If using repair, then update checksum if one uses --update-state */
+ if ((check_param.testflag & T_UPDATE_STATE) &&
+ (check_param.testflag & T_REP_ANY))
+ check_param.testflag|= T_CALC_CHECKSUM;
+
+ if (*argc == 0)
+ {
+ usage();
+ exit(-1);
+ }
+
+ if ((check_param.testflag & T_UNPACK) &&
+ (check_param.testflag & (T_QUICK | T_SORT_RECORDS)))
+ {
+ VOID(fprintf(stderr,
+ "%s: --unpack can't be used with --quick or --sort-records\n",
+ my_progname_short));
+ exit(1);
+ }
+ if ((check_param.testflag & T_READONLY) &&
+ (check_param.testflag &
+ (T_REP_ANY | T_STATISTICS | T_AUTO_INC |
+ T_SORT_RECORDS | T_SORT_INDEX | T_FORCE_CREATE)))
+ {
+ VOID(fprintf(stderr,
+ "%s: Can't use --readonly when repairing or sorting\n",
+ my_progname_short));
+ exit(1);
+ }
+
+ if (!opt_debug)
+ {
+ DEBUGGER_OFF; /* Speed up things a bit */
+ }
+ if (init_tmpdir(&maria_chk_tmpdir, opt_tmpdir))
+ exit(1);
+
+ check_param.tmpdir=&maria_chk_tmpdir;
+
+ if (set_collation_name)
+ if (!(set_collation= get_charset_by_name(set_collation_name,
+ MYF(MY_WME))))
+ exit(1);
+
+ return;
+} /* get options */
+
+
+ /* Check table */
+
+static int maria_chk(HA_CHECK *param, char *filename)
+{
+ int error,lock_type,recreate;
+ my_bool rep_quick= test(param->testflag & (T_QUICK | T_FORCE_UNIQUENESS));
+ MARIA_HA *info;
+ File datafile;
+ char llbuff[22],llbuff2[22];
+ my_bool state_updated=0;
+ MARIA_SHARE *share;
+ DBUG_ENTER("maria_chk");
+
+ param->out_flag=error=param->warning_printed=param->error_printed=
+ recreate=0;
+ datafile=0;
+ param->isam_file_name=filename; /* For error messages */
+ if (!(info=maria_open(filename,
+ (param->testflag & (T_DESCRIPT | T_READONLY)) ?
+ O_RDONLY : O_RDWR,
+ HA_OPEN_FOR_REPAIR |
+ ((param->testflag & T_WAIT_FOREVER) ?
+ HA_OPEN_WAIT_IF_LOCKED :
+ (param->testflag & T_DESCRIPT) ?
+ HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED))))
+ {
+ /* Avoid twice printing of isam file name */
+ param->error_printed=1;
+ switch (my_errno) {
+ case HA_ERR_CRASHED:
+ _ma_check_print_error(param,"'%s' doesn't have a correct index definition. You need to recreate it before you can do a repair",filename);
+ break;
+ case HA_ERR_NOT_A_TABLE:
+ _ma_check_print_error(param,"'%s' is not a MARIA-table",filename);
+ break;
+ case HA_ERR_CRASHED_ON_USAGE:
+ _ma_check_print_error(param,"'%s' is marked as crashed",filename);
+ break;
+ case HA_ERR_CRASHED_ON_REPAIR:
+ _ma_check_print_error(param,"'%s' is marked as crashed after last repair",filename);
+ break;
+ case HA_ERR_OLD_FILE:
+ _ma_check_print_error(param,"'%s' is a old type of MARIA-table", filename);
+ break;
+ case HA_ERR_NEW_FILE:
+ _ma_check_print_error(param,"'%s' uses new features not supported by this version of the MARIA library", filename);
+ break;
+ case HA_ERR_END_OF_FILE:
+ _ma_check_print_error(param,"Couldn't read complete header from '%s'", filename);
+ break;
+ case EAGAIN:
+ _ma_check_print_error(param,"'%s' is locked. Use -w to wait until unlocked",filename);
+ break;
+ case ENOENT:
+ _ma_check_print_error(param,"File '%s' doesn't exist",filename);
+ break;
+ case EACCES:
+ _ma_check_print_error(param,"You don't have permission to use '%s'",
+ filename);
+ break;
+ default:
+ _ma_check_print_error(param,"%d when opening MARIA-table '%s'",
+ my_errno,filename);
+ break;
+ }
+ DBUG_RETURN(1);
+ }
+ share= info->s;
+ share->tot_locks-= share->r_locks;
+ share->r_locks=0;
+ maria_block_size= share->base.block_size;
+
+ if (share->data_file_type == BLOCK_RECORD ||
+ ((param->testflag & T_UNPACK) &&
+ share->state.header.org_data_file_type == BLOCK_RECORD))
+ {
+ if (param->testflag & T_SORT_RECORDS)
+ {
+ _ma_check_print_error(param,
+ "Record format used by '%s' is is not yet supported with sort-records",
+ filename);
+ param->error_printed= 0;
+ error= 1;
+ goto end2;
+ }
+ /* We can't do parallell repair with BLOCK_RECORD yet */
+ if (param->testflag & T_REP_PARALLEL)
+ {
+ param->testflag&= ~T_REP_PARALLEL;
+ param->testflag|= T_REP_BY_SORT;
+ }
+ }
+
+ /*
+ Skip the checking of the file if:
+ We are using --fast and the table is closed properly
+ We are using --check-only-changed-tables and the table hasn't changed
+ */
+ if (param->testflag & (T_FAST | T_CHECK_ONLY_CHANGED))
+ {
+ my_bool need_to_check= (maria_is_crashed(info) ||
+ share->state.open_count != 0);
+
+ if ((param->testflag & (T_REP_ANY | T_SORT_RECORDS)) &&
+ ((share->state.changed & (STATE_CHANGED | STATE_CRASHED |
+ STATE_CRASHED_ON_REPAIR) ||
+ !(param->testflag & T_CHECK_ONLY_CHANGED))))
+ need_to_check=1;
+
+ if (info->s->base.keys && info->state->records)
+ {
+ if ((param->testflag & T_STATISTICS) &&
+ (share->state.changed & STATE_NOT_ANALYZED))
+ need_to_check=1;
+ if ((param->testflag & T_SORT_INDEX) &&
+ (share->state.changed & STATE_NOT_SORTED_PAGES))
+ need_to_check=1;
+ if ((param->testflag & T_REP_BY_SORT) &&
+ (share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
+ need_to_check=1;
+ }
+ if ((param->testflag & T_CHECK_ONLY_CHANGED) &&
+ (share->state.changed & (STATE_CHANGED | STATE_CRASHED |
+ STATE_CRASHED_ON_REPAIR)))
+ need_to_check=1;
+ if (!need_to_check)
+ {
+ if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
+ printf("MARIA file: %s is already checked\n",filename);
+ if (maria_close(info))
+ {
+ _ma_check_print_error(param,"%d when closing MARIA-table '%s'",
+ my_errno,filename);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+ }
+ if ((param->testflag & (T_REP_ANY | T_STATISTICS |
+ T_SORT_RECORDS | T_SORT_INDEX)) &&
+ (((param->testflag & T_UNPACK) &&
+ share->data_file_type == COMPRESSED_RECORD) ||
+ mi_uint2korr(share->state.header.state_info_length) !=
+ MARIA_STATE_INFO_SIZE ||
+ mi_uint2korr(share->state.header.base_info_length) !=
+ MARIA_BASE_INFO_SIZE ||
+ maria_is_any_intersect_keys_active(param->keys_in_use, share->base.keys,
+ ~share->state.key_map) ||
+ maria_test_if_almost_full(info) ||
+ info->s->state.header.file_version[3] != maria_file_magic[3] ||
+ (set_collation &&
+ set_collation->number != share->state.header.language)))
+ {
+ if (set_collation)
+ param->language= set_collation->number;
+ if (maria_recreate_table(param, &info,filename))
+ {
+ VOID(fprintf(stderr,
+ "MARIA-table '%s' is not fixed because of errors\n",
+ filename));
+ return(-1);
+ }
+ recreate=1;
+ if (!(param->testflag & T_REP_ANY))
+ {
+ param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
+ if (!(param->testflag & T_SILENT))
+ printf("- '%s' has old table-format. Recreating index\n",filename);
+ rep_quick= 1;
+ }
+ share= info->s;
+ share->tot_locks-= share->r_locks;
+ share->r_locks=0;
+ }
+
+ if (param->testflag & T_DESCRIPT)
+ {
+ param->total_files++;
+ param->total_records+=info->state->records;
+ param->total_deleted+=info->state->del;
+ descript(param, info, filename);
+ maria_close(info); /* Should always succeed */
+ return(0);
+ }
+
+ if (!stopwords_inited++)
+ ft_init_stopwords();
+
+ if (!(param->testflag & T_READONLY))
+ lock_type = F_WRLCK; /* table is changed */
+ else
+ lock_type= F_RDLCK;
+ if (info->lock_type == F_RDLCK)
+ info->lock_type=F_UNLCK; /* Read only table */
+ if (_ma_readinfo(info,lock_type,0))
+ {
+ _ma_check_print_error(param,"Can't lock indexfile of '%s', error: %d",
+ filename,my_errno);
+ param->error_printed=0;
+ error= 1;
+ goto end2;
+ }
+ /*
+ _ma_readinfo() has locked the table.
+ We mark the table as locked (without doing file locks) to be able to
+ use functions that only works on locked tables (like row caching).
+ */
+ maria_lock_database(info, F_EXTRA_LCK);
+ datafile= info->dfile.file;
+ if (init_pagecache(maria_pagecache, param->use_buffers, 0, 0,
+ maria_block_size, MY_WME) == 0)
+ {
+ _ma_check_print_error(param, "Can't initialize page cache with %lu memory",
+ (ulong) param->use_buffers);
+ error= 1;
+ goto end2;
+ }
+
+ if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
+ T_ZEROFILL))
+ {
+ /*
+ Mark table as not transactional to avoid logging. Should not be needed,
+ maria_repair and maria_zerofill do it already.
+ */
+ _ma_tmp_disable_logging_for_table(info, FALSE);
+
+ if (param->testflag & T_REP_ANY)
+ {
+ ulonglong tmp=share->state.key_map;
+ maria_copy_keys_active(share->state.key_map, share->base.keys,
+ param->keys_in_use);
+ if (tmp != share->state.key_map)
+ info->update|=HA_STATE_CHANGED;
+
+ if (rep_quick &&
+ maria_chk_del(param, info, param->testflag & ~T_VERBOSE))
+ {
+ if (param->testflag & T_FORCE_CREATE)
+ {
+ rep_quick=0;
+ _ma_check_print_info(param,"Creating new data file\n");
+ }
+ else
+ {
+ error=1;
+ _ma_check_print_error(param,
+ "Quick-recover aborted; Run recovery without switch 'q'");
+ }
+ }
+ }
+ if (!error)
+ {
+ /*
+ Unless this was only --zerofill-keep-lsn, old REDOs are not
+ applicable, tell the server's Recovery to ignore them; we don't
+ know what the log's end LSN is now, so we just let the server know
+ that it will have to find and store it.
+ This is the only case where create_rename_lsn can be a horizon and not
+ a LSN.
+ If this was only --zerofill-keep-lsn, the table can be used in
+ Recovery and especially in this scenario: do a dirty-copy-based backup
+ (snapshot-like), --zerofill-keep-lsn on the copies to achieve better
+ compression, compress the copies with an external tool, and after a
+ restore, Recovery still works (because pages and state still have
+ their correct LSNs).
+ */
+ if (share->base.born_transactional &&
+ ((param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
+ T_ZEROFILL | T_ZEROFILL_KEEP_LSN)) !=
+ (T_ZEROFILL | T_ZEROFILL_KEEP_LSN)))
+ share->state.create_rename_lsn= share->state.is_of_horizon=
+ share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS;
+ }
+ if (!error && (param->testflag & T_REP_ANY))
+ {
+ if ((param->testflag & (T_REP_BY_SORT | T_REP_PARALLEL)) &&
+ (maria_is_any_key_active(share->state.key_map) ||
+ (rep_quick && !param->keys_in_use && !recreate)) &&
+ maria_test_if_sort_rep(info, info->state->records,
+ info->s->state.key_map,
+ param->force_sort))
+ {
+ if (param->testflag & T_REP_BY_SORT)
+ error=maria_repair_by_sort(param,info,filename,rep_quick);
+ else
+ error=maria_repair_parallel(param,info,filename,rep_quick);
+ state_updated=1;
+ }
+ else
+ error=maria_repair(param, info,filename,rep_quick);
+ }
+ if (!error && (param->testflag & T_SORT_RECORDS))
+ {
+ /*
+ The data file is nowadays reopened in the repair code so we should
+ soon remove the following reopen-code
+ */
+#ifndef TO_BE_REMOVED
+ if (param->out_flag & O_NEW_DATA)
+ { /* Change temp file to org file */
+ VOID(my_close(info->dfile.file, MYF(MY_WME))); /* Close new file */
+ error|=maria_change_to_newfile(filename,MARIA_NAME_DEXT,DATA_TMP_EXT,
+ MYF(0));
+ if (_ma_open_datafile(info,info->s, NullS, -1))
+ error=1;
+ param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */
+ param->read_cache.file= info->dfile.file;
+ }
+#endif
+ if (! error)
+ {
+ uint key;
+ /*
+ We can't update the index in maria_sort_records if we have a
+ prefix compressed or fulltext index
+ */
+ my_bool update_index=1;
+ for (key=0 ; key < share->base.keys; key++)
+ if (share->keyinfo[key].flag & (HA_BINARY_PACK_KEY|HA_FULLTEXT))
+ update_index=0;
+
+ error=maria_sort_records(param,info,filename,param->opt_sort_key,
+ /* what is the following parameter for ? */
+ (my_bool) !(param->testflag & T_REP),
+ update_index);
+ datafile= info->dfile.file; /* This is now locked */
+ if (!error && !update_index)
+ {
+ if (param->verbose)
+ puts("Table had a compressed index; We must now recreate the index");
+ error=maria_repair_by_sort(param,info,filename,1);
+ }
+ }
+ }
+ if (!error && (param->testflag & T_SORT_INDEX))
+ error= maria_sort_index(param,info,filename);
+ if (!error && (param->testflag & T_ZEROFILL))
+ error= maria_zerofill(param, info, filename);
+ if (!error)
+ share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
+ STATE_CRASHED_ON_REPAIR);
+ else
+ maria_mark_crashed(info);
+ }
+ else if ((param->testflag & T_CHECK) || !(param->testflag & T_AUTO_INC))
+ {
+ if (!(param->testflag & T_SILENT) || param->testflag & T_INFO)
+ printf("Checking MARIA file: %s\n",filename);
+ if (!(param->testflag & T_SILENT))
+ printf("Data records: %7s Deleted blocks: %7s\n",
+ llstr(info->state->records,llbuff),
+ llstr(info->state->del,llbuff2));
+ maria_chk_init_for_check(param, info);
+ error= maria_chk_status(param,info);
+ maria_intersect_keys_active(share->state.key_map, param->keys_in_use);
+ error|= maria_chk_size(param,info);
+ if (!error || !(param->testflag & (T_FAST | T_FORCE_CREATE)))
+ error|=maria_chk_del(param, info,param->testflag);
+ if ((!error || (!(param->testflag & (T_FAST | T_FORCE_CREATE)) &&
+ !param->start_check_pos)))
+ {
+ error|=maria_chk_key(param, info);
+ if (!error && (param->testflag & (T_STATISTICS | T_AUTO_INC)))
+ error=maria_update_state_info(param, info,
+ ((param->testflag & T_STATISTICS) ?
+ UPDATE_STAT : 0) |
+ ((param->testflag & T_AUTO_INC) ?
+ UPDATE_AUTO_INC : 0));
+ }
+ if ((!rep_quick && !error) ||
+ !(param->testflag & (T_FAST | T_FORCE_CREATE)))
+ {
+ VOID(init_io_cache(&param->read_cache,datafile,
+ (uint) param->read_buffer_length,
+ READ_CACHE,
+ (param->start_check_pos ?
+ param->start_check_pos :
+ share->pack.header_length),
+ 1,
+ MYF(MY_WME)));
+ maria_lock_memory(param);
+ if ((info->s->data_file_type != STATIC_RECORD) ||
+ (param->testflag & (T_EXTEND | T_MEDIUM)))
+ error|=maria_chk_data_link(param, info,
+ test(param->testflag & T_EXTEND));
+ VOID(end_io_cache(&param->read_cache));
+ }
+ if (!error)
+ {
+ if ((share->state.changed & STATE_CHANGED) &&
+ (param->testflag & T_UPDATE_STATE))
+ info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
+ STATE_CRASHED_ON_REPAIR);
+ }
+ else if (!maria_is_crashed(info) &&
+ (param->testflag & T_UPDATE_STATE))
+ { /* Mark crashed */
+ maria_mark_crashed(info);
+ info->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
+ }
+ }
+
+ if ((param->testflag & T_AUTO_INC) ||
+ ((param->testflag & T_REP_ANY) && info->s->base.auto_key))
+ _ma_update_auto_increment_key(param, info,
+ (my_bool) !test(param->testflag & T_AUTO_INC));
+
+ if (info->update & HA_STATE_CHANGED && ! (param->testflag & T_READONLY))
+ error|=maria_update_state_info(param, info,
+ UPDATE_OPEN_COUNT |
+ (((param->testflag & T_REP_ANY) ?
+ UPDATE_TIME : 0) |
+ (state_updated ? UPDATE_STAT : 0) |
+ ((param->testflag & T_SORT_RECORDS) ?
+ UPDATE_SORT : 0)));
+ info->update&= ~HA_STATE_CHANGED;
+ _ma_reenable_logging_for_table(info, FALSE);
+ maria_lock_database(info, F_UNLCK);
+
+end2:
+ end_pagecache(maria_pagecache, 1);
+ if (maria_close(info))
+ {
+ _ma_check_print_error(param, default_close_errmsg, my_errno, filename);
+ DBUG_RETURN(1);
+ }
+ if (error == 0)
+ {
+ if (param->out_flag & O_NEW_DATA)
+ error|=maria_change_to_newfile(filename,MARIA_NAME_DEXT,DATA_TMP_EXT,
+ ((param->testflag & T_BACKUP_DATA) ?
+ MYF(MY_REDEL_MAKE_BACKUP) : MYF(0)));
+ if (param->out_flag & O_NEW_INDEX)
+ error|=maria_change_to_newfile(filename,MARIA_NAME_IEXT,INDEX_TMP_EXT,
+ MYF(0));
+ }
+ if (opt_transaction_logging &&
+ share->base.born_transactional && !error &&
+ (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
+ T_ZEROFILL)))
+ error= write_log_record(param);
+
+ if (param->not_visible_rows_found && (param->testflag & T_VERBOSE))
+ {
+ char buff[22];
+ printf("Max transaction id found: %s\n",
+ llstr(param->max_found_trid, buff));
+ }
+
+ VOID(fflush(stdout)); VOID(fflush(stderr));
+
+ if (param->error_printed)
+ {
+ if (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX))
+ {
+ VOID(fprintf(stderr,
+ "MARIA-table '%s' is not fixed because of errors\n",
+ filename));
+ if (param->testflag & T_REP_ANY)
+ VOID(fprintf(stderr,
+ "Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n"));
+ }
+ else if (!(param->error_printed & 2) &&
+ !(param->testflag & T_FORCE_CREATE))
+ VOID(fprintf(stderr,
+ "MARIA-table '%s' is corrupted\nFix it using switch \"-r\" or \"-o\"\n",
+ filename));
+ }
+ else if (param->warning_printed &&
+ ! (param->testflag & (T_REP_ANY | T_SORT_RECORDS | T_SORT_INDEX |
+ T_FORCE_CREATE)))
+ VOID(fprintf(stderr, "MARIA-table '%s' is usable but should be fixed\n",
+ filename));
+ VOID(fflush(stderr));
+ DBUG_RETURN(error);
+} /* maria_chk */
+
+
+/* Write info about table */
+
+static void descript(HA_CHECK *param, register MARIA_HA *info, char *name)
+{
+ uint key,keyseg_nr,field;
+ reg3 MARIA_KEYDEF *keyinfo;
+ reg2 HA_KEYSEG *keyseg;
+ reg4 const char *text;
+ char buff[200],length[10],*pos,*end;
+ enum en_fieldtype type;
+ MARIA_SHARE *share= info->s;
+ char llbuff[22],llbuff2[22];
+ DBUG_ENTER("descript");
+
+ if (param->testflag & T_VERY_SILENT)
+ {
+ longlong checksum= info->state->checksum;
+ if (!(share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)))
+ checksum= 0;
+ printf("%s %s %s\n", name, llstr(info->state->records,llbuff),
+ llstr(checksum, llbuff2));
+ DBUG_VOID_RETURN;
+ }
+
+ printf("MARIA file: %s\n",name);
+ printf("Record format: %s\n", record_formats[share->data_file_type]);
+ printf("Crashsafe: %s\n",
+ share->base.born_transactional ? "yes" : "no");
+ printf("Character set: %s (%d)\n",
+ get_charset_name(share->state.header.language),
+ share->state.header.language);
+
+ if (param->testflag & T_VERBOSE)
+ {
+ printf("File-version: %d\n",
+ (int) share->state.header.file_version[3]);
+ if (share->state.create_time)
+ {
+ get_date(buff,1,share->state.create_time);
+ printf("Creation time: %s\n",buff);
+ }
+ if (share->state.check_time)
+ {
+ get_date(buff,1,share->state.check_time);
+ printf("Recover time: %s\n",buff);
+ }
+ if (share->base.born_transactional)
+ {
+ printf("LSNs: create_rename (%lu,0x%lx),"
+ " state_horizon (%lu,0x%lx), skip_redo (%lu,0x%lx)\n",
+ LSN_IN_PARTS(share->state.create_rename_lsn),
+ LSN_IN_PARTS(share->state.is_of_horizon),
+ LSN_IN_PARTS(share->state.skip_redo_lsn));
+ }
+ compile_time_assert((MY_UUID_STRING_LENGTH + 1) <= sizeof(buff));
+ buff[MY_UUID_STRING_LENGTH]= 0;
+ my_uuid2str(share->base.uuid, buff);
+ printf("UUID: %s\n", buff);
+ pos=buff;
+ if (share->state.changed & STATE_CRASHED)
+ strmov(buff,"crashed");
+ else
+ {
+ if (share->state.open_count)
+ pos=strmov(pos,"open,");
+ if (share->state.changed & STATE_CHANGED)
+ pos=strmov(pos,"changed,");
+ else
+ pos=strmov(pos,"checked,");
+ if (!(share->state.changed & STATE_NOT_ANALYZED))
+ pos=strmov(pos,"analyzed,");
+ if (!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))
+ pos=strmov(pos,"optimized keys,");
+ if (!(share->state.changed & STATE_NOT_SORTED_PAGES))
+ pos=strmov(pos,"sorted index pages,");
+ if (!(share->state.changed & STATE_NOT_ZEROFILLED))
+ pos=strmov(pos,"zerofilled,");
+ if (!(share->state.changed & STATE_NOT_MOVABLE))
+ pos=strmov(pos,"movable,");
+ pos[-1]=0; /* Remove extra ',' */
+ }
+ printf("Status: %s\n",buff);
+ if (share->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
+ printf("Checksum: %26s\n",llstr(info->state->checksum,llbuff));
+;
+ if (share->options & HA_OPTION_DELAY_KEY_WRITE)
+ printf("Keys are only flushed at close\n");
+
+ if (share->options & HA_OPTION_PAGE_CHECKSUM)
+ printf("Page checksums are used\n");
+ if (share->base.auto_key)
+ {
+ printf("Auto increment key: %16d Last value: %18s\n",
+ share->base.auto_key,
+ llstr(share->state.auto_increment,llbuff));
+ }
+ }
+ printf("Data records: %16s Deleted blocks: %18s\n",
+ llstr(info->state->records,llbuff),llstr(info->state->del,llbuff2));
+ if (param->testflag & T_SILENT)
+ DBUG_VOID_RETURN; /* This is enough */
+
+ if (param->testflag & T_VERBOSE)
+ {
+#ifdef USE_RELOC
+ printf("Init-relocation: %16s\n",llstr(share->base.reloc,llbuff));
+#endif
+ printf("Datafile parts: %16s Deleted data: %18s\n",
+ llstr(share->state.split,llbuff),
+ llstr(info->state->empty,llbuff2));
+ printf("Datafile pointer (bytes): %11d Keyfile pointer (bytes): %13d\n",
+ share->rec_reflength,share->base.key_reflength);
+ printf("Datafile length: %16s Keyfile length: %18s\n",
+ llstr(info->state->data_file_length,llbuff),
+ llstr(info->state->key_file_length,llbuff2));
+
+ if (info->s->base.reloc == 1L && info->s->base.records == 1L)
+ puts("This is a one-record table");
+ else
+ {
+ if (share->base.max_data_file_length != HA_OFFSET_ERROR ||
+ share->base.max_key_file_length != HA_OFFSET_ERROR)
+ printf("Max datafile length: %16s Max keyfile length: %18s\n",
+ llstr(share->base.max_data_file_length-1,llbuff),
+ llstr(share->base.max_key_file_length-1,llbuff2));
+ }
+ }
+ printf("Block_size: %16d\n",(int) share->block_size);
+ printf("Recordlength: %16d\n",(int) share->base.pack_reclength);
+ if (! maria_is_all_keys_active(share->state.key_map, share->base.keys))
+ {
+ longlong2str(share->state.key_map,buff,2);
+ printf("Using only keys '%s' of %d possibly keys\n",
+ buff, share->base.keys);
+ }
+ puts("\ntable description:");
+ printf("Key Start Len Index Type");
+ if (param->testflag & T_VERBOSE)
+ printf(" Rec/key Root Blocksize");
+ VOID(putchar('\n'));
+
+ for (key=keyseg_nr=0, keyinfo= &share->keyinfo[0] ;
+ key < share->base.keys;
+ key++,keyinfo++)
+ {
+ keyseg=keyinfo->seg;
+ if (keyinfo->flag & HA_NOSAME) text="unique ";
+ else if (keyinfo->flag & HA_FULLTEXT) text="fulltext ";
+ else text="multip.";
+
+ pos=buff;
+ if (keyseg->flag & HA_REVERSE_SORT)
+ *pos++ = '-';
+ pos=strmov(pos,type_names[keyseg->type]);
+ *pos++ = ' ';
+ *pos=0;
+ if (keyinfo->flag & HA_PACK_KEY)
+ pos=strmov(pos,prefix_packed_txt);
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ pos=strmov(pos,bin_packed_txt);
+ if (keyseg->flag & HA_SPACE_PACK)
+ pos=strmov(pos,diff_txt);
+ if (keyseg->flag & HA_BLOB_PART)
+ pos=strmov(pos,blob_txt);
+ if (keyseg->flag & HA_NULL_PART)
+ pos=strmov(pos,null_txt);
+ *pos=0;
+
+ printf("%-4d%-6ld%-3d %-8s%-23s",
+ key+1,(long) keyseg->start+1,keyseg->length,text,buff);
+ if (share->state.key_root[key] != HA_OFFSET_ERROR)
+ llstr(share->state.key_root[key],buff);
+ else
+ buff[0]=0;
+ if (param->testflag & T_VERBOSE)
+ printf("%9.0f %12s %10d",
+ share->state.rec_per_key_part[keyseg_nr++],
+ buff,keyinfo->block_length);
+ VOID(putchar('\n'));
+ while ((++keyseg)->type != HA_KEYTYPE_END)
+ {
+ pos=buff;
+ if (keyseg->flag & HA_REVERSE_SORT)
+ *pos++ = '-';
+ pos=strmov(pos,type_names[keyseg->type]);
+ *pos++= ' ';
+ if (keyseg->flag & HA_SPACE_PACK)
+ pos=strmov(pos,diff_txt);
+ if (keyseg->flag & HA_BLOB_PART)
+ pos=strmov(pos,blob_txt);
+ if (keyseg->flag & HA_NULL_PART)
+ pos=strmov(pos,null_txt);
+ *pos=0;
+ printf(" %-6ld%-3d %-21s",
+ (long) keyseg->start+1,keyseg->length,buff);
+ if (param->testflag & T_VERBOSE)
+ printf("%11.0f", share->state.rec_per_key_part[keyseg_nr++]);
+ VOID(putchar('\n'));
+ }
+ keyseg++;
+ }
+ if (share->state.header.uniques)
+ {
+ MARIA_UNIQUEDEF *uniqueinfo;
+ puts("\nUnique Key Start Len Nullpos Nullbit Type");
+ for (key=0,uniqueinfo= &share->uniqueinfo[0] ;
+ key < share->state.header.uniques; key++, uniqueinfo++)
+ {
+ my_bool new_row=0;
+ char null_bit[8],null_pos[8];
+ printf("%-8d%-5d",key+1,uniqueinfo->key+1);
+ for (keyseg=uniqueinfo->seg ; keyseg->type != HA_KEYTYPE_END ; keyseg++)
+ {
+ if (new_row)
+ fputs(" ",stdout);
+ null_bit[0]=null_pos[0]=0;
+ if (keyseg->null_bit)
+ {
+ sprintf(null_bit,"%d",keyseg->null_bit);
+ sprintf(null_pos,"%ld",(long) keyseg->null_pos+1);
+ }
+ printf("%-7ld%-5d%-9s%-10s%-30s\n",
+ (long) keyseg->start+1,keyseg->length,
+ null_pos,null_bit,
+ type_names[keyseg->type]);
+ new_row=1;
+ }
+ }
+ }
+ if (param->verbose > 1)
+ {
+ char null_bit[8],null_pos[8];
+ printf("\nField Start Length Nullpos Nullbit Type");
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ printf(" Huff tree Bits");
+ VOID(putchar('\n'));
+
+ for (field=0 ; field < share->base.fields ; field++)
+ {
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ type=share->columndef[field].base_type;
+ else
+ type=(enum en_fieldtype) share->columndef[field].type;
+ end=strmov(buff,field_pack[type]);
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ if (share->columndef[field].pack_type & PACK_TYPE_SELECTED)
+ end=strmov(end,", not_always");
+ if (share->columndef[field].pack_type & PACK_TYPE_SPACE_FIELDS)
+ end=strmov(end,", no empty");
+ if (share->columndef[field].pack_type & PACK_TYPE_ZERO_FILL)
+ {
+ sprintf(end,", zerofill(%d)",share->columndef[field].space_length_bits);
+ end=strend(end);
+ }
+ }
+ if (buff[0] == ',')
+ strmov(buff,buff+2);
+ int10_to_str((long) share->columndef[field].length,length,10);
+ null_bit[0]=null_pos[0]=0;
+ if (share->columndef[field].null_bit)
+ {
+ sprintf(null_bit,"%d",share->columndef[field].null_bit);
+ sprintf(null_pos,"%d",share->columndef[field].null_pos+1);
+ }
+ printf("%-6d%-6u%-7s%-8s%-8s%-35s",field+1,
+ (uint) share->columndef[field].offset+1,
+ length, null_pos, null_bit, buff);
+ if (share->options & HA_OPTION_COMPRESS_RECORD)
+ {
+ if (share->columndef[field].huff_tree)
+ printf("%3d %2d",
+ (uint) (share->columndef[field].huff_tree-share->decode_trees)+1,
+ share->columndef[field].huff_tree->quick_table_bits);
+ }
+ VOID(putchar('\n'));
+ }
+ }
+ DBUG_VOID_RETURN;
+} /* describe */
+
+
+ /* Sort records according to one key */
+
+static int maria_sort_records(HA_CHECK *param,
+ register MARIA_HA *info, char *name,
+ uint sort_key,
+ my_bool write_info,
+ my_bool update_index)
+{
+ int got_error;
+ uint key;
+ MARIA_KEYDEF *keyinfo;
+ File new_file;
+ uchar *temp_buff;
+ ha_rows old_record_count;
+ MARIA_SHARE *share= info->s;
+ char llbuff[22],llbuff2[22];
+ MARIA_SORT_INFO sort_info;
+ MARIA_SORT_PARAM sort_param;
+ DBUG_ENTER("sort_records");
+
+ bzero((char*)&sort_info,sizeof(sort_info));
+ bzero((char*)&sort_param,sizeof(sort_param));
+ sort_param.sort_info=&sort_info;
+ sort_info.param=param;
+ keyinfo= &share->keyinfo[sort_key];
+ got_error=1;
+ temp_buff=0;
+ new_file= -1;
+
+ if (! maria_is_key_active(share->state.key_map, sort_key))
+ {
+ _ma_check_print_warning(param,
+ "Can't sort table '%s' on key %d; No such key",
+ name,sort_key+1);
+ param->error_printed=0;
+ DBUG_RETURN(0); /* Nothing to do */
+ }
+ if (keyinfo->flag & HA_FULLTEXT)
+ {
+ _ma_check_print_warning(param,"Can't sort table '%s' on FULLTEXT key %d",
+ name,sort_key+1);
+ param->error_printed=0;
+ DBUG_RETURN(0); /* Nothing to do */
+ }
+ if (keyinfo->flag & HA_BINARY_PACK_KEY)
+ {
+ _ma_check_print_warning(param,
+ "Can't sort table '%s' on a key with prefix "
+ "packing %d",
+ name,sort_key+1);
+ param->error_printed=0;
+ DBUG_RETURN(0);
+ }
+
+
+ if (share->data_file_type == COMPRESSED_RECORD)
+ {
+ _ma_check_print_warning(param,"Can't sort read-only table '%s'", name);
+ param->error_printed=0;
+ DBUG_RETURN(0); /* Nothing to do */
+ }
+ if (!(param->testflag & T_SILENT))
+ {
+ printf("- Sorting records for MARIA-table '%s'\n",name);
+ if (write_info)
+ printf("Data records: %9s Deleted: %9s\n",
+ llstr(info->state->records,llbuff),
+ llstr(info->state->del,llbuff2));
+ }
+ if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
+ DBUG_RETURN(0); /* Nothing to do */
+
+ if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
+ WRITE_CACHE,share->pack.header_length,1,
+ MYF(MY_WME | MY_WAIT_IF_FULL)))
+ goto err;
+ info->opt_flag|=WRITE_CACHE_USED;
+
+ if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ _ma_check_print_error(param,"Not enough memory for key block");
+ goto err;
+ }
+
+ if (!(sort_param.record=
+ (uchar*) my_malloc((uint) share->base.default_rec_buff_size, MYF(0))))
+ {
+ _ma_check_print_error(param,"Not enough memory for record");
+ goto err;
+ }
+
+ fn_format(param->temp_filename,name,"", MARIA_NAME_DEXT,2+4+32);
+ new_file= my_create(fn_format(param->temp_filename,
+ param->temp_filename,"",
+ DATA_TMP_EXT,
+ MY_REPLACE_EXT | MY_UNPACK_FILENAME),
+ 0, param->tmpfile_createflag,
+ MYF(0));
+ if (new_file < 0)
+ {
+ _ma_check_print_error(param,"Can't create new tempfile: '%s'",
+ param->temp_filename);
+ goto err;
+ }
+ if (share->pack.header_length)
+ if (maria_filecopy(param, new_file, info->dfile.file, 0L,
+ share->pack.header_length,
+ "datafile-header"))
+ goto err;
+ info->rec_cache.file=new_file; /* Use this file for cacheing*/
+
+ maria_lock_memory(param);
+ for (key=0 ; key < share->base.keys ; key++)
+ share->keyinfo[key].flag|= HA_SORT_ALLOWS_SAME;
+
+ if (my_pread(share->kfile.file, temp_buff,
+ (uint) keyinfo->block_length,
+ share->state.key_root[sort_key],
+ MYF(MY_NABP+MY_WME)))
+ {
+ _ma_check_print_error(param, "Can't read indexpage from filepos: %s",
+ llstr(share->state.key_root[sort_key], llbuff));
+ goto err;
+ }
+
+ /* Setup param for _ma_sort_write_record */
+ sort_info.info=info;
+ sort_info.new_data_file_type=share->data_file_type;
+ sort_param.fix_datafile=1;
+ sort_param.master=1;
+ sort_param.filepos=share->pack.header_length;
+ old_record_count=info->state->records;
+ info->state->records=0;
+ if (sort_info.new_data_file_type != COMPRESSED_RECORD)
+ info->state->checksum=0;
+
+ if (sort_record_index(&sort_param,info,keyinfo,
+ share->state.key_root[sort_key],
+ temp_buff, sort_key,new_file,update_index) ||
+ maria_write_data_suffix(&sort_info,1) ||
+ flush_io_cache(&info->rec_cache))
+ goto err;
+
+ if (info->state->records != old_record_count)
+ {
+ _ma_check_print_error(param,"found %s of %s records",
+ llstr(info->state->records,llbuff),
+ llstr(old_record_count,llbuff2));
+ goto err;
+ }
+
+ VOID(my_close(info->dfile.file, MYF(MY_WME)));
+ param->out_flag|=O_NEW_DATA; /* Data in new file */
+ info->dfile.file= new_file; /* Use new datafile */
+ _ma_set_data_pagecache_callbacks(&info->dfile, info->s);
+
+ info->state->del=0;
+ info->state->empty=0;
+ share->state.dellink= HA_OFFSET_ERROR;
+ info->state->data_file_length=sort_param.filepos;
+ share->state.split=info->state->records; /* Only hole records */
+ share->state.version=(ulong) time((time_t*) 0);
+
+ info->update= (short) (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
+
+ if (param->testflag & T_WRITE_LOOP)
+ {
+ VOID(fputs(" \r",stdout)); VOID(fflush(stdout));
+ }
+ got_error=0;
+
+err:
+ if (got_error && new_file >= 0)
+ {
+ VOID(end_io_cache(&info->rec_cache));
+ (void) my_close(new_file,MYF(MY_WME));
+ (void) my_delete(param->temp_filename, MYF(MY_WME));
+ }
+ if (temp_buff)
+ {
+ my_afree((uchar*) temp_buff);
+ }
+ my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR));
+ info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
+ VOID(end_io_cache(&info->rec_cache));
+ my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
+ sort_info.buff=0;
+ share->state.sortkey=sort_key;
+ DBUG_RETURN(got_error);
+} /* sort_records */
+
+
+/* Sort records recursive using one index */
+
+static int sort_record_index(MARIA_SORT_PARAM *sort_param,MARIA_HA *info,
+ MARIA_KEYDEF *keyinfo,
+ my_off_t page, uchar *buff, uint sort_key,
+ File new_file,my_bool update_index)
+{
+ MARIA_SHARE *share= info->s;
+ uint page_flag, nod_flag,used_length;
+ uchar *temp_buff,*keypos,*endpos;
+ my_off_t next_page,rec_pos;
+ uchar lastkey[MARIA_MAX_KEY_BUFF];
+ char llbuff[22];
+ MARIA_SORT_INFO *sort_info= sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
+ MARIA_KEY tmp_key;
+ DBUG_ENTER("sort_record_index");
+
+ page_flag= _ma_get_keypage_flag(share, buff);
+ nod_flag= _ma_test_if_nod(share, buff);
+ temp_buff=0;
+ tmp_key.keyinfo= keyinfo;
+ tmp_key.data= lastkey;
+
+ if (nod_flag)
+ {
+ if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length)))
+ {
+ _ma_check_print_error(param,"Not Enough memory");
+ DBUG_RETURN(-1);
+ }
+ }
+ used_length= _ma_get_page_used(share, buff);
+ keypos= buff + share->keypage_header + nod_flag;
+ endpos= buff + used_length;
+ for ( ;; )
+ {
+ _sanity(__FILE__,__LINE__);
+ if (nod_flag)
+ {
+ next_page= _ma_kpos(nod_flag, keypos);
+ if (my_pread(share->kfile.file, (uchar*)temp_buff,
+ (uint) keyinfo->block_length, next_page,
+ MYF(MY_NABP+MY_WME)))
+ {
+ _ma_check_print_error(param,"Can't read keys from filepos: %s",
+ llstr(next_page,llbuff));
+ goto err;
+ }
+ if (sort_record_index(sort_param, info,keyinfo,next_page,temp_buff,
+ sort_key,
+ new_file, update_index))
+ goto err;
+ }
+ _sanity(__FILE__,__LINE__);
+ if (keypos >= endpos ||
+ !(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &keypos))
+ break;
+ rec_pos= _ma_row_pos_from_key(&tmp_key);
+
+ if ((*share->read_record)(info,sort_param->record,rec_pos))
+ {
+ _ma_check_print_error(param,"%d when reading datafile",my_errno);
+ goto err;
+ }
+ if (rec_pos != sort_param->filepos && update_index)
+ {
+ _ma_dpointer(share, keypos - nod_flag - tmp_key.ref_length,
+ sort_param->filepos);
+ if (maria_movepoint(info,sort_param->record,rec_pos,sort_param->filepos,
+ sort_key))
+ {
+ _ma_check_print_error(param,"%d when updating key-pointers",my_errno);
+ goto err;
+ }
+ }
+ if (_ma_sort_write_record(sort_param))
+ goto err;
+ }
+ /* Clear end of block to get better compression if the table is backuped */
+ bzero((uchar*) buff+used_length,keyinfo->block_length-used_length);
+ if (my_pwrite(share->kfile.file, (uchar*)buff, (uint)keyinfo->block_length,
+ page,param->myf_rw))
+ {
+ _ma_check_print_error(param,"%d when updating keyblock",my_errno);
+ goto err;
+ }
+ if (temp_buff)
+ my_afree((uchar*) temp_buff);
+ DBUG_RETURN(0);
+err:
+ if (temp_buff)
+ my_afree((uchar*) temp_buff);
+ DBUG_RETURN(1);
+} /* sort_record_index */
+
+
+static my_bool write_log_record(HA_CHECK *param)
+{
+ /*
+ Now that all operations including O_NEW_DATA|INDEX are successfully
+ done, we can write a log record.
+ */
+ MARIA_HA *info= maria_open(param->isam_file_name, O_RDWR, 0);
+ if (info == NULL)
+ _ma_check_print_error(param, default_open_errmsg, my_errno,
+ param->isam_file_name);
+ else
+ {
+ if (write_log_record_for_repair(param, info))
+ _ma_check_print_error(param, "%d when writing log record for"
+ " MARIA-table '%s'", my_errno,
+ param->isam_file_name);
+ else if (maria_close(info))
+ _ma_check_print_error(param, default_close_errmsg, my_errno,
+ param->isam_file_name);
+ else
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#include "ma_check_standalone.h"
diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h
new file mode 100644
index 00000000000..7c2017c4671
--- /dev/null
+++ b/storage/maria/maria_def.h
@@ -0,0 +1,1221 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* This file is included by all internal maria files */
+
+#include "maria.h" /* Structs & some defines */
+#include <myisampack.h> /* packing of keys */
+#include <my_tree.h>
+#include <my_bitmap.h>
+#ifdef THREAD
+#include <my_pthread.h>
+#include <thr_lock.h>
+#else
+#include <my_no_pthread.h>
+#endif
+#include <hash.h>
+#include "ma_loghandler.h"
+#include "ma_control_file.h"
+#include "ma_state.h"
+#include <waiting_threads.h>
+
+/* For testing recovery */
+#ifdef TO_BE_REMOVED
+#define IDENTICAL_PAGES_AFTER_RECOVERY 1
+#endif
+/* Do extra sanity checking */
+#define SANITY_CHECKS 1
+#ifdef EXTRA_DEBUG
+#define EXTRA_DEBUG_KEY_CHANGES
+#endif
+
+#define MAX_NONMAPPED_INSERTS 1000
+#define MARIA_MAX_TREE_LEVELS 32
+
+/* maria_open() flag, specific for maria_pack */
+#define HA_OPEN_IGNORE_MOVED_STATE (1U << 30)
+
+struct st_transaction;
+
+/* undef map from my_nosys; We need test-if-disk full */
+#undef my_write
+
+#define CRC_SIZE 4
+
+typedef struct st_maria_state_info
+{
+ struct
+ { /* Fileheader (24 bytes) */
+ uchar file_version[4];
+ uchar options[2];
+ uchar header_length[2];
+ uchar state_info_length[2];
+ uchar base_info_length[2];
+ uchar base_pos[2];
+ uchar key_parts[2]; /* Key parts */
+ uchar unique_key_parts[2]; /* Key parts + unique parts */
+ uchar keys; /* number of keys in file */
+ uchar uniques; /* number of UNIQUE definitions */
+ uchar language; /* Language for indexes */
+ uchar fulltext_keys;
+ uchar data_file_type;
+ /* Used by mariapack to store the original data_file_type */
+ uchar org_data_file_type;
+ } header;
+
+ MARIA_STATUS_INFO state;
+ /* maria_ha->state points here for crash-safe but not versioned tables */
+ MARIA_STATUS_INFO common;
+ ha_rows split; /* number of split blocks */
+ my_off_t dellink; /* Link to next removed block */
+ pgcache_page_no_t first_bitmap_with_space;
+ ulonglong auto_increment;
+ TrID create_trid; /* Minum trid for file */
+ ulong update_count; /* Updated for each write lock */
+ ulong status;
+ double *rec_per_key_part;
+ ulong *nulls_per_key_part;
+ ha_checksum checksum; /* Table checksum */
+ my_off_t *key_root; /* Start of key trees */
+ my_off_t key_del; /* delete links for index pages */
+ my_off_t records_at_analyze; /* Rows when calculating rec_per_key */
+
+ ulong sec_index_changed; /* Updated when new sec_index */
+ ulong sec_index_used; /* which extra index are in use */
+ ulonglong key_map; /* Which keys are in use */
+ ulong version; /* timestamp of create */
+ time_t create_time; /* Time when created database */
+ time_t recover_time; /* Time for last recover */
+ time_t check_time; /* Time for last check */
+ uint sortkey; /* sorted by this key (not used) */
+ uint open_count;
+ uint changed; /* Changed since maria_chk */
+ /**
+ Birthday of the table: no record in the log before this LSN should ever
+ be applied to the table. Updated when created, renamed, explicitely
+ repaired (REPAIR|OPTIMIZE TABLE, ALTER TABLE ENABLE KEYS, maria_chk).
+ */
+ LSN create_rename_lsn;
+ /** @brief Log horizon when state was last updated on disk */
+ TRANSLOG_ADDRESS is_of_horizon;
+ /**
+ REDO phase should ignore any record before this LSN. UNDO phase
+ shouldn't, this is the difference with create_rename_lsn.
+ skip_redo_lsn >= create_rename_lsn.
+ The distinction is for these cases:
+ - after a repair at end of bulk insert (enabling indices), REDO phase
+ should skip the table but UNDO phase should not, so only skip_redo_lsn is
+ increased, not create_rename_lsn
+ - if one table is corrupted and so recovery fails, user may repair the
+ table with maria_chk and let recovery restart: that recovery should then
+ skip the repaired table even in the UNDO phase, so create_rename_lsn is
+ increased.
+ */
+ LSN skip_redo_lsn;
+
+ /* the following isn't saved on disk */
+ uint state_diff_length; /* Should be 0 */
+ uint state_length; /* Length of state header in file */
+ ulong *key_info;
+} MARIA_STATE_INFO;
+
+
+#define MARIA_STATE_INFO_SIZE \
+ (24 + 2 + LSN_STORE_SIZE*3 + 4 + 11*8 + 4*4 + 8 + 3*4 + 5*8)
+#define MARIA_FILE_OPEN_COUNT_OFFSET 0
+#define MARIA_FILE_CHANGED_OFFSET 2
+#define MARIA_FILE_CREATE_RENAME_LSN_OFFSET 4
+#define MARIA_FILE_CREATE_TRID_OFFSET (4 + LSN_STORE_SIZE*3 + 11*8)
+
+#define MARIA_STATE_KEY_SIZE (8 + 4)
+#define MARIA_STATE_KEYBLOCK_SIZE 8
+#define MARIA_STATE_KEYSEG_SIZE 12
+#define MARIA_STATE_EXTRA_SIZE (MARIA_MAX_KEY*MARIA_STATE_KEY_SIZE + MARIA_MAX_KEY*HA_MAX_KEY_SEG*MARIA_STATE_KEYSEG_SIZE)
+#define MARIA_KEYDEF_SIZE (2+ 5*2)
+#define MARIA_UNIQUEDEF_SIZE (2+1+1)
+#define HA_KEYSEG_SIZE (6+ 2*2 + 4*2)
+#define MARIA_MAX_KEY_BUFF (HA_MAX_KEY_BUFF + MARIA_MAX_PACK_TRANSID_SIZE)
+#define MARIA_COLUMNDEF_SIZE (2*7+1+1+4)
+#define MARIA_BASE_INFO_SIZE (MY_UUID_SIZE + 5*8 + 6*4 + 11*2 + 6 + 5*2 + 1 + 16)
+#define MARIA_INDEX_BLOCK_MARGIN 16 /* Safety margin for .MYI tables */
+/* Internal management bytes needed to store 2 transid/key on an index page */
+#define MARIA_MAX_PACK_TRANSID_SIZE (TRANSID_SIZE+1)
+#define MARIA_TRANSID_PACK_OFFSET (256- TRANSID_SIZE - 1)
+#define MARIA_MIN_TRANSID_PACK_OFFSET (MARIA_TRANSID_PACK_OFFSET-TRANSID_SIZE)
+#define MARIA_INDEX_OVERHEAD_SIZE (MARIA_MAX_PACK_TRANSID_SIZE * 2)
+#define MARIA_DELETE_KEY_NR 255 /* keynr for deleted blocks */
+
+/*
+ Basic information of the Maria table. This is stored on disk
+ and not changed (unless we do DLL changes).
+*/
+
+typedef struct st_ma_base_info
+{
+ my_off_t keystart; /* Start of keys */
+ my_off_t max_data_file_length;
+ my_off_t max_key_file_length;
+ my_off_t margin_key_file_length;
+ ha_rows records, reloc; /* Create information */
+ ulong mean_row_length; /* Create information */
+ ulong reclength; /* length of unpacked record */
+ ulong pack_reclength; /* Length of full packed rec */
+ ulong min_pack_length;
+ ulong max_pack_length; /* Max possibly length of packed rec */
+ ulong min_block_length;
+ uint fields; /* fields in table */
+ uint fixed_not_null_fields;
+ uint fixed_not_null_fields_length;
+ uint max_field_lengths;
+ uint pack_fields; /* packed fields in table */
+ uint varlength_fields; /* char/varchar/blobs */
+ /* Number of bytes in the index used to refer to a row (2-8) */
+ uint rec_reflength;
+ /* Number of bytes in the index used to refer to another index page (2-8) */
+ uint key_reflength; /* = 2-8 */
+ uint keys; /* same as in state.header */
+ uint auto_key; /* Which key-1 is a auto key */
+ uint blobs; /* Number of blobs */
+ /* Length of packed bits (when table was created first time) */
+ uint pack_bytes;
+ /* Length of null bits (when table was created first time) */
+ uint original_null_bytes;
+ uint null_bytes; /* Null bytes in record */
+ uint field_offsets; /* Number of field offsets */
+ uint max_key_block_length; /* Max block length */
+ uint max_key_length; /* Max key length */
+ /* Extra allocation when using dynamic record format */
+ uint extra_alloc_bytes;
+ uint extra_alloc_procent;
+ uint is_nulls_extended; /* 1 if new null bytes */
+ uint default_row_flag; /* 0 or ROW_FLAG_NULLS_EXTENDED */
+ uint block_size;
+ /* Size of initial record buffer */
+ uint default_rec_buff_size;
+ /* Extra number of bytes the row format require in the record buffer */
+ uint extra_rec_buff_size;
+ /* Tuning flags that can be ignored by older Maria versions */
+ uint extra_options;
+
+ /* The following are from the header */
+ uint key_parts, all_key_parts;
+ uchar uuid[MY_UUID_SIZE];
+ /**
+ @brief If false, we disable logging, versioning, transaction etc. Observe
+ difference with MARIA_SHARE::now_transactional
+ */
+ my_bool born_transactional;
+} MARIA_BASE_INFO;
+
+
+/* Structs used intern in database */
+
+typedef struct st_maria_blob /* Info of record */
+{
+ ulong offset; /* Offset to blob in record */
+ uint pack_length; /* Type of packed length */
+ ulong length; /* Calc:ed for each record */
+} MARIA_BLOB;
+
+
+typedef struct st_maria_pack
+{
+ ulong header_length;
+ uint ref_length;
+ uchar version;
+} MARIA_PACK;
+
+typedef struct st_maria_file_bitmap
+{
+ uchar *map;
+ pgcache_page_no_t page; /* Page number for current bitmap */
+ uint used_size; /* Size of bitmap head that is not 0 */
+ my_bool changed; /* 1 if page needs to be flushed */
+ my_bool flush_all_requested; /**< If _ma_bitmap_flush_all waiting */
+ uint non_flushable; /**< 0 if bitmap and log are in sync */
+ PAGECACHE_FILE file; /* datafile where bitmap is stored */
+
+#ifdef THREAD
+ pthread_mutex_t bitmap_lock;
+ pthread_cond_t bitmap_cond; /**< When bitmap becomes flushable */
+#endif
+ /* Constants, allocated when initiating bitmaps */
+ uint sizes[8]; /* Size per bit combination */
+ uint total_size; /* Total usable size of bitmap page */
+ uint block_size; /* Block size of file */
+ ulong pages_covered; /* Pages covered by bitmap + 1 */
+ DYNAMIC_ARRAY pinned_pages; /**< not-yet-flushable bitmap pages */
+} MARIA_FILE_BITMAP;
+
+#define MARIA_CHECKPOINT_LOOKS_AT_ME 1
+#define MARIA_CHECKPOINT_SHOULD_FREE_ME 2
+#define MARIA_CHECKPOINT_SEEN_IN_LOOP 4
+
+typedef struct st_maria_share
+{ /* Shared between opens */
+ MARIA_STATE_INFO state;
+ MARIA_BASE_INFO base;
+ MARIA_STATE_HISTORY *state_history;
+ MARIA_KEYDEF ft2_keyinfo; /* Second-level ft-key definition */
+ MARIA_KEYDEF *keyinfo; /* Key definitions */
+ MARIA_UNIQUEDEF *uniqueinfo; /* unique definitions */
+ HA_KEYSEG *keyparts; /* key part info */
+ MARIA_COLUMNDEF *columndef; /* Pointer to column information */
+ MARIA_PACK pack; /* Data about packed records */
+ MARIA_BLOB *blobs; /* Pointer to blobs */
+ uint16 *column_nr; /* Original column order */
+ LEX_STRING unique_file_name; /* realpath() of index file */
+ LEX_STRING data_file_name; /* Resolved path names from symlinks */
+ LEX_STRING index_file_name;
+ LEX_STRING open_file_name; /* parameter to open filename */
+ uchar *file_map; /* mem-map of file if possible */
+ PAGECACHE *pagecache; /* ref to the current key cache */
+ MARIA_DECODE_TREE *decode_trees;
+ /*
+ Previous auto-increment value. Used to verify if we can restore the
+ auto-increment counter if we have to abort an insert (duplicate key).
+ */
+ ulonglong last_auto_increment;
+ uint16 *decode_tables;
+ uint16 id; /**< 2-byte id by which log records refer to the table */
+ /* Called the first time the table instance is opened */
+ my_bool (*once_init)(struct st_maria_share *, File);
+ /* Called when the last instance of the table is closed */
+ my_bool (*once_end)(struct st_maria_share *);
+ /* Is called for every open of the table */
+ my_bool (*init)(MARIA_HA *);
+ /* Is called for every close of the table */
+ void (*end)(MARIA_HA *);
+ /* Called when we want to read a record from a specific position */
+ int (*read_record)(MARIA_HA *, uchar *, MARIA_RECORD_POS);
+ /* Initialize a scan */
+ my_bool (*scan_init)(MARIA_HA *);
+ /* Read next record while scanning */
+ int (*scan)(MARIA_HA *, uchar *, MARIA_RECORD_POS, my_bool);
+ /* End scan */
+ void (*scan_end)(MARIA_HA *);
+ int (*scan_remember_pos)(MARIA_HA *, MARIA_RECORD_POS*);
+ void (*scan_restore_pos)(MARIA_HA *, MARIA_RECORD_POS);
+ /* Pre-write of row (some handlers may do the actual write here) */
+ MARIA_RECORD_POS (*write_record_init)(MARIA_HA *, const uchar *);
+ /* Write record (or accept write_record_init) */
+ my_bool (*write_record)(MARIA_HA *, const uchar *);
+ /* Called when write failed */
+ my_bool (*write_record_abort)(MARIA_HA *);
+ my_bool (*update_record)(MARIA_HA *, MARIA_RECORD_POS,
+ const uchar *, const uchar *);
+ my_bool (*delete_record)(MARIA_HA *, const uchar *record);
+ my_bool (*compare_record)(MARIA_HA *, const uchar *);
+ /* calculate checksum for a row */
+ ha_checksum(*calc_checksum)(MARIA_HA *, const uchar *);
+ /*
+ Calculate checksum for a row during write. May be 0 if we calculate
+ the checksum in write_record_init()
+ */
+ ha_checksum(*calc_write_checksum)(MARIA_HA *, const uchar *);
+ /* calculate checksum for a row during check table */
+ ha_checksum(*calc_check_checksum)(MARIA_HA *, const uchar *);
+ /* Compare a row in memory with a row on disk */
+ my_bool (*compare_unique)(MARIA_HA *, MARIA_UNIQUEDEF *,
+ const uchar *record, MARIA_RECORD_POS pos);
+ my_off_t (*keypos_to_recpos)(struct st_maria_share *share, my_off_t pos);
+ my_off_t (*recpos_to_keypos)(struct st_maria_share *share, my_off_t pos);
+ my_bool (*row_is_visible)(MARIA_HA *);
+
+ /* Mapings to read/write the data file */
+ size_t (*file_read)(MARIA_HA *, uchar *, size_t, my_off_t, myf);
+ size_t (*file_write)(MARIA_HA *, const uchar *, size_t, my_off_t, myf);
+ invalidator_by_filename invalidator; /* query cache invalidator */
+ my_off_t key_del_current; /* delete links for index pages */
+ ulong this_process; /* processid */
+ ulong last_process; /* For table-change-check */
+ ulong last_version; /* Version on start */
+ ulong options; /* Options used */
+ ulong min_pack_length; /* These are used by packed data */
+ ulong max_pack_length;
+ ulong state_diff_length;
+ uint rec_reflength; /* rec_reflength in use now */
+ uint keypage_header;
+ uint32 ftparsers; /* Number of distinct ftparsers
+ + 1 */
+ PAGECACHE_FILE kfile; /* Shared keyfile */
+ File data_file; /* Shared data file */
+ int mode; /* mode of file on open */
+ uint reopen; /* How many times opened */
+ uint in_trans; /* Number of references by trn */
+ uint w_locks, r_locks, tot_locks; /* Number of read/write locks */
+ uint block_size; /* block_size of keyfile & data file*/
+ /* Fixed length part of a packed row in BLOCK_RECORD format */
+ uint base_length;
+ myf write_flag;
+ enum data_file_type data_file_type;
+ enum pagecache_page_type page_type; /* value depending transactional */
+ /**
+ if Checkpoint looking at table; protected by close_lock or THR_LOCK_maria
+ */
+ uint8 in_checkpoint;
+ my_bool temporary;
+ /* Below flag is needed to make log tables work with concurrent insert */
+ my_bool is_log_table;
+
+ my_bool changed, /* If changed since lock */
+ global_changed, /* If changed since open */
+ not_flushed;
+ my_bool lock_key_trees; /* If we have to lock trees on read */
+ my_bool non_transactional_concurrent_insert;
+ my_bool delay_key_write;
+ my_bool have_rtree;
+ /**
+ @brief if the table is transactional right now. It may have been created
+ transactional (base.born_transactional==TRUE) but with transactionality
+ (logging) temporarily disabled (now_transactional==FALSE). The opposite
+ (FALSE, TRUE) is impossible.
+ */
+ my_bool now_transactional;
+ my_bool have_versioning;
+ my_bool key_del_used; /* != 0 if key_del is locked */
+#ifdef THREAD
+ THR_LOCK lock;
+ void (*lock_restore_status)(void *);
+ /**
+ Protects kfile, dfile, most members of the state, state disk writes,
+ versioning information (like in_trans, state_history).
+ @todo find the exhaustive list.
+ */
+ pthread_mutex_t intern_lock;
+ pthread_mutex_t key_del_lock;
+ pthread_cond_t key_del_cond;
+ /**
+ _Always_ held while closing table; prevents checkpoint from looking at
+ structures freed during closure (like bitmap). If you need close_lock and
+ intern_lock, lock them in this order.
+ */
+ pthread_mutex_t close_lock;
+#endif
+ my_off_t mmaped_length;
+ uint nonmmaped_inserts; /* counter of writing in
+ non-mmaped area */
+ MARIA_FILE_BITMAP bitmap;
+ rw_lock_t mmap_lock;
+ LSN lsn_of_file_id; /**< LSN of its last LOGREC_FILE_ID */
+} MARIA_SHARE;
+
+
+typedef uchar MARIA_BITMAP_BUFFER;
+
+typedef struct st_maria_bitmap_block
+{
+ pgcache_page_no_t page; /* Page number */
+ /* Number of continuous pages. TAIL_BIT is set if this is a tail page */
+ uint page_count;
+ uint empty_space; /* Set for head and tail pages */
+ /*
+ Number of BLOCKS for block-region (holds all non-blob-fields or one blob)
+ */
+ uint sub_blocks;
+ /* set to <> 0 in write_record() if this block was actually used */
+ uint8 used;
+ uint8 org_bitmap_value;
+} MARIA_BITMAP_BLOCK;
+
+
+typedef struct st_maria_bitmap_blocks
+{
+ MARIA_BITMAP_BLOCK *block;
+ uint count;
+ my_bool tail_page_skipped; /* If some tail pages was not used */
+ my_bool page_skipped; /* If some full pages was not used */
+} MARIA_BITMAP_BLOCKS;
+
+
+/* Data about the currently read row */
+typedef struct st_maria_row
+{
+ MARIA_BITMAP_BLOCKS insert_blocks;
+ MARIA_BITMAP_BUFFER *extents;
+ MARIA_RECORD_POS lastpos, nextpos;
+ MARIA_RECORD_POS *tail_positions;
+ ha_checksum checksum;
+ LSN orig_undo_lsn; /* Lsn at start of row insert */
+ TrID trid; /* Transaction id for current row */
+ uchar *empty_bits, *field_lengths;
+ uint *null_field_lengths; /* All null field lengths */
+ ulong *blob_lengths; /* Length for each blob */
+ ulong min_length, normal_length, char_length, varchar_length;
+ ulong blob_length, head_length, total_length;
+ size_t extents_buffer_length; /* Size of 'extents' buffer */
+ uint field_lengths_length; /* Length of data in field_lengths */
+ uint extents_count; /* number of extents in 'extents' */
+ uint full_page_count, tail_count; /* For maria_chk */
+ uint space_on_head_page;
+} MARIA_ROW;
+
+/* Data to scan row in blocked format */
+typedef struct st_maria_block_scan
+{
+ uchar *bitmap_buff, *bitmap_pos, *bitmap_end, *page_buff;
+ uchar *dir, *dir_end;
+ pgcache_page_no_t bitmap_page;
+ ulonglong bits;
+ uint number_of_rows, bit_pos;
+ MARIA_RECORD_POS row_base_page;
+} MARIA_BLOCK_SCAN;
+
+
+struct st_maria_handler
+{
+ MARIA_SHARE *s; /* Shared between open:s */
+ struct st_ma_transaction *trn; /* Pointer to active transaction */
+ MARIA_STATUS_INFO *state, state_save;
+ MARIA_STATUS_INFO *state_start; /* State at start of transaction */
+ MARIA_ROW cur_row; /* The active row that we just read */
+ MARIA_ROW new_row; /* Storage for a row during update */
+ MARIA_KEY last_key; /* Last found key */
+ MARIA_BLOCK_SCAN scan, *scan_save;
+ MARIA_BLOB *blobs; /* Pointer to blobs */
+ MARIA_BIT_BUFF bit_buff;
+ DYNAMIC_ARRAY bitmap_blocks;
+ DYNAMIC_ARRAY pinned_pages;
+ /* accumulate indexfile changes between write's */
+ TREE *bulk_insert;
+ LEX_CUSTRING *log_row_parts; /* For logging */
+ DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
+ MEM_ROOT ft_memroot; /* used by the parser */
+ MYSQL_FTPARSER_PARAM *ftparser_param; /* share info between init/deinit */
+ uchar *buff; /* page buffer */
+ uchar *keyread_buff; /* Buffer for last key read */
+ uchar *lastkey_buff; /* Last used search key */
+ uchar *lastkey_buff2;
+ uchar *first_mbr_key; /* Searhed spatial key */
+ uchar *rec_buff; /* Temp buffer for recordpack */
+ uchar *blob_buff; /* Temp buffer for blobs */
+ uchar *int_keypos, /* Save position for next/previous */
+ *int_maxpos; /* -""- */
+ uchar *update_field_data; /* Used by update in rows-in-block */
+ uint int_nod_flag; /* -""- */
+ uint32 int_keytree_version; /* -""- */
+ int (*read_record)(MARIA_HA *, uchar*, MARIA_RECORD_POS);
+ invalidator_by_filename invalidator; /* query cache invalidator */
+ ulonglong last_auto_increment; /* auto value at start of statement */
+ ulong this_unique; /* uniq filenumber or thread */
+ ulong last_unique; /* last unique number */
+ ulong this_loop; /* counter for this open */
+ ulong last_loop; /* last used counter */
+ MARIA_RECORD_POS save_lastpos;
+ MARIA_RECORD_POS dup_key_pos;
+ TrID dup_key_trid;
+ my_off_t pos; /* Intern variable */
+ my_off_t last_keypage; /* Last key page read */
+ my_off_t last_search_keypage; /* Last keypage when searching */
+
+ /*
+ QQ: the folloing two xxx_length fields should be removed,
+ as they are not compatible with parallel repair
+ */
+ ulong packed_length, blob_length; /* Length of found, packed record */
+ size_t rec_buff_size, blob_buff_size;
+ PAGECACHE_FILE dfile; /* The datafile */
+ IO_CACHE rec_cache; /* When cacheing records */
+ LIST open_list;
+ MY_BITMAP changed_fields;
+ ulong row_base_length; /* Length of row header */
+ uint row_flag; /* Flag to store in row header */
+ uint opt_flag; /* Optim. for space/speed */
+ uint update; /* If file changed since open */
+ int lastinx; /* Last used index */
+ uint last_rkey_length; /* Last length in maria_rkey() */
+ uint *last_rtree_keypos; /* Last key positions for rtrees */
+ uint bulk_insert_ref_length; /* Lenght of row ref during bi */
+ uint non_flushable_state;
+ enum ha_rkey_function last_key_func; /* CONTAIN, OVERLAP, etc */
+ uint save_lastkey_data_length;
+ uint save_lastkey_ref_length;
+ uint pack_key_length; /* For MARIA_MRG */
+ myf lock_wait; /* is 0 or MY_SHORT_WAIT */
+ int errkey; /* Got last error on this key */
+ int lock_type; /* How database was locked */
+ int tmp_lock_type; /* When locked by readinfo */
+ uint data_changed; /* Somebody has changed data */
+ uint save_update; /* When using KEY_READ */
+ int save_lastinx;
+ uint preload_buff_size; /* When preloading indexes */
+ uint16 last_used_keyseg; /* For MARIAMRG */
+ uint8 key_del_used; /* != 0 if key_del is used */
+ my_bool was_locked; /* Was locked in panic */
+ my_bool append_insert_at_end; /* Set if concurrent insert */
+ my_bool quick_mode;
+ /* Marker if key_del_changed */
+ /* If info->keyread_buff can't be used for rnext */
+ my_bool page_changed;
+ /* If info->keyread_buff has to be re-read for rnext */
+ my_bool keyread_buff_used;
+ my_bool once_flags; /* For MARIA_MRG */
+ /* For bulk insert enable/disable transactions control */
+ my_bool switched_transactional;
+#ifdef __WIN__
+ my_bool owned_by_merge; /* This Maria table is part of a merge union */
+#endif
+#ifdef THREAD
+ THR_LOCK_DATA lock;
+#endif
+ uchar *maria_rtree_recursion_state; /* For RTREE */
+ uchar length_buff[5]; /* temp buff to store blob lengths */
+ int maria_rtree_recursion_depth;
+};
+
+/* Some defines used by maria-functions */
+
+#define USE_WHOLE_KEY 65535 /* Use whole key in _search() */
+#define F_EXTRA_LCK -1
+
+/* bits in opt_flag */
+#define MEMMAP_USED 32
+#define REMEMBER_OLD_POS 64
+
+#define WRITEINFO_UPDATE_KEYFILE 1
+#define WRITEINFO_NO_UNLOCK 2
+
+/* once_flags */
+#define USE_PACKED_KEYS 1
+#define RRND_PRESERVE_LASTINX 2
+
+/* bits in state.changed */
+
+#define STATE_CHANGED 1
+#define STATE_CRASHED 2
+#define STATE_CRASHED_ON_REPAIR 4
+#define STATE_NOT_ANALYZED 8
+#define STATE_NOT_OPTIMIZED_KEYS 16
+#define STATE_NOT_SORTED_PAGES 32
+#define STATE_NOT_OPTIMIZED_ROWS 64
+#define STATE_NOT_ZEROFILLED 128
+#define STATE_NOT_MOVABLE 256
+#define STATE_MOVED 512 /* set if base->uuid != maria_uuid */
+
+/* options to maria_read_cache */
+
+#define READING_NEXT 1
+#define READING_HEADER 2
+
+/* Number of bytes on key pages to indicate used size */
+#define KEYPAGE_USED_SIZE 2
+#define KEYPAGE_KEYID_SIZE 1
+#define KEYPAGE_FLAG_SIZE 1
+#define KEYPAGE_CHECKSUM_SIZE 4
+#define MAX_KEYPAGE_HEADER_SIZE (LSN_STORE_SIZE + KEYPAGE_USED_SIZE + \
+ KEYPAGE_KEYID_SIZE + KEYPAGE_FLAG_SIZE + \
+ TRANSID_SIZE)
+#define KEYPAGE_FLAG_ISNOD 1
+#define KEYPAGE_FLAG_HAS_TRANSID 2
+/* Position to KEYPAGE_FLAG for transactional tables */
+#define KEYPAGE_TRANSFLAG_OFFSET LSN_STORE_SIZE + TRANSID_SIZE + KEYPAGE_KEYID_SIZE
+
+#define _ma_get_page_used(share,x) \
+ ((uint) mi_uint2korr((x) + (share)->keypage_header - KEYPAGE_USED_SIZE))
+#define _ma_store_page_used(share,x,y) \
+ mi_int2store((x) + (share)->keypage_header - KEYPAGE_USED_SIZE, (y))
+#define _ma_test_if_nod(share,x) \
+ ((_ma_get_keypage_flag(share,x) & KEYPAGE_FLAG_ISNOD) ? (share)->base.key_reflength : 0)
+
+#define _ma_get_used_and_nod(share,buff,length,nod) \
+{ \
+ (nod)= _ma_test_if_nod((share),(buff)); \
+ (length)= _ma_get_page_used((share),(buff)); \
+}
+#define _ma_get_used_and_nod_with_flag(share,flag,buff,length,nod) \
+{ \
+ (nod)= (((flag) & KEYPAGE_FLAG_ISNOD) ? (share)->base.key_reflength : 0); \
+ (length)= _ma_get_page_used((share),(buff)); \
+}
+#define _ma_store_keynr(share, x, nr) x[(share)->keypage_header - KEYPAGE_KEYID_SIZE - KEYPAGE_FLAG_SIZE - KEYPAGE_USED_SIZE]= (nr)
+#define _ma_get_keynr(share, x) ((uchar) x[(share)->keypage_header - KEYPAGE_KEYID_SIZE - KEYPAGE_FLAG_SIZE - KEYPAGE_USED_SIZE])
+#define _ma_store_transid(buff, transid) \
+ transid_store((buff) + LSN_STORE_SIZE, (transid))
+#define _ma_korr_transid(buff) \
+ transid_korr((buff) + LSN_STORE_SIZE)
+#define _ma_get_keypage_flag(share,x) x[(share)->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_FLAG_SIZE]
+#define _ma_store_keypage_flag(share,x,flag) x[(share)->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_FLAG_SIZE]= (flag)
+#define _ma_mark_page_with_transid(share, x) x[(share)->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_FLAG_SIZE]|= KEYPAGE_FLAG_HAS_TRANSID
+
+
+/*
+ TODO: write int4store_aligned as *((uint32 *) (T))= (uint32) (A) for
+ architectures where it is possible
+*/
+#define int4store_aligned(A,B) int4store((A),(B))
+
+#define maria_mark_crashed(x) do{(x)->s->state.changed|= STATE_CRASHED; \
+ DBUG_PRINT("error", ("Marked table crashed")); \
+ }while(0)
+#define maria_mark_crashed_share(x) \
+ do{(x)->state.changed|= STATE_CRASHED; \
+ DBUG_PRINT("error", ("Marked table crashed")); \
+ }while(0)
+#define maria_mark_crashed_on_repair(x) do{(x)->s->state.changed|= \
+ STATE_CRASHED|STATE_CRASHED_ON_REPAIR; \
+ (x)->update|= HA_STATE_CHANGED; \
+ DBUG_PRINT("error", \
+ ("Marked table crashed")); \
+ }while(0)
+#define maria_is_crashed(x) ((x)->s->state.changed & STATE_CRASHED)
+#define maria_is_crashed_on_repair(x) ((x)->s->state.changed & STATE_CRASHED_ON_REPAIR)
+#ifdef EXTRA_DEBUG
+/**
+ Brings additional information in certain debug builds and in standalone
+ (non-ha_maria) programs. To help debugging. Not in ha_maria, to not spam the
+ user (some messages can be produced many times per statement, or even
+ wrongly during some repair operations).
+*/
+#define maria_print_error(SHARE, ERRNO) \
+ do{ if (!maria_in_ha_maria) \
+ _ma_report_error((ERRNO), &(SHARE)->index_file_name); } \
+ while(0)
+#else
+#define maria_print_error(SHARE, ERRNO) while (0)
+#endif
+#define DBUG_DUMP_KEY(name, key) DBUG_DUMP(name, (key)->data, (key)->data_length + (key)->ref_length)
+
+
+/* Functions to store length of space packed keys, VARCHAR or BLOB keys */
+
+#define store_key_length(key,length) \
+{ if ((length) < 255) \
+ { *(key)=(length); } \
+ else \
+ { *(key)=255; mi_int2store((key)+1,(length)); } \
+}
+
+#define get_key_full_length(length,key) \
+ { if (*(const uchar*) (key) != 255) \
+ length= ((uint) *(const uchar*) ((key)++))+1; \
+ else \
+ { length=mi_uint2korr((key)+1)+3; (key)+=3; } \
+}
+
+#define get_key_full_length_rdonly(length,key) \
+{ if (*(const uchar*) (key) != 255) \
+ length= ((uint) *(const uchar*) ((key)))+1; \
+ else \
+ { length=mi_uint2korr((key)+1)+3; } \
+}
+
+#define maria_max_key_length() ((maria_block_size - MAX_KEYPAGE_HEADER_SIZE)/2 - MARIA_INDEX_OVERHEAD_SIZE)
+#define get_pack_length(length) ((length) >= 255 ? 3 : 1)
+#define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)
+
+/**
+ Sets table's trn and prints debug information
+ @param tbl MARIA_HA of table
+ @param newtrn what to put into tbl->trn
+ @note cast of newtrn is because %p of NULL gives warning (NULL is int)
+*/
+#define _ma_set_trn_for_table(tbl, newtrn) do { \
+ DBUG_PRINT("info",("table: %p trn: %p -> %p", \
+ (tbl), (tbl)->trn, (void *)(newtrn))); \
+ (tbl)->trn= (newtrn); \
+ } while (0)
+
+
+#define MARIA_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
+/* Don't use to small record-blocks */
+#define MARIA_EXTEND_BLOCK_LENGTH 20
+#define MARIA_SPLIT_LENGTH ((MARIA_EXTEND_BLOCK_LENGTH+4)*2)
+ /* Max prefix of record-block */
+#define MARIA_MAX_DYN_BLOCK_HEADER 20
+#define MARIA_BLOCK_INFO_HEADER_LENGTH 20
+#define MARIA_DYN_DELETE_BLOCK_HEADER 20 /* length of delete-block-header */
+#define MARIA_DYN_MAX_BLOCK_LENGTH ((1L << 24)-4L)
+#define MARIA_DYN_MAX_ROW_LENGTH (MARIA_DYN_MAX_BLOCK_LENGTH - MARIA_SPLIT_LENGTH)
+#define MARIA_DYN_ALIGN_SIZE 4 /* Align blocks on this */
+#define MARIA_MAX_DYN_HEADER_BYTE 13 /* max header uchar for dynamic rows */
+#define MARIA_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MARIA_DYN_ALIGN_SIZE-1)))
+#define MARIA_REC_BUFF_OFFSET ALIGN_SIZE(MARIA_DYN_DELETE_BLOCK_HEADER+sizeof(uint32))
+
+#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
+
+#define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */
+#define PACK_TYPE_SPACE_FIELDS 2
+#define PACK_TYPE_ZERO_FILL 4
+#define MARIA_FOUND_WRONG_KEY 32738 /* Impossible value from ha_key_cmp */
+
+#define MARIA_BLOCK_SIZE(key_length,data_pointer,key_pointer,block_size) (((((key_length)+(data_pointer)+(key_pointer))*4+(key_pointer)+2)/(block_size)+1)*(block_size))
+#define MARIA_MAX_KEYPTR_SIZE 5 /* For calculating block lengths */
+
+/* Marker for impossible delete link */
+#define IMPOSSIBLE_PAGE_NO LL(0xFFFFFFFFFF)
+
+/* The UNIQUE check is done with a hashed long key */
+
+#define MARIA_UNIQUE_HASH_TYPE HA_KEYTYPE_ULONG_INT
+#define maria_unique_store(A,B) mi_int4store((A),(B))
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_maria;
+#endif
+#if !defined(THREAD) || defined(DONT_USE_RW_LOCKS)
+#define rw_wrlock(A) {}
+#define rw_rdlock(A) {}
+#define rw_unlock(A) {}
+#endif
+
+/* Some tuning parameters */
+#define MARIA_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */
+#define MARIA_MIN_SIZE_BULK_INSERT_TREE 16384 /* this is per key */
+#define MARIA_MIN_ROWS_TO_USE_BULK_INSERT 100
+#define MARIA_MIN_ROWS_TO_DISABLE_INDEXES 100
+#define MARIA_MIN_ROWS_TO_USE_WRITE_CACHE 10
+/* Keep a small buffer for tables only using small blobs */
+#define MARIA_SMALL_BLOB_BUFFER 1024
+#define MARIA_MAX_CONTROL_FILE_LOCK_RETRY 30 /* Retry this many times */
+
+
+/* Some extern variables */
+extern LIST *maria_open_list;
+extern uchar maria_file_magic[], maria_pack_file_magic[];
+extern uchar maria_uuid[MY_UUID_SIZE];
+extern uint32 maria_read_vec[], maria_readnext_vec[];
+extern uint maria_quick_table_bits;
+extern char *maria_data_root;
+extern uchar maria_zero_string[];
+extern my_bool maria_inited, maria_in_ha_maria;
+extern HASH maria_stored_state;
+
+/* This is used by _ma_calc_xxx_key_length och _ma_store_key */
+typedef struct st_maria_s_param
+{
+ const uchar *key;
+ uchar *prev_key, *next_key_pos;
+ uchar *key_pos; /* For balance page */
+ uint ref_length, key_length, n_ref_length;
+ uint n_length, totlength, part_of_prev_key, prev_length, pack_marker;
+ uint changed_length;
+ int move_length; /* For balance_page */
+ my_bool store_not_null;
+} MARIA_KEY_PARAM;
+
+
+/* Used to store reference to pinned page */
+typedef struct st_pinned_page
+{
+ PAGECACHE_BLOCK_LINK *link;
+ enum pagecache_page_lock unlock, write_lock;
+ my_bool changed;
+} MARIA_PINNED_PAGE;
+
+/* Prototypes for intern functions */
+extern int _ma_read_dynamic_record(MARIA_HA *, uchar *, MARIA_RECORD_POS);
+extern int _ma_read_rnd_dynamic_record(MARIA_HA *, uchar *, MARIA_RECORD_POS,
+ my_bool);
+extern my_bool _ma_write_dynamic_record(MARIA_HA *, const uchar *);
+extern my_bool _ma_update_dynamic_record(MARIA_HA *, MARIA_RECORD_POS,
+ const uchar *, const uchar *);
+extern my_bool _ma_delete_dynamic_record(MARIA_HA *info, const uchar *record);
+extern my_bool _ma_cmp_dynamic_record(MARIA_HA *info, const uchar *record);
+extern my_bool _ma_write_blob_record(MARIA_HA *, const uchar *);
+extern my_bool _ma_update_blob_record(MARIA_HA *, MARIA_RECORD_POS,
+ const uchar *, const uchar *);
+extern int _ma_read_static_record(MARIA_HA *info, uchar *, MARIA_RECORD_POS);
+extern int _ma_read_rnd_static_record(MARIA_HA *, uchar *, MARIA_RECORD_POS,
+ my_bool);
+extern my_bool _ma_write_static_record(MARIA_HA *, const uchar *);
+extern my_bool _ma_update_static_record(MARIA_HA *, MARIA_RECORD_POS,
+ const uchar *, const uchar *);
+extern my_bool _ma_delete_static_record(MARIA_HA *info, const uchar *record);
+extern my_bool _ma_cmp_static_record(MARIA_HA *info, const uchar *record);
+extern my_bool _ma_ck_write(MARIA_HA *info, MARIA_KEY *key);
+extern int _ma_enlarge_root(MARIA_HA *info, MARIA_KEY *key,
+ MARIA_RECORD_POS *root);
+extern int _ma_insert(MARIA_HA *info, MARIA_KEY *key, uchar *anc_buff,
+ uchar *key_pos, my_off_t anc_page, uchar *key_buff,
+ my_off_t father_page, uchar *father_buff,
+ MARIA_PINNED_PAGE *father_page_link,
+ uchar *father_key_pos, my_bool insert_last);
+extern int _ma_ck_real_write_btree(MARIA_HA *info, MARIA_KEY *key,
+ MARIA_RECORD_POS *root, uint32 comp_flag);
+extern int _ma_split_page(MARIA_HA *info, MARIA_KEY *key, my_off_t split_page,
+ uchar *split_buff, uint org_split_length,
+ uchar *inserted_key_pos, uint changed_length,
+ int move_length,
+ uchar *key_buff, my_bool insert_last_key);
+extern uchar *_ma_find_half_pos(MARIA_HA *info, MARIA_KEY *key, uint nod_flag,
+ uchar *page, uchar ** after_key);
+extern int _ma_calc_static_key_length(const MARIA_KEY *key, uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *key_buff,
+ MARIA_KEY_PARAM *s_temp);
+extern int _ma_calc_var_key_length(const MARIA_KEY *key, uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *key_buff,
+ MARIA_KEY_PARAM *s_temp);
+extern int _ma_calc_var_pack_key_length(const MARIA_KEY *key,
+ uint nod_flag, uchar *next_key,
+ uchar *org_key, uchar *prev_key,
+ MARIA_KEY_PARAM *s_temp);
+extern int _ma_calc_bin_pack_key_length(const MARIA_KEY *key,
+ uint nod_flag, uchar *next_key,
+ uchar *org_key, uchar *prev_key,
+ MARIA_KEY_PARAM *s_temp);
+extern void _ma_store_static_key(MARIA_KEYDEF *keyinfo, uchar *key_pos,
+ MARIA_KEY_PARAM *s_temp);
+extern void _ma_store_var_pack_key(MARIA_KEYDEF *keyinfo, uchar *key_pos,
+ MARIA_KEY_PARAM *s_temp);
+#ifdef NOT_USED
+extern void _ma_store_pack_key(MARIA_KEYDEF *keyinfo, uchar *key_pos,
+ MARIA_KEY_PARAM *s_temp);
+#endif
+extern void _ma_store_bin_pack_key(MARIA_KEYDEF *keyinfo, uchar *key_pos,
+ MARIA_KEY_PARAM *s_temp);
+
+extern int _ma_ck_delete(MARIA_HA *info, MARIA_KEY *key);
+extern int _ma_ck_real_delete(register MARIA_HA *info, MARIA_KEY *key,
+ my_off_t *root);
+extern int _ma_readinfo(MARIA_HA *info, int lock_flag, int check_keybuffer);
+extern int _ma_writeinfo(MARIA_HA *info, uint options);
+extern int _ma_test_if_changed(MARIA_HA *info);
+extern int _ma_mark_file_changed(MARIA_HA *info);
+extern void _ma_mark_file_crashed(MARIA_SHARE *share);
+extern my_bool _ma_set_uuid(MARIA_HA *info, my_bool reset_uuid);
+extern my_bool _ma_check_if_zero(uchar *pos, size_t size);
+extern int _ma_decrement_open_count(MARIA_HA *info);
+extern int _ma_check_index(MARIA_HA *info, int inx);
+extern int _ma_search(MARIA_HA *info, MARIA_KEY *key, uint32 nextflag,
+ my_off_t pos);
+extern int _ma_bin_search( const MARIA_KEY *key, uchar *page,
+ uint32 comp_flag, uchar **ret_pos, uchar *buff,
+ my_bool *was_last_key);
+extern int _ma_seq_search(const MARIA_KEY *key, uchar *page,
+ uint comp_flag, uchar ** ret_pos, uchar *buff,
+ my_bool *was_last_key);
+extern int _ma_prefix_search(const MARIA_KEY *key, uchar *page,
+ uint32 comp_flag, uchar ** ret_pos, uchar *buff,
+ my_bool *was_last_key);
+extern my_off_t _ma_kpos(uint nod_flag, const uchar *after_key);
+extern void _ma_kpointer(MARIA_HA *info, uchar *buff, my_off_t pos);
+MARIA_RECORD_POS _ma_row_pos_from_key(const MARIA_KEY *key);
+TrID _ma_trid_from_key(const MARIA_KEY *key);
+extern MARIA_RECORD_POS _ma_rec_pos(MARIA_SHARE *share, uchar *ptr);
+extern void _ma_dpointer(MARIA_SHARE *share, uchar *buff,
+ MARIA_RECORD_POS pos);
+extern uint _ma_get_static_key(MARIA_KEY *key, uint page_flag, uint nod_flag,
+ uchar **page);
+extern uchar *_ma_skip_static_key(MARIA_KEY *key, uint page_flag,
+ uint nod_flag, uchar *page);
+extern uint _ma_get_pack_key(MARIA_KEY *key, uint page_flag, uint nod_flag,
+ uchar **page);
+extern uchar *_ma_skip_pack_key(MARIA_KEY *key, uint page_flag,
+ uint nod_flag, uchar *page);
+extern uint _ma_get_binary_pack_key(MARIA_KEY *key, uint page_flag,
+ uint nod_flag, uchar **page_pos);
+uchar *_ma_skip_binary_pack_key(MARIA_KEY *key, uint page_flag,
+ uint nod_flag, uchar *page);
+extern uchar *_ma_get_last_key(MARIA_KEY *key, uchar *keypos, uchar *endpos);
+extern uchar *_ma_get_key(MARIA_KEY *key, uchar *page, uchar *keypos);
+extern uint _ma_keylength(MARIA_KEYDEF *keyinfo, const uchar *key);
+extern uint _ma_keylength_part(MARIA_KEYDEF *keyinfo, const uchar *key,
+ HA_KEYSEG *end);
+extern uchar *_qq_move_key(MARIA_KEYDEF *keyinfo, uchar *to,
+ const uchar *from);
+
+extern int _ma_search_next(MARIA_HA *info, MARIA_KEY *key,
+ uint32 nextflag, my_off_t pos);
+extern int _ma_search_first(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ my_off_t pos);
+extern int _ma_search_last(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ my_off_t pos);
+extern my_off_t _ma_static_keypos_to_recpos(MARIA_SHARE *share, my_off_t pos);
+extern my_off_t _ma_static_recpos_to_keypos(MARIA_SHARE *share, my_off_t pos);
+extern my_off_t _ma_transparent_recpos(MARIA_SHARE *share, my_off_t pos);
+extern my_off_t _ma_transaction_keypos_to_recpos(MARIA_SHARE *, my_off_t pos);
+extern my_off_t _ma_transaction_recpos_to_keypos(MARIA_SHARE *, my_off_t pos);
+
+extern uchar *_ma_fetch_keypage(MARIA_HA *info,
+ const MARIA_KEYDEF *keyinfo,
+ my_off_t page, enum pagecache_page_lock lock,
+ int level, uchar *buff, int return_buffer,
+ MARIA_PINNED_PAGE **page_link);
+extern int _ma_write_keypage(MARIA_HA *info,
+ const MARIA_KEYDEF *keyinfo,
+ my_off_t page, enum pagecache_page_lock lock,
+ int level, uchar *buff);
+extern int _ma_dispose(MARIA_HA *info, my_off_t pos, my_bool page_not_read);
+extern my_off_t _ma_new(register MARIA_HA *info, int level,
+ MARIA_PINNED_PAGE **page_link);
+extern my_bool _ma_compact_keypage(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
+ my_off_t page_pos, uchar *page,
+ TrID min_read_from);
+extern uint transid_store_packed(MARIA_HA *info, uchar *to, ulonglong trid);
+extern ulonglong transid_get_packed(MARIA_SHARE *share, const uchar *from);
+#define transid_packed_length(data) \
+ ((data)[0] < MARIA_MIN_TRANSID_PACK_OFFSET ? 1 : \
+ (uint) ((uchar) (data)[0]) - (MARIA_TRANSID_PACK_OFFSET - 1))
+#define key_has_transid(key) (*(key) & 1)
+
+extern MARIA_KEY *_ma_make_key(MARIA_HA *info, MARIA_KEY *int_key, uint keynr,
+ uchar *key, const uchar *record,
+ MARIA_RECORD_POS filepos, ulonglong trid);
+extern MARIA_KEY *_ma_pack_key(MARIA_HA *info, MARIA_KEY *int_key,
+ uint keynr, uchar *key,
+ const uchar *old, key_part_map keypart_map,
+ HA_KEYSEG ** last_used_keyseg);
+extern void _ma_copy_key(MARIA_KEY *to, const MARIA_KEY *from);
+extern int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS);
+extern my_bool _ma_read_cache(IO_CACHE *info, uchar *buff,
+ MARIA_RECORD_POS pos, size_t length,
+ uint re_read_if_possibly);
+extern ulonglong ma_retrieve_auto_increment(const uchar *key, uint8 key_type);
+extern my_bool _ma_alloc_buffer(uchar **old_addr, size_t *old_size,
+ size_t new_size);
+extern ulong _ma_rec_unpack(MARIA_HA *info, uchar *to, uchar *from,
+ ulong reclength);
+extern my_bool _ma_rec_check(MARIA_HA *info, const uchar *record,
+ uchar *packpos, ulong packed_length,
+ my_bool with_checkum, ha_checksum checksum);
+extern int _ma_write_part_record(MARIA_HA *info, my_off_t filepos,
+ ulong length, my_off_t next_filepos,
+ uchar ** record, ulong *reclength,
+ int *flag);
+extern void _ma_print_key(FILE *stream, MARIA_KEY *key);
+extern void _ma_print_keydata(FILE *stream, HA_KEYSEG *keyseg,
+ const uchar *key, uint length);
+extern my_bool _ma_once_init_pack_row(MARIA_SHARE *share, File dfile);
+extern my_bool _ma_once_end_pack_row(MARIA_SHARE *share);
+extern int _ma_read_pack_record(MARIA_HA *info, uchar *buf,
+ MARIA_RECORD_POS filepos);
+extern int _ma_read_rnd_pack_record(MARIA_HA *, uchar *, MARIA_RECORD_POS,
+ my_bool);
+extern int _ma_pack_rec_unpack(MARIA_HA *info, MARIA_BIT_BUFF *bit_buff,
+ uchar *to, uchar *from, ulong reclength);
+extern ulonglong _ma_safe_mul(ulonglong a, ulonglong b);
+extern int _ma_ft_update(MARIA_HA *info, uint keynr, uchar *keybuf,
+ const uchar *oldrec, const uchar *newrec,
+ my_off_t pos);
+
+/*
+ Parameter to _ma_get_block_info
+ The dynamic row header is read into this struct. For an explanation of
+ the fields, look at the function _ma_get_block_info().
+*/
+
+typedef struct st_maria_block_info
+{
+ uchar header[MARIA_BLOCK_INFO_HEADER_LENGTH];
+ ulong rec_len;
+ ulong data_len;
+ ulong block_len;
+ ulong blob_len;
+ MARIA_RECORD_POS filepos;
+ MARIA_RECORD_POS next_filepos;
+ MARIA_RECORD_POS prev_filepos;
+ uint second_read;
+ uint offset;
+} MARIA_BLOCK_INFO;
+
+
+/* bits in return from _ma_get_block_info */
+
+#define BLOCK_FIRST 1
+#define BLOCK_LAST 2
+#define BLOCK_DELETED 4
+#define BLOCK_ERROR 8 /* Wrong data */
+#define BLOCK_SYNC_ERROR 16 /* Right data at wrong place */
+#define BLOCK_FATAL_ERROR 32 /* hardware-error */
+
+#define NEED_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
+#define MAXERR 20
+#define BUFFERS_WHEN_SORTING 16 /* Alloc for sort-key-tree */
+#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
+#define INDEX_TMP_EXT ".TMM"
+#define DATA_TMP_EXT ".TMD"
+
+#define UPDATE_TIME 1
+#define UPDATE_STAT 2
+#define UPDATE_SORT 4
+#define UPDATE_AUTO_INC 8
+#define UPDATE_OPEN_COUNT 16
+
+#define USE_BUFFER_INIT (((1024L*1024L*128-MALLOC_OVERHEAD)/8192)*8192)
+#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
+#define SORT_BUFFER_INIT (1024L*1024L*64-MALLOC_OVERHEAD)
+#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
+
+#define fast_ma_writeinfo(INFO) if (!(INFO)->s->tot_locks) (void) _ma_writeinfo((INFO),0)
+#define fast_ma_readinfo(INFO) ((INFO)->lock_type == F_UNLCK) && _ma_readinfo((INFO),F_RDLCK,1)
+
+extern uint _ma_get_block_info(MARIA_BLOCK_INFO *, File, my_off_t);
+extern uint _ma_rec_pack(MARIA_HA *info, uchar *to, const uchar *from);
+extern uint _ma_pack_get_block_info(MARIA_HA *maria, MARIA_BIT_BUFF *bit_buff,
+ MARIA_BLOCK_INFO *info, uchar **rec_buff_p,
+ size_t *rec_buff_size,
+ File file, my_off_t filepos);
+extern void _ma_store_blob_length(uchar *pos, uint pack_length, uint length);
+extern void _ma_report_error(int errcode, const LEX_STRING *file_name);
+extern my_bool _ma_memmap_file(MARIA_HA *info);
+extern void _ma_unmap_file(MARIA_HA *info);
+extern uint _ma_save_pack_length(uint version, uchar * block_buff,
+ ulong length);
+extern uint _ma_calc_pack_length(uint version, ulong length);
+extern ulong _ma_calc_blob_length(uint length, const uchar *pos);
+extern size_t _ma_mmap_pread(MARIA_HA *info, uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags);
+extern size_t _ma_mmap_pwrite(MARIA_HA *info, const uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags);
+extern size_t _ma_nommap_pread(MARIA_HA *info, uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags);
+extern size_t _ma_nommap_pwrite(MARIA_HA *info, const uchar *Buffer,
+ size_t Count, my_off_t offset, myf MyFlags);
+
+/* my_pwrite instead of my_write used */
+#define MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET 1
+/* info should be written */
+#define MA_STATE_INFO_WRITE_FULL_INFO 2
+/* intern_lock taking is needed */
+#define MA_STATE_INFO_WRITE_LOCK 4
+uint _ma_state_info_write(MARIA_SHARE *share, uint pWrite);
+uint _ma_state_info_write_sub(File file, MARIA_STATE_INFO *state, uint pWrite);
+uint _ma_state_info_read_dsk(File file, MARIA_STATE_INFO *state);
+uint _ma_base_info_write(File file, MARIA_BASE_INFO *base);
+my_bool _ma_keyseg_write(File file, const HA_KEYSEG *keyseg);
+uchar *_ma_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg);
+my_bool _ma_keydef_write(File file, MARIA_KEYDEF *keydef);
+uchar *_ma_keydef_read(uchar *ptr, MARIA_KEYDEF *keydef);
+my_bool _ma_uniquedef_write(File file, MARIA_UNIQUEDEF *keydef);
+uchar *_ma_uniquedef_read(uchar *ptr, MARIA_UNIQUEDEF *keydef);
+my_bool _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef);
+uchar *_ma_columndef_read(uchar *ptr, MARIA_COLUMNDEF *columndef);
+my_bool _ma_column_nr_write(File file, uint16 *offsets, uint columns);
+uchar *_ma_column_nr_read(uchar *ptr, uint16 *offsets, uint columns);
+ulong _ma_calc_total_blob_length(MARIA_HA *info, const uchar *record);
+ha_checksum _ma_checksum(MARIA_HA *info, const uchar *buf);
+ha_checksum _ma_static_checksum(MARIA_HA *info, const uchar *buf);
+my_bool _ma_check_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
+ uchar *record, ha_checksum unique_hash,
+ MARIA_RECORD_POS pos);
+ha_checksum _ma_unique_hash(MARIA_UNIQUEDEF *def, const uchar *buf);
+my_bool _ma_cmp_static_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
+ const uchar *record, MARIA_RECORD_POS pos);
+my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
+ const uchar *record, MARIA_RECORD_POS pos);
+my_bool _ma_unique_comp(MARIA_UNIQUEDEF *def, const uchar *a, const uchar *b,
+ my_bool null_are_equal);
+void _ma_get_status(void *param, my_bool concurrent_insert);
+void _ma_update_status(void *param);
+void _ma_restore_status(void *param);
+void _ma_copy_status(void *to, void *from);
+my_bool _ma_check_status(void *param);
+void _ma_restore_status(void *param);
+void _ma_reset_status(MARIA_HA *maria);
+int _ma_def_scan_remember_pos(MARIA_HA *info, MARIA_RECORD_POS *lastpos);
+void _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos);
+
+#include "ma_commit.h"
+
+extern MARIA_HA *_ma_test_if_reopen(const char *filename);
+my_bool _ma_check_table_is_closed(const char *name, const char *where);
+int _ma_open_datafile(MARIA_HA *info, MARIA_SHARE *share, const char *org_name,
+ File file_to_dup);
+int _ma_open_keyfile(MARIA_SHARE *share);
+void _ma_setup_functions(register MARIA_SHARE *share);
+my_bool _ma_dynmap_file(MARIA_HA *info, my_off_t size);
+void _ma_remap_file(MARIA_HA *info, my_off_t size);
+
+MARIA_RECORD_POS _ma_write_init_default(MARIA_HA *info, const uchar *record);
+my_bool _ma_write_abort_default(MARIA_HA *info);
+
+C_MODE_START
+#define MARIA_FLUSH_DATA 1
+#define MARIA_FLUSH_INDEX 2
+int _ma_flush_table_files(MARIA_HA *info, uint flush_data_or_index,
+ enum flush_type flush_type_for_data,
+ enum flush_type flush_type_for_index);
+/*
+ Functions needed by _ma_check (are overridden in MySQL/ha_maria.cc).
+ See ma_check_standalone.h .
+*/
+volatile int *_ma_killed_ptr(HA_CHECK *param);
+void _ma_check_print_error _VARARGS((HA_CHECK *param, const char *fmt, ...))
+ ATTRIBUTE_FORMAT(printf, 2, 3);
+void _ma_check_print_warning _VARARGS((HA_CHECK *param, const char *fmt, ...))
+ ATTRIBUTE_FORMAT(printf, 2, 3);
+void _ma_check_print_info _VARARGS((HA_CHECK *param, const char *fmt, ...))
+ ATTRIBUTE_FORMAT(printf, 2, 3);
+my_bool write_log_record_for_repair(const HA_CHECK *param, MARIA_HA *info);
+C_MODE_END
+
+int _ma_flush_pending_blocks(MARIA_SORT_PARAM *param);
+int _ma_sort_ft_buf_flush(MARIA_SORT_PARAM *sort_param);
+int _ma_thr_write_keys(MARIA_SORT_PARAM *sort_param);
+#ifdef THREAD
+pthread_handler_t _ma_thr_find_all_keys(void *arg);
+#endif
+
+int _ma_sort_write_record(MARIA_SORT_PARAM *sort_param);
+int _ma_create_index_by_sort(MARIA_SORT_PARAM *info, my_bool no_messages,
+ size_t);
+int _ma_sync_table_files(const MARIA_HA *info);
+int _ma_initialize_data_file(MARIA_SHARE *share, File dfile);
+int _ma_update_state_lsns(MARIA_SHARE *share,
+ LSN lsn, TrID create_trid, my_bool do_sync,
+ my_bool update_create_rename_lsn);
+int _ma_update_state_lsns_sub(MARIA_SHARE *share, LSN lsn,
+ TrID create_trid, my_bool do_sync,
+ my_bool update_create_rename_lsn);
+void _ma_set_data_pagecache_callbacks(PAGECACHE_FILE *file,
+ MARIA_SHARE *share);
+void _ma_set_index_pagecache_callbacks(PAGECACHE_FILE *file,
+ MARIA_SHARE *share);
+void _ma_tmp_disable_logging_for_table(MARIA_HA *info,
+ my_bool log_incomplete);
+my_bool _ma_reenable_logging_for_table(MARIA_HA *info, my_bool flush_pages);
+my_bool write_log_record_for_bulk_insert(MARIA_HA *info);
+
+
+#define MARIA_NO_CRC_NORMAL_PAGE 0xffffffff
+#define MARIA_NO_CRC_BITMAP_PAGE 0xfffffffe
+extern my_bool maria_page_crc_set_index(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_crc_set_normal(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_crc_check_bitmap(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_crc_check_data(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_crc_check_index(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_crc_check_none(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_filler_set_bitmap(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_filler_set_normal(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_page_filler_set_none(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern void maria_page_write_failure(uchar* data_ptr);
+extern my_bool maria_flush_log_for_page(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+extern my_bool maria_flush_log_for_page_none(uchar *page,
+ pgcache_page_no_t page_no,
+ uchar *data_ptr);
+void maria_concurrent_inserts(MARIA_HA *info, my_bool concurrent_insert);
+extern PAGECACHE *maria_log_pagecache;
diff --git a/storage/maria/maria_ftdump.c b/storage/maria/maria_ftdump.c
new file mode 100644
index 00000000000..5e3b47b956e
--- /dev/null
+++ b/storage/maria/maria_ftdump.c
@@ -0,0 +1,280 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code
+ added support for long options (my_getopt) 22.5.2002 by Jani Tolonen */
+
+#include "ma_ftdefs.h"
+#include <my_getopt.h>
+
+static void usage();
+static void complain(int val);
+static my_bool get_one_option(int, const struct my_option *, char *);
+
+static int count=0, stats=0, dump=0, lstats=0;
+static my_bool verbose;
+static char *query=NULL;
+static uint lengths[256];
+
+#define MAX_LEN (HA_FT_MAXBYTELEN+10)
+#define HOW_OFTEN_TO_WRITE 10000
+
+static struct my_option my_long_options[] =
+{
+ {"help", 'h', "Display help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"help", '?', "Synonym for -h.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"count", 'c', "Calculate per-word stats (counts and global weights).",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"dump", 'd', "Dump index (incl. data offsets and word weights).",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"length", 'l', "Report length distribution.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"stats", 's', "Report global stats.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"verbose", 'v', "Be verbose.",
+ (uchar**) &verbose, (uchar**) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+int main(int argc,char *argv[])
+{
+ int error=0, subkeys;
+ uint keylen, keylen2=0, inx, doc_cnt=0;
+ float weight= 1.0;
+ double gws, min_gws=0, avg_gws=0;
+ MARIA_HA *info;
+ char buf[MAX_LEN], buf2[MAX_LEN], buf_maxlen[MAX_LEN], buf_min_gws[MAX_LEN];
+ ulong total=0, maxlen=0, uniq=0, max_doc_cnt=0;
+ struct { MARIA_HA *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */
+
+ MY_INIT(argv[0]);
+ if ((error= handle_options(&argc, &argv, my_long_options, get_one_option)))
+ exit(error);
+ maria_init();
+ if (count || dump)
+ verbose=0;
+ if (!count && !dump && !lstats && !query)
+ stats=1;
+
+ if (verbose)
+ setbuf(stdout,NULL);
+
+ if (argc < 2)
+ usage();
+
+ {
+ char *end;
+ inx= (uint) strtoll(argv[1], &end, 10);
+ if (*end)
+ usage();
+ }
+
+ init_pagecache(maria_pagecache, USE_BUFFER_INIT, 0, 0,
+ MARIA_KEY_BLOCK_LENGTH, MY_WME);
+
+ if (!(info=maria_open(argv[0], O_RDONLY,
+ HA_OPEN_ABORT_IF_LOCKED|HA_OPEN_FROM_SQL_LAYER)))
+ {
+ error=my_errno;
+ goto err;
+ }
+
+ *buf2=0;
+ aio->info=info;
+
+ if ((inx >= info->s->base.keys) ||
+ !(info->s->keyinfo[inx].flag & HA_FULLTEXT))
+ {
+ printf("Key %d in table %s is not a FULLTEXT key\n", inx,
+ info->s->open_file_name.str);
+ goto err;
+ }
+
+ maria_lock_database(info, F_EXTRA_LCK);
+
+ info->cur_row.lastpos= HA_OFFSET_ERROR;
+ info->update|= HA_STATE_PREV_FOUND;
+
+ while (!(error=maria_rnext(info,NULL,inx)))
+ {
+ keylen=*(info->lastkey_buff);
+
+ subkeys=ft_sintXkorr(info->lastkey_buff + keylen + 1);
+ if (subkeys >= 0)
+ weight=*(float*)&subkeys;
+
+#ifdef HAVE_SNPRINTF
+ snprintf(buf,MAX_LEN,"%.*s",(int) keylen,info->lastkey_buff+1);
+#else
+ sprintf(buf,"%.*s",(int) keylen,info->lastkey_buff+1);
+#endif
+ my_casedn_str(default_charset_info,buf);
+ total++;
+ lengths[keylen]++;
+
+ if (count || stats)
+ {
+ if (strcmp(buf, buf2))
+ {
+ if (*buf2)
+ {
+ uniq++;
+ avg_gws+=gws=GWS_IN_USE;
+ if (count)
+ printf("%9u %20.7f %s\n",doc_cnt,gws,buf2);
+ if (maxlen<keylen2)
+ {
+ maxlen=keylen2;
+ strmov(buf_maxlen, buf2);
+ }
+ if (max_doc_cnt < doc_cnt)
+ {
+ max_doc_cnt=doc_cnt;
+ strmov(buf_min_gws, buf2);
+ min_gws=gws;
+ }
+ }
+ strmov(buf2, buf);
+ keylen2=keylen;
+ doc_cnt=0;
+ }
+ doc_cnt+= (subkeys >= 0 ? 1 : -subkeys);
+ }
+ if (dump)
+ {
+ if (subkeys>=0)
+ printf("%9lx %20.7f %s\n", (long) info->cur_row.lastpos,weight,buf);
+ else
+ printf("%9lx => %17d %s\n",(long) info->cur_row.lastpos,-subkeys,buf);
+ }
+ if (verbose && (total%HOW_OFTEN_TO_WRITE)==0)
+ printf("%10ld\r",total);
+ }
+ maria_lock_database(info, F_UNLCK);
+
+ if (count || stats)
+ {
+ if (*buf2)
+ {
+ uniq++;
+ avg_gws+=gws=GWS_IN_USE;
+ if (count)
+ printf("%9u %20.7f %s\n",doc_cnt,gws,buf2);
+ if (maxlen<keylen2)
+ {
+ maxlen=keylen2;
+ strmov(buf_maxlen, buf2);
+ }
+ if (max_doc_cnt < doc_cnt)
+ {
+ max_doc_cnt=doc_cnt;
+ strmov(buf_min_gws, buf2);
+ min_gws=gws;
+ }
+ }
+ }
+
+ if (stats)
+ {
+ count=0;
+ for (inx=0;inx<256;inx++)
+ {
+ count+=lengths[inx];
+ if ((ulong) count >= total/2)
+ break;
+ }
+ printf("Total rows: %lu\nTotal words: %lu\n"
+ "Unique words: %lu\nLongest word: %lu chars (%s)\n"
+ "Median length: %u\n"
+ "Average global weight: %f\n"
+ "Most common word: %lu times, weight: %f (%s)\n",
+ (long) info->state->records, total, uniq, maxlen, buf_maxlen,
+ inx, avg_gws/uniq, max_doc_cnt, min_gws, buf_min_gws);
+ }
+ if (lstats)
+ {
+ count=0;
+ for (inx=0; inx<256; inx++)
+ {
+ count+=lengths[inx];
+ if (count && lengths[inx])
+ printf("%3u: %10lu %5.2f%% %20lu %4.1f%%\n", inx,
+ (ulong) lengths[inx],100.0*lengths[inx]/total,(ulong) count,
+ 100.0*count/total);
+ }
+ }
+
+err:
+ if (error && error != HA_ERR_END_OF_FILE)
+ printf("got error %d\n",my_errno);
+ if (info)
+ maria_close(info);
+ maria_end();
+ return 0;
+}
+
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch(optid) {
+ case 'd':
+ dump=1;
+ complain(count || query);
+ break;
+ case 's':
+ stats=1;
+ complain(query!=0);
+ break;
+ case 'c':
+ count= 1;
+ complain(dump || query);
+ break;
+ case 'l':
+ lstats=1;
+ complain(query!=0);
+ break;
+ case '?':
+ case 'h':
+ usage();
+ }
+ return 0;
+}
+
+#include <help_start.h>
+
+static void usage()
+{
+ printf("Use: maria_ft_dump <table_name> <index_num>\n");
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+ NETWARE_SET_SCREEN_MODE(1);
+ exit(1);
+}
+
+#include <help_end.h>
+
+static void complain(int val) /* Kinda assert :-) */
+{
+ if (val)
+ {
+ printf("You cannot use these options together!\n");
+ exit(1);
+ }
+}
diff --git a/storage/maria/maria_pack.c b/storage/maria/maria_pack.c
new file mode 100644
index 00000000000..234ac61c08d
--- /dev/null
+++ b/storage/maria/maria_pack.c
@@ -0,0 +1,3243 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Pack MARIA file */
+
+#ifndef USE_MY_FUNC
+#define USE_MY_FUNC /* We need at least my_malloc */
+#endif
+
+#include "maria_def.h"
+#include <queues.h>
+#include <my_tree.h>
+#include "mysys_err.h"
+#ifdef MSDOS
+#include <io.h>
+#endif
+#ifndef __GNU_LIBRARY__
+#define __GNU_LIBRARY__ /* Skip warnings in getopt.h */
+#endif
+#include <my_getopt.h>
+#include <assert.h>
+
+#if SIZEOF_LONG_LONG > 4
+#define BITS_SAVED 64
+#else
+#define BITS_SAVED 32
+#endif
+
+#define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */
+#define HEAD_LENGTH 32
+#define ALLOWED_JOIN_DIFF 256 /* Diff allowed to join trees */
+
+#define DATA_TMP_EXT ".TMD"
+#define OLD_EXT ".OLD"
+#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
+
+struct st_file_buffer {
+ File file;
+ uchar *buffer,*pos,*end;
+ my_off_t pos_in_file;
+ int bits;
+ ulonglong bitbucket;
+};
+
+struct st_huff_tree;
+struct st_huff_element;
+
+typedef struct st_huff_counts {
+ uint field_length,max_zero_fill;
+ uint pack_type;
+ uint max_end_space,max_pre_space,length_bits,min_space;
+ ulong max_length;
+ enum en_fieldtype field_type;
+ struct st_huff_tree *tree; /* Tree for field */
+ my_off_t counts[256];
+ my_off_t end_space[8];
+ my_off_t pre_space[8];
+ my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed;
+ TREE int_tree; /* Tree for detecting distinct column values. */
+ uchar *tree_buff; /* Column values, 'field_length' each. */
+ uchar *tree_pos; /* Points to end of column values in 'tree_buff'. */
+} HUFF_COUNTS;
+
+typedef struct st_huff_element HUFF_ELEMENT;
+
+/*
+ WARNING: It is crucial for the optimizations in calc_packed_length()
+ that 'count' is the first element of 'HUFF_ELEMENT'.
+*/
+struct st_huff_element {
+ my_off_t count;
+ union un_element {
+ struct st_nod {
+ HUFF_ELEMENT *left,*right;
+ } nod;
+ struct st_leaf {
+ HUFF_ELEMENT *null;
+ uint element_nr; /* Number of element */
+ } leaf;
+ } a;
+};
+
+
+typedef struct st_huff_tree {
+ HUFF_ELEMENT *root,*element_buffer;
+ HUFF_COUNTS *counts;
+ uint tree_number;
+ uint elements;
+ my_off_t bytes_packed;
+ uint tree_pack_length;
+ uint min_chr,max_chr,char_bits,offset_bits,max_offset,height;
+ ulonglong *code;
+ uchar *code_len;
+} HUFF_TREE;
+
+
+typedef struct st_isam_mrg {
+ MARIA_HA **file,**current,**end;
+ uint free_file;
+ uint count;
+ uint min_pack_length; /* Theese is used by packed data */
+ uint max_pack_length;
+ uint ref_length;
+ uint max_blob_length;
+ my_off_t records;
+ /* true if at least one source file has at least one disabled index */
+ my_bool src_file_has_indexes_disabled;
+} PACK_MRG_INFO;
+
+
+extern int main(int argc,char * *argv);
+static void get_options(int *argc,char ***argv);
+static MARIA_HA *open_maria_file(char *name,int mode);
+static my_bool open_maria_files(PACK_MRG_INFO *mrg,char **names,uint count);
+static int compress(PACK_MRG_INFO *file,char *join_name);
+static HUFF_COUNTS *init_huff_count(MARIA_HA *info,my_off_t records);
+static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees,
+ uint trees,
+ HUFF_COUNTS *huff_counts,
+ uint fields);
+static int compare_tree(void* cmp_arg __attribute__((unused)),
+ const uchar *s,const uchar *t);
+static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts);
+static void check_counts(HUFF_COUNTS *huff_counts,uint trees,
+ my_off_t records);
+static int test_space_compress(HUFF_COUNTS *huff_counts,my_off_t records,
+ uint max_space_length,my_off_t *space_counts,
+ my_off_t tot_space_count,
+ enum en_fieldtype field_type);
+static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts,uint trees);
+static int make_huff_tree(HUFF_TREE *tree,HUFF_COUNTS *huff_counts);
+static int compare_huff_elements(void *not_used, uchar *a,uchar *b);
+static int save_counts_in_queue(uchar *key,element_count count,
+ HUFF_TREE *tree);
+static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,uint flag);
+static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees);
+static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees);
+static void make_traverse_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,uint size,
+ ulonglong code);
+static int write_header(PACK_MRG_INFO *isam_file, uint header_length,uint trees,
+ my_off_t tot_elements,my_off_t filelength);
+static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees);
+static my_off_t write_huff_tree(HUFF_TREE *huff_tree,uint trees);
+static uint *make_offset_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,
+ uint *offset);
+static uint max_bit(uint value);
+static int compress_maria_file(PACK_MRG_INFO *file,HUFF_COUNTS *huff_counts);
+static char *make_new_name(char *new_name,char *old_name);
+static char *make_old_name(char *new_name,char *old_name);
+static void init_file_buffer(File file,pbool read_buffer);
+static int flush_buffer(ulong neaded_length);
+static void end_file_buffer(void);
+static void write_bits(ulonglong value, uint bits);
+static void flush_bits(void);
+static int save_state(MARIA_HA *isam_file,PACK_MRG_INFO *mrg,
+ my_off_t new_length, ha_checksum crc);
+static int save_state_mrg(File file,PACK_MRG_INFO *isam_file,
+ my_off_t new_length, ha_checksum crc);
+static int mrg_close(PACK_MRG_INFO *mrg);
+static int mrg_rrnd(PACK_MRG_INFO *info,uchar *buf);
+static void mrg_reset(PACK_MRG_INFO *mrg);
+#if !defined(DBUG_OFF)
+static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count);
+static int fakecmp(my_off_t **count1, my_off_t **count2);
+#endif
+
+
+static int error_on_write=0,test_only=0,verbose=0,silent=0,
+ write_loop=0,force_pack=0, isamchk_neaded=0;
+static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL;
+static my_bool backup, opt_wait;
+/*
+ tree_buff_length is somewhat arbitrary. The bigger it is the better
+ the chance to win in terms of compression factor. On the other hand,
+ this table becomes part of the compressed file header. And its length
+ is coded with 16 bits in the header. Hence the limit is 2**16 - 1.
+*/
+static uint tree_buff_length= 65536 - MALLOC_OVERHEAD;
+static char tmp_dir[FN_REFLEN]={0},*join_table;
+static my_off_t intervall_length;
+static ha_checksum glob_crc;
+static struct st_file_buffer file_buffer;
+static QUEUE queue;
+static HUFF_COUNTS *global_count;
+static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static const char *load_default_groups[]= { "mariapack",0 };
+
+ /* The main program */
+
+int main(int argc, char **argv)
+{
+ int error,ok;
+ PACK_MRG_INFO merge;
+ char **default_argv;
+ MY_INIT(argv[0]);
+
+ load_defaults("my",load_default_groups,&argc,&argv);
+ default_argv= argv;
+ get_options(&argc,&argv);
+ maria_init();
+
+ error=ok=isamchk_neaded=0;
+ if (join_table)
+ { /* Join files into one */
+ if (open_maria_files(&merge,argv,(uint) argc) ||
+ compress(&merge,join_table))
+ error=1;
+ }
+ else while (argc--)
+ {
+ MARIA_HA *isam_file;
+ if (!(isam_file=open_maria_file(*argv++,O_RDWR)))
+ error=1;
+ else
+ {
+ merge.file= &isam_file;
+ merge.current=0;
+ merge.free_file=0;
+ merge.count=1;
+ if (compress(&merge,0))
+ error=1;
+ else
+ ok=1;
+ }
+ }
+ if (ok && isamchk_neaded && !silent)
+ puts("Remember to run maria_chk -rq on compressed tables");
+ VOID(fflush(stdout));
+ VOID(fflush(stderr));
+ free_defaults(default_argv);
+ maria_end();
+ my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR);
+ exit(error ? 2 : 0);
+#ifndef _lint
+ return 0; /* No compiler warning */
+#endif
+}
+
+enum options_mp {OPT_CHARSETS_DIR_MP=256, OPT_AUTO_CLOSE};
+
+static struct my_option my_long_options[] =
+{
+#ifdef __NETWARE__
+ {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"backup", 'b', "Make a backup of the table as table_name.OLD.",
+ (uchar**) &backup, (uchar**) &backup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"character-sets-dir", OPT_CHARSETS_DIR_MP,
+ "Directory where character sets are.", (uchar**) &charsets_dir,
+ (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"force", 'f',
+ "Force packing of table even if it gets bigger or if tempfile exists.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"join", 'j',
+ "Join all given tables into 'new_table_name'. All tables MUST have identical layouts.",
+ (uchar**) &join_table, (uchar**) &join_table, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
+ 0, 0, 0},
+ {"help", '?', "Display this help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"silent", 's', "Be more silent.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"tmpdir", 'T', "Use temporary directory to store temporary table.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"test", 't', "Don't pack table, only test packing it.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"verbose", 'v', "Write info about progress and packing result. Use many -v for more verbosity!",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Output version information and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"wait", 'w', "Wait and retry if table is in use.", (uchar**) &opt_wait,
+ (uchar**) &opt_wait, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+#include <help_start.h>
+
+static void print_version(void)
+{
+ VOID(printf("%s Ver 1.0 for %s on %s\n",
+ my_progname, SYSTEM_TYPE, MACHINE_TYPE));
+ NETWARE_SET_SCREEN_MODE(1);
+}
+
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 2002 MySQL AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
+ puts("and you are welcome to modify and redistribute it under the GPL license\n");
+
+ puts("Pack a MARIA-table to take much less space.");
+ puts("Keys are not updated, you must run maria_chk -rq on the index (.MAI) file");
+ puts("afterwards to update the keys.");
+ puts("You should give the .MAI file as the filename argument.");
+ puts("To unpack a packed table, run maria_chk -u on the table");
+
+ VOID(printf("\nUsage: %s [OPTIONS] filename...\n", my_progname));
+ my_print_help(my_long_options);
+ print_defaults("my", load_default_groups);
+ my_print_variables(my_long_options);
+}
+
+#include <help_end.h>
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument)
+{
+ uint length;
+
+ switch(optid) {
+#ifdef __NETWARE__
+ case OPT_AUTO_CLOSE:
+ setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
+ break;
+#endif
+ case 'f':
+ force_pack= 1;
+ tmpfile_createflag= O_RDWR | O_TRUNC;
+ break;
+ case 's':
+ write_loop= verbose= 0;
+ silent= 1;
+ break;
+ case 't':
+ test_only= 1;
+ /* Avoid to reset 'verbose' if it was already set > 1. */
+ if (! verbose)
+ verbose= 1;
+ break;
+ case 'T':
+ length= (uint) (strmov(tmp_dir, argument) - tmp_dir);
+ if (length != dirname_length(tmp_dir))
+ {
+ tmp_dir[length]=FN_LIBCHAR;
+ tmp_dir[length+1]=0;
+ }
+ break;
+ case 'v':
+ verbose++; /* Allow for selecting the level of verbosity. */
+ silent= 0;
+ break;
+ case '#':
+ DBUG_PUSH(argument ? argument : "d:t:o,/tmp/maria_pack.trace");
+ break;
+ case 'V':
+ print_version();
+ exit(0);
+ case 'I':
+ case '?':
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+ /* reads options */
+ /* Initiates DEBUG - but no debugging here ! */
+
+static void get_options(int *argc,char ***argv)
+{
+ int ho_error;
+
+ my_progname= argv[0][0];
+ if (isatty(fileno(stdout)))
+ write_loop=1;
+
+ if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ if (!*argc)
+ {
+ usage();
+ exit(1);
+ }
+ if (join_table)
+ {
+ backup=0; /* Not needed */
+ tmp_dir[0]=0;
+ }
+ return;
+}
+
+
+static MARIA_HA *open_maria_file(char *name,int mode)
+{
+ MARIA_HA *isam_file;
+ MARIA_SHARE *share;
+ DBUG_ENTER("open_maria_file");
+
+ if (!(isam_file=maria_open(name, mode, HA_OPEN_IGNORE_MOVED_STATE |
+ (opt_wait ? HA_OPEN_WAIT_IF_LOCKED :
+ HA_OPEN_ABORT_IF_LOCKED))))
+ {
+ VOID(fprintf(stderr, "%s gave error %d on open\n", name, my_errno));
+ DBUG_RETURN(0);
+ }
+ share=isam_file->s;
+ if (share->options & HA_OPTION_COMPRESS_RECORD && !join_table)
+ {
+ if (!force_pack)
+ {
+ VOID(fprintf(stderr, "%s is already compressed\n", name));
+ VOID(maria_close(isam_file));
+ DBUG_RETURN(0);
+ }
+ if (verbose)
+ puts("Recompressing already compressed table");
+ share->options&= ~HA_OPTION_READ_ONLY_DATA; /* We are modifing it */
+ }
+ if (! force_pack && share->state.state.records != 0 &&
+ (share->state.state.records <= 1 ||
+ share->state.state.data_file_length < 1024))
+ {
+ VOID(fprintf(stderr, "%s is too small to compress\n", name));
+ VOID(maria_close(isam_file));
+ DBUG_RETURN(0);
+ }
+ VOID(maria_lock_database(isam_file,F_WRLCK));
+ maria_ignore_trids(isam_file);
+ DBUG_RETURN(isam_file);
+}
+
+
+static my_bool open_maria_files(PACK_MRG_INFO *mrg,char **names,uint count)
+{
+ uint i,j;
+ mrg->count=0;
+ mrg->current=0;
+ mrg->file=(MARIA_HA**) my_malloc(sizeof(MARIA_HA*)*count,MYF(MY_FAE));
+ mrg->free_file=1;
+ mrg->src_file_has_indexes_disabled= 0;
+ for (i=0; i < count ; i++)
+ {
+ if (!(mrg->file[i]=open_maria_file(names[i],O_RDONLY)))
+ goto error;
+
+ mrg->src_file_has_indexes_disabled|=
+ ! maria_is_all_keys_active(mrg->file[i]->s->state.key_map,
+ mrg->file[i]->s->base.keys);
+ }
+ /* Check that files are identical */
+ for (j=0 ; j < count-1 ; j++)
+ {
+ MARIA_COLUMNDEF *m1,*m2,*end;
+ if (mrg->file[j]->s->base.reclength != mrg->file[j+1]->s->base.reclength ||
+ mrg->file[j]->s->base.fields != mrg->file[j+1]->s->base.fields)
+ goto diff_file;
+ m1=mrg->file[j]->s->columndef;
+ end=m1+mrg->file[j]->s->base.fields;
+ m2=mrg->file[j+1]->s->columndef;
+ for ( ; m1 != end ; m1++,m2++)
+ {
+ if (m1->type != m2->type || m1->length != m2->length)
+ goto diff_file;
+ }
+ }
+ mrg->count=count;
+ return 0;
+
+ diff_file:
+ VOID(fprintf(stderr, "%s: Tables '%s' and '%s' are not identical\n",
+ my_progname, names[j], names[j+1]));
+ error:
+ while (i--)
+ maria_close(mrg->file[i]);
+ my_free((uchar*) mrg->file,MYF(0));
+ return 1;
+}
+
+
+static int compress(PACK_MRG_INFO *mrg,char *result_table)
+{
+ int error;
+ File new_file,join_maria_file;
+ MARIA_HA *isam_file;
+ MARIA_SHARE *share;
+ char org_name[FN_REFLEN],new_name[FN_REFLEN],temp_name[FN_REFLEN];
+ uint i,header_length,fields,trees,used_trees;
+ my_off_t old_length,new_length,tot_elements;
+ HUFF_COUNTS *huff_counts;
+ HUFF_TREE *huff_trees;
+ DBUG_ENTER("compress");
+
+ isam_file=mrg->file[0]; /* Take this as an example */
+ share=isam_file->s;
+ new_file=join_maria_file= -1;
+ trees=fields=0;
+ huff_trees=0;
+ huff_counts=0;
+ maria_block_size= isam_file->s->block_size;
+
+ /* Create temporary or join file */
+ if (backup)
+ VOID(fn_format(org_name,isam_file->s->open_file_name.str,
+ "",MARIA_NAME_DEXT, 2));
+ else
+ VOID(fn_format(org_name,isam_file->s->open_file_name.str,
+ "",MARIA_NAME_DEXT, 2+4+16));
+
+ if (init_pagecache(maria_pagecache, MARIA_MIN_PAGE_CACHE_SIZE, 0, 0,
+ maria_block_size, MY_WME) == 0)
+ {
+ fprintf(stderr, "Can't initialize page cache\n");
+ goto err;
+ }
+
+ if (!test_only && result_table)
+ {
+ /* Make a new indexfile based on first file in list */
+ uint length;
+ uchar *buff;
+ strmov(org_name,result_table); /* Fix error messages */
+ VOID(fn_format(new_name,result_table,"",MARIA_NAME_IEXT,2));
+ if ((join_maria_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME)))
+ < 0)
+ goto err;
+ length=(uint) share->base.keystart;
+ if (!(buff= (uchar*) my_malloc(length,MYF(MY_WME))))
+ goto err;
+ if (my_pread(share->kfile.file, buff, length, 0L, MYF(MY_WME | MY_NABP)) ||
+ my_write(join_maria_file,buff,length,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ my_free(buff,MYF(0));
+ goto err;
+ }
+ my_free(buff,MYF(0));
+ VOID(fn_format(new_name,result_table,"",MARIA_NAME_DEXT,2));
+ }
+ else if (!tmp_dir[0])
+ VOID(make_new_name(new_name,org_name));
+ else
+ VOID(fn_format(new_name,org_name,tmp_dir,DATA_TMP_EXT,1+2+4));
+ if (!test_only &&
+ (new_file=my_create(new_name,0,tmpfile_createflag,MYF(MY_WME))) < 0)
+ goto err;
+
+ /* Start calculating statistics */
+
+ mrg->records=0;
+ for (i=0 ; i < mrg->count ; i++)
+ mrg->records+=mrg->file[i]->s->state.state.records;
+
+ DBUG_PRINT("info", ("Compressing %s: (%lu records)",
+ result_table ? new_name : org_name,
+ (ulong) mrg->records));
+ if (write_loop || verbose)
+ {
+ VOID(printf("Compressing %s: (%lu records)\n",
+ result_table ? new_name : org_name, (ulong) mrg->records));
+ }
+ trees=fields=share->base.fields;
+ huff_counts=init_huff_count(isam_file,mrg->records);
+ QUICK_SAFEMALLOC;
+
+ /*
+ Read the whole data file(s) for statistics.
+ */
+ DBUG_PRINT("info", ("- Calculating statistics"));
+ if (write_loop || verbose)
+ VOID(printf("- Calculating statistics\n"));
+ if (get_statistic(mrg,huff_counts))
+ goto err;
+ NORMAL_SAFEMALLOC;
+ old_length=0;
+ for (i=0; i < mrg->count ; i++)
+ old_length+= (mrg->file[i]->s->state.state.data_file_length -
+ mrg->file[i]->s->state.state.empty);
+
+ /*
+ Create a global priority queue in preparation for making
+ temporary Huffman trees.
+ */
+ if (init_queue(&queue,256,0,0,compare_huff_elements,0))
+ goto err;
+
+ /*
+ Check each column if we should use pre-space-compress, end-space-
+ compress, empty-field-compress or zero-field-compress.
+ */
+ check_counts(huff_counts,fields,mrg->records);
+
+ /*
+ Build a Huffman tree for each column.
+ */
+ huff_trees=make_huff_trees(huff_counts,trees);
+
+ /*
+ If the packed lengths of combined columns is less then the sum of
+ the non-combined columns, then create common Huffman trees for them.
+ We do this only for uchar compressed columns, not for distinct values
+ compressed columns.
+ */
+ if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0)
+ goto err;
+
+ /*
+ Assign codes to all uchar or column values.
+ */
+ if (make_huff_decode_table(huff_trees,fields))
+ goto err;
+
+ /* Prepare a file buffer. */
+ init_file_buffer(new_file,0);
+
+ /*
+ Reserve space in the target file for the fixed compressed file header.
+ */
+ file_buffer.pos_in_file=HEAD_LENGTH;
+ if (! test_only)
+ VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0)));
+
+ /*
+ Write field infos: field type, pack type, length bits, tree number.
+ */
+ write_field_info(huff_counts,fields,used_trees);
+
+ /*
+ Write decode trees.
+ */
+ if (!(tot_elements=write_huff_tree(huff_trees,trees)))
+ goto err;
+
+ /*
+ Calculate the total length of the compression info header.
+ This includes the fixed compressed file header, the column compression
+ type descriptions, and the decode trees.
+ */
+ header_length=(uint) file_buffer.pos_in_file+
+ (uint) (file_buffer.pos-file_buffer.buffer);
+
+ /*
+ Compress the source file into the target file.
+ */
+ DBUG_PRINT("info", ("- Compressing file"));
+ if (write_loop || verbose)
+ VOID(printf("- Compressing file\n"));
+ error=compress_maria_file(mrg,huff_counts);
+ new_length=file_buffer.pos_in_file;
+ if (!error && !test_only)
+ {
+ uchar buff[MEMMAP_EXTRA_MARGIN]; /* End marginal for memmap */
+ bzero(buff,sizeof(buff));
+ error=my_write(file_buffer.file,buff,sizeof(buff),
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
+ }
+
+ /*
+ Write the fixed compressed file header.
+ */
+ if (!error)
+ error=write_header(mrg,header_length,used_trees,tot_elements,
+ new_length);
+
+ /* Flush the file buffer. */
+ end_file_buffer();
+
+ /* Display statistics. */
+ DBUG_PRINT("info", ("Min record length: %6d Max length: %6d "
+ "Mean total length: %6ld",
+ mrg->min_pack_length, mrg->max_pack_length,
+ (ulong) (mrg->records ? (new_length/mrg->records) : 0)));
+ if (verbose && mrg->records)
+ VOID(printf("Min record length: %6d Max length: %6d "
+ "Mean total length: %6ld\n", mrg->min_pack_length,
+ mrg->max_pack_length, (ulong) (new_length/mrg->records)));
+
+ /* Close source and target file. */
+ if (!test_only)
+ {
+ error|=my_close(new_file,MYF(MY_WME));
+ if (!result_table)
+ {
+ error|=my_close(isam_file->dfile.file, MYF(MY_WME));
+ isam_file->dfile.file= -1; /* Tell maria_close file is closed */
+ isam_file->s->bitmap.file.file= -1;
+ }
+ }
+
+ /* Cleanup. */
+ free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
+ if (! test_only && ! error)
+ {
+ if (result_table)
+ {
+ error=save_state_mrg(join_maria_file,mrg,new_length,glob_crc);
+ }
+ else
+ {
+ if (backup)
+ {
+ if (my_rename(org_name,make_old_name(temp_name,
+ isam_file->s->open_file_name.str),
+ MYF(MY_WME)))
+ error=1;
+ else
+ {
+ if (tmp_dir[0])
+ error=my_copy(new_name,org_name,MYF(MY_WME));
+ else
+ error=my_rename(new_name,org_name,MYF(MY_WME));
+ if (!error)
+ {
+ VOID(my_copystat(temp_name,org_name,MYF(MY_COPYTIME)));
+ if (tmp_dir[0])
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
+ }
+ }
+ else
+ {
+ if (tmp_dir[0])
+ {
+ error=my_copy(new_name,org_name,
+ MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_COPYTIME));
+ if (!error)
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ }
+ else
+ error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
+ }
+ if (! error)
+ error=save_state(isam_file,mrg,new_length,glob_crc);
+ }
+ }
+ error|=mrg_close(mrg);
+ if (join_maria_file >= 0)
+ error|=my_close(join_maria_file,MYF(MY_WME));
+ if (error)
+ {
+ VOID(fprintf(stderr, "Aborting: %s is not compressed\n", org_name));
+ VOID(my_delete(new_name,MYF(MY_WME)));
+ DBUG_RETURN(-1);
+ }
+ if (write_loop || verbose)
+ {
+ if (old_length)
+ VOID(printf("%.4g%% \n",
+ (((longlong) (old_length - new_length)) * 100.0 /
+ (longlong) old_length)));
+ else
+ puts("Empty file saved in compressed format");
+ }
+ DBUG_RETURN(0);
+
+ err:
+ end_pagecache(maria_pagecache, 1);
+ free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields);
+ if (new_file >= 0)
+ VOID(my_close(new_file,MYF(0)));
+ if (join_maria_file >= 0)
+ VOID(my_close(join_maria_file,MYF(0)));
+ mrg_close(mrg);
+ VOID(fprintf(stderr, "Aborted: %s is not compressed\n", org_name));
+ DBUG_RETURN(-1);
+}
+
+ /* Init a huff_count-struct for each field and init it */
+
+static HUFF_COUNTS *init_huff_count(MARIA_HA *info,my_off_t records)
+{
+ reg2 uint i;
+ reg1 HUFF_COUNTS *count;
+ if ((count = (HUFF_COUNTS*) my_malloc(info->s->base.fields*
+ sizeof(HUFF_COUNTS),
+ MYF(MY_ZEROFILL | MY_WME))))
+ {
+ for (i=0 ; i < info->s->base.fields ; i++)
+ {
+ enum en_fieldtype type;
+ count[i].field_length=info->s->columndef[i].length;
+ type= count[i].field_type= (enum en_fieldtype) info->s->columndef[i].type;
+ if (type == FIELD_INTERVALL ||
+ type == FIELD_CONSTANT ||
+ type == FIELD_ZERO)
+ type = FIELD_NORMAL;
+ if (count[i].field_length <= 8 &&
+ (type == FIELD_NORMAL ||
+ type == FIELD_SKIP_ZERO))
+ count[i].max_zero_fill= count[i].field_length;
+ /*
+ For every column initialize a tree, which is used to detect distinct
+ column values. 'int_tree' works together with 'tree_buff' and
+ 'tree_pos'. It's keys are implemented by pointers into 'tree_buff'.
+ This is accomplished by '-1' as the element size.
+ */
+ init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0, NULL,
+ NULL);
+ if (records && type != FIELD_BLOB && type != FIELD_VARCHAR)
+ count[i].tree_pos=count[i].tree_buff =
+ my_malloc(count[i].field_length > 1 ? tree_buff_length : 2,
+ MYF(MY_WME));
+ }
+ }
+ return count;
+}
+
+
+ /* Free memory used by counts and trees */
+
+static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees,
+ HUFF_COUNTS *huff_counts,
+ uint fields)
+{
+ register uint i;
+
+ if (huff_trees)
+ {
+ for (i=0 ; i < trees ; i++)
+ {
+ if (huff_trees[i].element_buffer)
+ my_free((uchar*) huff_trees[i].element_buffer,MYF(0));
+ if (huff_trees[i].code)
+ my_free((uchar*) huff_trees[i].code,MYF(0));
+ }
+ my_free((uchar*) huff_trees,MYF(0));
+ }
+ if (huff_counts)
+ {
+ for (i=0 ; i < fields ; i++)
+ {
+ if (huff_counts[i].tree_buff)
+ {
+ my_free((uchar*) huff_counts[i].tree_buff,MYF(0));
+ delete_tree(&huff_counts[i].int_tree);
+ }
+ }
+ my_free((uchar*) huff_counts,MYF(0));
+ }
+ delete_queue(&queue); /* This is safe to free */
+ return;
+}
+
+ /* Read through old file and gather some statistics */
+
+static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts)
+{
+ int error;
+ uint length, null_bytes;
+ ulong reclength,max_blob_length;
+ uchar *record,*pos,*next_pos,*end_pos,*start_pos;
+ ha_rows record_count;
+ HUFF_COUNTS *count,*end_count;
+ TREE_ELEMENT *element;
+ ha_checksum(*calc_checksum)(MARIA_HA *, const uchar *);
+ DBUG_ENTER("get_statistic");
+
+ reclength= mrg->file[0]->s->base.reclength;
+ null_bytes= mrg->file[0]->s->base.null_bytes;
+ record=(uchar*) my_alloca(reclength);
+ end_count=huff_counts+mrg->file[0]->s->base.fields;
+ record_count=0; glob_crc=0;
+ max_blob_length=0;
+
+ /* Check how to calculate checksum */
+ if (mrg->file[0]->s->data_file_type == STATIC_RECORD)
+ calc_checksum= _ma_static_checksum;
+ else
+ calc_checksum= _ma_checksum;
+
+ mrg_reset(mrg);
+ while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
+ {
+ ulong tot_blob_length=0;
+ if (! error)
+ {
+ /* glob_crc is a checksum over all bytes of all records. */
+ glob_crc+= (*calc_checksum)(mrg->file[0],record);
+
+ /* Count the incidence of values separately for every column. */
+ for (pos=record + null_bytes, count=huff_counts ;
+ count < end_count ;
+ count++,
+ pos=next_pos)
+ {
+ next_pos=end_pos=(start_pos=pos)+count->field_length;
+
+ /*
+ Put the whole column value in a tree if there is room for it.
+ 'int_tree' is used to quickly check for duplicate values.
+ 'tree_buff' collects as many distinct column values as
+ possible. If the field length is > 1, it is tree_buff_length,
+ else 2 bytes. Each value is 'field_length' bytes big. If there
+ are more distinct column values than fit into the buffer, we
+ give up with this tree. BLOBs and VARCHARs do not have a
+ tree_buff as it can only be used with fixed length columns.
+ For the special case of field length == 1, we handle only the
+ case that there is only one distinct value in the table(s).
+ Otherwise, we can have a maximum of 256 distinct values. This
+ is then handled by the normal Huffman tree build.
+
+ Another limit for collecting distinct column values is the
+ number of values itself. Since we would need to build a
+ Huffman tree for the values, we are limited by the 'IS_OFFSET'
+ constant. This constant expresses a bit which is used to
+ determine if a tree element holds a final value or an offset
+ to a child element. Hence, all values and offsets need to be
+ smaller than 'IS_OFFSET'. A tree element is implemented with
+ two integer values, one for the left branch and one for the
+ right branch. For the extreme case that the first element
+ points to the last element, the number of integers in the tree
+ must be less or equal to IS_OFFSET. So the number of elements
+ must be less or equal to IS_OFFSET / 2.
+
+ WARNING: At first, we insert a pointer into the record buffer
+ as the key for the tree. If we got a new distinct value, which
+ is really inserted into the tree, instead of being counted
+ only, we will copy the column value from the record buffer to
+ 'tree_buff' and adjust the key pointer of the tree accordingly.
+ */
+ if (count->tree_buff)
+ {
+ global_count=count;
+ if (!(element=tree_insert(&count->int_tree,pos, 0,
+ count->int_tree.custom_arg)) ||
+ (element->count == 1 &&
+ (count->tree_buff + tree_buff_length <
+ count->tree_pos + count->field_length)) ||
+ (count->int_tree.elements_in_tree > IS_OFFSET / 2) ||
+ (count->field_length == 1 &&
+ count->int_tree.elements_in_tree > 1))
+ {
+ delete_tree(&count->int_tree);
+ my_free(count->tree_buff,MYF(0));
+ count->tree_buff=0;
+ }
+ else
+ {
+ /*
+ If tree_insert() succeeds, it either creates a new element
+ or increments the counter of an existing element.
+ */
+ if (element->count == 1)
+ {
+ /* Copy the new column value into 'tree_buff'. */
+ memcpy(count->tree_pos,pos,(size_t) count->field_length);
+ /* Adjust the key pointer in the tree. */
+ tree_set_pointer(element,count->tree_pos);
+ /* Point behind the last column value so far. */
+ count->tree_pos+=count->field_length;
+ }
+ }
+ }
+
+ /* Save character counters and space-counts and zero-field-counts */
+ if (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIP_ENDSPACE)
+ {
+ /* Ignore trailing space. */
+ for ( ; end_pos > pos ; end_pos--)
+ if (end_pos[-1] != ' ')
+ break;
+ /* Empty fields are just counted. Go to the next record. */
+ if (end_pos == pos)
+ {
+ count->empty_fields++;
+ count->max_zero_fill=0;
+ continue;
+ }
+ /*
+ Count the total of all trailing spaces and the number of
+ short trailing spaces. Remember the longest trailing space.
+ */
+ length= (uint) (next_pos-end_pos);
+ count->tot_end_space+=length;
+ if (length < 8)
+ count->end_space[length]++;
+ if (count->max_end_space < length)
+ count->max_end_space = length;
+ }
+
+ if (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIP_PRESPACE)
+ {
+ /* Ignore leading space. */
+ for (pos=start_pos; pos < end_pos ; pos++)
+ if (pos[0] != ' ')
+ break;
+ /* Empty fields are just counted. Go to the next record. */
+ if (end_pos == pos)
+ {
+ count->empty_fields++;
+ count->max_zero_fill=0;
+ continue;
+ }
+ /*
+ Count the total of all leading spaces and the number of
+ short leading spaces. Remember the longest leading space.
+ */
+ length= (uint) (pos-start_pos);
+ count->tot_pre_space+=length;
+ if (length < 8)
+ count->pre_space[length]++;
+ if (count->max_pre_space < length)
+ count->max_pre_space = length;
+ }
+
+ /* Calculate pos, end_pos, and max_length for variable length fields. */
+ if (count->field_type == FIELD_BLOB)
+ {
+ uint field_length=count->field_length -portable_sizeof_char_ptr;
+ ulong blob_length= _ma_calc_blob_length(field_length, start_pos);
+ memcpy_fixed((char*) &pos, start_pos+field_length,sizeof(char*));
+ end_pos=pos+blob_length;
+ tot_blob_length+=blob_length;
+ set_if_bigger(count->max_length,blob_length);
+ }
+ else if (count->field_type == FIELD_VARCHAR)
+ {
+ uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
+ length= (pack_length == 1 ? (uint) *(uchar*) start_pos :
+ uint2korr(start_pos));
+ pos= start_pos+pack_length;
+ end_pos= pos+length;
+ set_if_bigger(count->max_length,length);
+ }
+
+ /* Evaluate 'max_zero_fill' for short fields. */
+ if (count->field_length <= 8 &&
+ (count->field_type == FIELD_NORMAL ||
+ count->field_type == FIELD_SKIP_ZERO))
+ {
+ uint i;
+ /* Zero fields are just counted. Go to the next record. */
+ if (!memcmp((uchar*) start_pos,zero_string,count->field_length))
+ {
+ count->zero_fields++;
+ continue;
+ }
+ /*
+ max_zero_fill starts with field_length. It is decreased every
+ time a shorter "zero trailer" is found. It is set to zero when
+ an empty field is found (see above). This suggests that the
+ variable should be called 'min_zero_fill'.
+ */
+ for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ;
+ i++) ;
+ if (i < count->max_zero_fill)
+ count->max_zero_fill=i;
+ }
+
+ /* Ignore zero fields and check fields. */
+ if (count->field_type == FIELD_ZERO ||
+ count->field_type == FIELD_CHECK)
+ continue;
+
+ /*
+ Count the incidence of every uchar value in the
+ significant field value.
+ */
+ for ( ; pos < end_pos ; pos++)
+ count->counts[(uchar) *pos]++;
+
+ /* Step to next field. */
+ }
+
+ if (tot_blob_length > max_blob_length)
+ max_blob_length=tot_blob_length;
+ record_count++;
+ if (write_loop && record_count % WRITE_COUNT == 0)
+ {
+ VOID(printf("%lu\r", (ulong) record_count));
+ VOID(fflush(stdout));
+ }
+ }
+ else if (error != HA_ERR_RECORD_DELETED)
+ {
+ VOID(fprintf(stderr, "Got error %d while reading rows\n", error));
+ break;
+ }
+
+ /* Step to next record. */
+ }
+ if (write_loop)
+ {
+ VOID(printf(" \r"));
+ VOID(fflush(stdout));
+ }
+
+ /*
+ If --debug=d,fakebigcodes is set, fake the counts to get big Huffman
+ codes.
+ */
+ DBUG_EXECUTE_IF("fakebigcodes", fakebigcodes(huff_counts, end_count););
+
+ DBUG_PRINT("info", ("Found the following number of incidents "
+ "of the uchar codes:"));
+ if (verbose >= 2)
+ VOID(printf("Found the following number of incidents "
+ "of the uchar codes:\n"));
+ for (count= huff_counts ; count < end_count; count++)
+ {
+ uint idx;
+ my_off_t total_count;
+ char llbuf[32];
+
+ DBUG_PRINT("info", ("column: %3u", (uint) (count - huff_counts + 1)));
+ if (verbose >= 2)
+ VOID(printf("column: %3u\n", (uint) (count - huff_counts + 1)));
+ if (count->tree_buff)
+ {
+ DBUG_PRINT("info", ("number of distinct values: %u",
+ (uint) ((count->tree_pos - count->tree_buff) /
+ count->field_length)));
+ if (verbose >= 2)
+ VOID(printf("number of distinct values: %u\n",
+ (uint) ((count->tree_pos - count->tree_buff) /
+ count->field_length)));
+ }
+ total_count= 0;
+ for (idx= 0; idx < 256; idx++)
+ {
+ if (count->counts[idx])
+ {
+ total_count+= count->counts[idx];
+ DBUG_PRINT("info", ("counts[0x%02x]: %12s", idx,
+ llstr((longlong) count->counts[idx], llbuf)));
+ if (verbose >= 2)
+ VOID(printf("counts[0x%02x]: %12s\n", idx,
+ llstr((longlong) count->counts[idx], llbuf)));
+ }
+ }
+ DBUG_PRINT("info", ("total: %12s", llstr((longlong) total_count,
+ llbuf)));
+ if ((verbose >= 2) && total_count)
+ {
+ VOID(printf("total: %12s\n",
+ llstr((longlong) total_count, llbuf)));
+ }
+ }
+
+ mrg->records=record_count;
+ mrg->max_blob_length=max_blob_length;
+ my_afree((uchar*) record);
+ DBUG_RETURN(error != HA_ERR_END_OF_FILE);
+}
+
+static int compare_huff_elements(void *not_used __attribute__((unused)),
+ uchar *a, uchar *b)
+{
+ return *((my_off_t*) a) < *((my_off_t*) b) ? -1 :
+ (*((my_off_t*) a) == *((my_off_t*) b) ? 0 : 1);
+}
+
+ /* Check each tree if we should use pre-space-compress, end-space-
+ compress, empty-field-compress or zero-field-compress */
+
+static void check_counts(HUFF_COUNTS *huff_counts, uint trees,
+ my_off_t records)
+{
+ uint space_fields,fill_zero_fields,field_count[(int) FIELD_enum_val_count];
+ my_off_t old_length,new_length,length;
+ DBUG_ENTER("check_counts");
+
+ bzero((uchar*) field_count,sizeof(field_count));
+ space_fields=fill_zero_fields=0;
+
+ for (; trees-- ; huff_counts++)
+ {
+ if (huff_counts->field_type == FIELD_BLOB)
+ {
+ huff_counts->length_bits=max_bit(huff_counts->max_length);
+ goto found_pack;
+ }
+ else if (huff_counts->field_type == FIELD_VARCHAR)
+ {
+ huff_counts->length_bits=max_bit(huff_counts->max_length);
+ goto found_pack;
+ }
+ else if (huff_counts->field_type == FIELD_CHECK)
+ {
+ huff_counts->bytes_packed=0;
+ huff_counts->counts[0]=0;
+ goto found_pack;
+ }
+
+ huff_counts->field_type=FIELD_NORMAL;
+ huff_counts->pack_type=0;
+
+ /* Check for zero-filled records (in this column), or zero records. */
+ if (huff_counts->zero_fields || ! records)
+ {
+ my_off_t old_space_count;
+ /*
+ If there are only zero filled records (in this column),
+ or no records at all, we are done.
+ */
+ if (huff_counts->zero_fields == records)
+ {
+ huff_counts->field_type= FIELD_ZERO;
+ huff_counts->bytes_packed=0;
+ huff_counts->counts[0]=0;
+ goto found_pack;
+ }
+ /* Remeber the number of significant spaces. */
+ old_space_count=huff_counts->counts[' '];
+ /* Add all leading and trailing spaces. */
+ huff_counts->counts[' ']+= (huff_counts->tot_end_space +
+ huff_counts->tot_pre_space +
+ huff_counts->empty_fields *
+ huff_counts->field_length);
+ /* Check, what the compressed length of this would be. */
+ old_length=calc_packed_length(huff_counts,0)+records/8;
+ /* Get the number of zero bytes. */
+ length=huff_counts->zero_fields*huff_counts->field_length;
+ /* Add it to the counts. */
+ huff_counts->counts[0]+=length;
+ /* Check, what the compressed length of this would be. */
+ new_length=calc_packed_length(huff_counts,0);
+ /* If the compression without the zeroes would be shorter, we are done. */
+ if (old_length < new_length && huff_counts->field_length > 1)
+ {
+ huff_counts->field_type=FIELD_SKIP_ZERO;
+ huff_counts->counts[0]-=length;
+ huff_counts->bytes_packed=old_length- records/8;
+ goto found_pack;
+ }
+ /* Remove the insignificant spaces, but keep the zeroes. */
+ huff_counts->counts[' ']=old_space_count;
+ }
+ /* Check, what the compressed length of this column would be. */
+ huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
+
+ /*
+ If there are enough empty records (in this column),
+ treating them specially may pay off.
+ */
+ if (huff_counts->empty_fields)
+ {
+ if (huff_counts->field_length > 2 &&
+ huff_counts->empty_fields + (records - huff_counts->empty_fields)*
+ (1+max_bit(max(huff_counts->max_pre_space,
+ huff_counts->max_end_space))) <
+ records * max_bit(huff_counts->field_length))
+ {
+ huff_counts->pack_type |= PACK_TYPE_SPACE_FIELDS;
+ }
+ else
+ {
+ length=huff_counts->empty_fields*huff_counts->field_length;
+ if (huff_counts->tot_end_space || ! huff_counts->tot_pre_space)
+ {
+ huff_counts->tot_end_space+=length;
+ huff_counts->max_end_space=huff_counts->field_length;
+ if (huff_counts->field_length < 8)
+ huff_counts->end_space[huff_counts->field_length]+=
+ huff_counts->empty_fields;
+ }
+ if (huff_counts->tot_pre_space)
+ {
+ huff_counts->tot_pre_space+=length;
+ huff_counts->max_pre_space=huff_counts->field_length;
+ if (huff_counts->field_length < 8)
+ huff_counts->pre_space[huff_counts->field_length]+=
+ huff_counts->empty_fields;
+ }
+ }
+ }
+
+ /*
+ If there are enough trailing spaces (in this column),
+ treating them specially may pay off.
+ */
+ if (huff_counts->tot_end_space)
+ {
+ huff_counts->counts[' ']+=huff_counts->tot_pre_space;
+ if (test_space_compress(huff_counts,records,huff_counts->max_end_space,
+ huff_counts->end_space,
+ huff_counts->tot_end_space,FIELD_SKIP_ENDSPACE))
+ goto found_pack;
+ huff_counts->counts[' ']-=huff_counts->tot_pre_space;
+ }
+
+ /*
+ If there are enough leading spaces (in this column),
+ treating them specially may pay off.
+ */
+ if (huff_counts->tot_pre_space)
+ {
+ if (test_space_compress(huff_counts,records,huff_counts->max_pre_space,
+ huff_counts->pre_space,
+ huff_counts->tot_pre_space,FIELD_SKIP_PRESPACE))
+ goto found_pack;
+ }
+
+ found_pack: /* Found field-packing */
+
+ /* Test if we can use zero-fill */
+
+ if (huff_counts->max_zero_fill &&
+ (huff_counts->field_type == FIELD_NORMAL ||
+ huff_counts->field_type == FIELD_SKIP_ZERO))
+ {
+ huff_counts->counts[0]-=huff_counts->max_zero_fill*
+ (huff_counts->field_type == FIELD_SKIP_ZERO ?
+ records - huff_counts->zero_fields : records);
+ huff_counts->pack_type|=PACK_TYPE_ZERO_FILL;
+ huff_counts->bytes_packed=calc_packed_length(huff_counts,0);
+ }
+
+ /* Test if intervall-field is better */
+
+ if (huff_counts->tree_buff)
+ {
+ HUFF_TREE tree;
+
+ DBUG_EXECUTE_IF("forceintervall",
+ huff_counts->bytes_packed= ~ (my_off_t) 0;);
+ tree.element_buffer=0;
+ if (!make_huff_tree(&tree,huff_counts) &&
+ tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed)
+ {
+ if (tree.elements == 1)
+ huff_counts->field_type=FIELD_CONSTANT;
+ else
+ huff_counts->field_type=FIELD_INTERVALL;
+ huff_counts->pack_type=0;
+ }
+ else
+ {
+ my_free((uchar*) huff_counts->tree_buff,MYF(0));
+ delete_tree(&huff_counts->int_tree);
+ huff_counts->tree_buff=0;
+ }
+ if (tree.element_buffer)
+ my_free((uchar*) tree.element_buffer,MYF(0));
+ }
+ if (huff_counts->pack_type & PACK_TYPE_SPACE_FIELDS)
+ space_fields++;
+ if (huff_counts->pack_type & PACK_TYPE_ZERO_FILL)
+ fill_zero_fields++;
+ field_count[huff_counts->field_type]++;
+ }
+ DBUG_PRINT("info", ("normal: %3d empty-space: %3d "
+ "empty-zero: %3d empty-fill: %3d",
+ field_count[FIELD_NORMAL],space_fields,
+ field_count[FIELD_SKIP_ZERO],fill_zero_fields));
+ DBUG_PRINT("info", ("pre-space: %3d end-space: %3d "
+ "intervall-fields: %3d zero: %3d",
+ field_count[FIELD_SKIP_PRESPACE],
+ field_count[FIELD_SKIP_ENDSPACE],
+ field_count[FIELD_INTERVALL],
+ field_count[FIELD_ZERO]));
+ if (verbose)
+ VOID(printf("\nnormal: %3d empty-space: %3d "
+ "empty-zero: %3d empty-fill: %3d\n"
+ "pre-space: %3d end-space: %3d "
+ "intervall-fields: %3d zero: %3d\n",
+ field_count[FIELD_NORMAL],space_fields,
+ field_count[FIELD_SKIP_ZERO],fill_zero_fields,
+ field_count[FIELD_SKIP_PRESPACE],
+ field_count[FIELD_SKIP_ENDSPACE],
+ field_count[FIELD_INTERVALL],
+ field_count[FIELD_ZERO]));
+ DBUG_VOID_RETURN;
+}
+
+
+/* Test if we can use space-compression and empty-field-compression */
+
+static int
+test_space_compress(HUFF_COUNTS *huff_counts, my_off_t records,
+ uint max_space_length, my_off_t *space_counts,
+ my_off_t tot_space_count, enum en_fieldtype field_type)
+{
+ int min_pos;
+ uint length_bits,i;
+ my_off_t space_count,min_space_count,min_pack,new_length,skip;
+
+ length_bits=max_bit(max_space_length);
+
+ /* Default no end_space-packing */
+ space_count=huff_counts->counts[(uint) ' '];
+ min_space_count= (huff_counts->counts[(uint) ' ']+= tot_space_count);
+ min_pack=calc_packed_length(huff_counts,0);
+ min_pos= -2;
+ huff_counts->counts[(uint) ' ']=space_count;
+
+ /* Test with allways space-count */
+ new_length=huff_counts->bytes_packed+length_bits*records/8;
+ if (new_length+1 < min_pack)
+ {
+ min_pos= -1;
+ min_pack=new_length;
+ min_space_count=space_count;
+ }
+ /* Test with length-flag */
+ for (skip=0L, i=0 ; i < 8 ; i++)
+ {
+ if (space_counts[i])
+ {
+ if (i)
+ huff_counts->counts[(uint) ' ']+=space_counts[i];
+ skip+=huff_counts->pre_space[i];
+ new_length=calc_packed_length(huff_counts,0)+
+ (records+(records-skip)*(1+length_bits))/8;
+ if (new_length < min_pack)
+ {
+ min_pos=(int) i;
+ min_pack=new_length;
+ min_space_count=huff_counts->counts[(uint) ' '];
+ }
+ }
+ }
+
+ huff_counts->counts[(uint) ' ']=min_space_count;
+ huff_counts->bytes_packed=min_pack;
+ switch (min_pos) {
+ case -2:
+ return(0); /* No space-compress */
+ case -1: /* Always space-count */
+ huff_counts->field_type=field_type;
+ huff_counts->min_space=0;
+ huff_counts->length_bits=max_bit(max_space_length);
+ break;
+ default:
+ huff_counts->field_type=field_type;
+ huff_counts->min_space=(uint) min_pos;
+ huff_counts->pack_type|=PACK_TYPE_SELECTED;
+ huff_counts->length_bits=max_bit(max_space_length);
+ break;
+ }
+ return(1); /* Using space-compress */
+}
+
+
+ /* Make a huff_tree of each huff_count */
+
+static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees)
+{
+ uint tree;
+ HUFF_TREE *huff_tree;
+ DBUG_ENTER("make_huff_trees");
+
+ if (!(huff_tree=(HUFF_TREE*) my_malloc(trees*sizeof(HUFF_TREE),
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(0);
+
+ for (tree=0 ; tree < trees ; tree++)
+ {
+ if (make_huff_tree(huff_tree+tree,huff_counts+tree))
+ {
+ while (tree--)
+ my_free((uchar*) huff_tree[tree].element_buffer,MYF(0));
+ my_free((uchar*) huff_tree,MYF(0));
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(huff_tree);
+}
+
+/*
+ Build a Huffman tree.
+
+ SYNOPSIS
+ make_huff_tree()
+ huff_tree The Huffman tree.
+ huff_counts The counts.
+
+ DESCRIPTION
+ Build a Huffman tree according to huff_counts->counts or
+ huff_counts->tree_buff. tree_buff, if non-NULL contains up to
+ tree_buff_length of distinct column values. In that case, whole
+ values can be Huffman encoded instead of single bytes.
+
+ RETURN
+ 0 OK
+ != 0 Error
+*/
+
+static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts)
+{
+ uint i,found,bits_packed,first,last;
+ my_off_t bytes_packed;
+ HUFF_ELEMENT *a,*b,*new_huff_el;
+
+ first=last=0;
+ if (huff_counts->tree_buff)
+ {
+ /* Calculate the number of distinct values in tree_buff. */
+ found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) /
+ huff_counts->field_length;
+ first=0; last=found-1;
+ }
+ else
+ {
+ /* Count the number of uchar codes found in the column. */
+ for (i=found=0 ; i < 256 ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ if (! found++)
+ first=i;
+ last=i;
+ }
+ }
+ if (found < 2)
+ found=2;
+ }
+
+ /* When using 'tree_buff' we can have more that 256 values. */
+ if (queue.max_elements < found)
+ {
+ delete_queue(&queue);
+ if (init_queue(&queue,found,0,0,compare_huff_elements,0))
+ return -1;
+ }
+
+ /* Allocate or reallocate an element buffer for the Huffman tree. */
+ if (!huff_tree->element_buffer)
+ {
+ if (!(huff_tree->element_buffer=
+ (HUFF_ELEMENT*) my_malloc(found*2*sizeof(HUFF_ELEMENT),MYF(MY_WME))))
+ return 1;
+ }
+ else
+ {
+ HUFF_ELEMENT *temp;
+ if (!(temp=
+ (HUFF_ELEMENT*) my_realloc((uchar*) huff_tree->element_buffer,
+ found*2*sizeof(HUFF_ELEMENT),
+ MYF(MY_WME))))
+ return 1;
+ huff_tree->element_buffer=temp;
+ }
+
+ huff_counts->tree=huff_tree;
+ huff_tree->counts=huff_counts;
+ huff_tree->min_chr=first;
+ huff_tree->max_chr=last;
+ huff_tree->char_bits=max_bit(last-first);
+ huff_tree->offset_bits=max_bit(found-1)+1;
+
+ if (huff_counts->tree_buff)
+ {
+ huff_tree->elements=0;
+ huff_tree->tree_pack_length=(1+15+16+5+5+
+ (huff_tree->char_bits+1)*found+
+ (huff_tree->offset_bits+1)*
+ (found-2)+7)/8 +
+ (uint) (huff_tree->counts->tree_pos-
+ huff_tree->counts->tree_buff);
+ /*
+ Put a HUFF_ELEMENT into the queue for every distinct column value.
+
+ tree_walk() calls save_counts_in_queue() for every element in
+ 'int_tree'. This takes elements from the target trees element
+ buffer and places references to them into the buffer of the
+ priority queue. We insert in column value order, but the order is
+ in fact irrelevant here. We will establish the correct order
+ later.
+ */
+ tree_walk(&huff_counts->int_tree,
+ (int (*)(void*, element_count,void*)) save_counts_in_queue,
+ (uchar*) huff_tree, left_root_right);
+ }
+ else
+ {
+ huff_tree->elements=found;
+ huff_tree->tree_pack_length=(9+9+5+5+
+ (huff_tree->char_bits+1)*found+
+ (huff_tree->offset_bits+1)*
+ (found-2)+7)/8;
+ /*
+ Put a HUFF_ELEMENT into the queue for every uchar code found in the column.
+
+ The elements are taken from the target trees element buffer.
+ Instead of using queue_insert(), we just place references to the
+ elements into the buffer of the priority queue. We insert in byte
+ value order, but the order is in fact irrelevant here. We will
+ establish the correct order later.
+ */
+ for (i=first, found=0 ; i <= last ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ new_huff_el=huff_tree->element_buffer+(found++);
+ new_huff_el->count=huff_counts->counts[i];
+ new_huff_el->a.leaf.null=0;
+ new_huff_el->a.leaf.element_nr=i;
+ queue.root[found]=(uchar*) new_huff_el;
+ }
+ }
+ /*
+ If there is only a single uchar value in this field in all records,
+ add a second element with zero incidence. This is required to enter
+ the loop, which builds the Huffman tree.
+ */
+ while (found < 2)
+ {
+ new_huff_el=huff_tree->element_buffer+(found++);
+ new_huff_el->count=0;
+ new_huff_el->a.leaf.null=0;
+ if (last)
+ new_huff_el->a.leaf.element_nr=huff_tree->min_chr=last-1;
+ else
+ new_huff_el->a.leaf.element_nr=huff_tree->max_chr=last+1;
+ queue.root[found]=(uchar*) new_huff_el;
+ }
+ }
+
+ /* Make a queue from the queue buffer. */
+ queue.elements=found;
+
+ /*
+ Make a priority queue from the queue. Construct its index so that we
+ have a partially ordered tree.
+ */
+ for (i=found/2 ; i > 0 ; i--)
+ _downheap(&queue,i);
+
+ /* The Huffman algorithm. */
+ bytes_packed=0; bits_packed=0;
+ for (i=1 ; i < found ; i++)
+ {
+ /*
+ Pop the top element from the queue (the one with the least incidence).
+ Popping from a priority queue includes a re-ordering of the queue,
+ to get the next least incidence element to the top.
+ */
+ a=(HUFF_ELEMENT*) queue_remove(&queue,0);
+ /*
+ Copy the next least incidence element. The queue implementation
+ reserves root[0] for temporary purposes. root[1] is the top.
+ */
+ b=(HUFF_ELEMENT*) queue.root[1];
+ /* Get a new element from the element buffer. */
+ new_huff_el=huff_tree->element_buffer+found+i;
+ /* The new element gets the sum of the two least incidence elements. */
+ new_huff_el->count=a->count+b->count;
+ /*
+ The Huffman algorithm assigns another bit to the code for a byte
+ every time that bytes incidence is combined (directly or indirectly)
+ to a new element as one of the two least incidence elements.
+ This means that one more bit per incidence of that uchar is required
+ in the resulting file. So we add the new combined incidence as the
+ number of bits by which the result grows.
+ */
+ bits_packed+=(uint) (new_huff_el->count & 7);
+ bytes_packed+=new_huff_el->count/8;
+ /* The new element points to its children, lesser in left. */
+ new_huff_el->a.nod.left=a;
+ new_huff_el->a.nod.right=b;
+ /*
+ Replace the copied top element by the new element and re-order the
+ queue.
+ */
+ queue.root[1]=(uchar*) new_huff_el;
+ queue_replaced(&queue);
+ }
+ huff_tree->root=(HUFF_ELEMENT*) queue.root[1];
+ huff_tree->bytes_packed=bytes_packed+(bits_packed+7)/8;
+ return 0;
+}
+
+static int compare_tree(void* cmp_arg __attribute__((unused)),
+ register const uchar *s, register const uchar *t)
+{
+ uint length;
+ for (length=global_count->field_length; length-- ;)
+ if (*s++ != *t++)
+ return (int) s[-1] - (int) t[-1];
+ return 0;
+}
+
+/*
+ Organize distinct column values and their incidences into a priority queue.
+
+ SYNOPSIS
+ save_counts_in_queue()
+ key The column value.
+ count The incidence of this value.
+ tree The Huffman tree to be built later.
+
+ DESCRIPTION
+ We use the element buffer of the targeted tree. The distinct column
+ values are organized in a priority queue first. The Huffman
+ algorithm will later organize the elements into a Huffman tree. For
+ the time being, we just place references to the elements into the
+ queue buffer. The buffer will later be organized into a priority
+ queue.
+
+ RETURN
+ 0
+ */
+
+static int save_counts_in_queue(uchar *key, element_count count,
+ HUFF_TREE *tree)
+{
+ HUFF_ELEMENT *new_huff_el;
+
+ new_huff_el=tree->element_buffer+(tree->elements++);
+ new_huff_el->count=count;
+ new_huff_el->a.leaf.null=0;
+ new_huff_el->a.leaf.element_nr= (uint) (key- tree->counts->tree_buff) /
+ tree->counts->field_length;
+ queue.root[tree->elements]=(uchar*) new_huff_el;
+ return 0;
+}
+
+
+/*
+ Calculate length of file if given counts should be used.
+
+ SYNOPSIS
+ calc_packed_length()
+ huff_counts The counts for a column of the table(s).
+ add_tree_lenght If the decode tree length should be added.
+
+ DESCRIPTION
+ We need to follow the Huffman algorithm until we know, how many bits
+ are required for each uchar code. But we do not need the resulting
+ Huffman tree. Hence, we can leave out some steps which are essential
+ in make_huff_tree().
+
+ RETURN
+ Number of bytes required to compress this table column.
+*/
+
+static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts,
+ uint add_tree_lenght)
+{
+ uint i,found,bits_packed,first,last;
+ my_off_t bytes_packed;
+ HUFF_ELEMENT element_buffer[256];
+ DBUG_ENTER("calc_packed_length");
+
+ /*
+ WARNING: We use a small hack for efficiency: Instead of placing
+ references to HUFF_ELEMENTs into the queue, we just insert
+ references to the counts of the uchar codes which appeared in this
+ table column. During the Huffman algorithm they are successively
+ replaced by references to HUFF_ELEMENTs. This works, because
+ HUFF_ELEMENTs have the incidence count at their beginning.
+ Regardless, wether the queue array contains references to counts of
+ type my_off_t or references to HUFF_ELEMENTs which have the count of
+ type my_off_t at their beginning, it always points to a count of the
+ same type.
+
+ Instead of using queue_insert(), we just copy the references into
+ the buffer of the priority queue. We insert in uchar value order, but
+ the order is in fact irrelevant here. We will establish the correct
+ order later.
+ */
+ first=last=0;
+ for (i=found=0 ; i < 256 ; i++)
+ {
+ if (huff_counts->counts[i])
+ {
+ if (! found++)
+ first=i;
+ last=i;
+ /* We start with root[1], which is the queues top element. */
+ queue.root[found]=(uchar*) &huff_counts->counts[i];
+ }
+ }
+ if (!found)
+ DBUG_RETURN(0); /* Empty tree */
+ /*
+ If there is only a single uchar value in this field in all records,
+ add a second element with zero incidence. This is required to enter
+ the loop, which follows the Huffman algorithm.
+ */
+ if (found < 2)
+ queue.root[++found]=(uchar*) &huff_counts->counts[last ? 0 : 1];
+
+ /* Make a queue from the queue buffer. */
+ queue.elements=found;
+
+ bytes_packed=0; bits_packed=0;
+ /* Add the length of the coding table, which would become part of the file. */
+ if (add_tree_lenght)
+ bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+
+ (max_bit(found-1)+1+1)*(found-2) +7)/8;
+
+ /*
+ Make a priority queue from the queue. Construct its index so that we
+ have a partially ordered tree.
+ */
+ for (i=(found+1)/2 ; i > 0 ; i--)
+ _downheap(&queue,i);
+
+ /* The Huffman algorithm. */
+ for (i=0 ; i < found-1 ; i++)
+ {
+ my_off_t *a;
+ my_off_t *b;
+ HUFF_ELEMENT *new_huff_el;
+
+ /*
+ Pop the top element from the queue (the one with the least
+ incidence). Popping from a priority queue includes a re-ordering
+ of the queue, to get the next least incidence element to the top.
+ */
+ a= (my_off_t*) queue_remove(&queue, 0);
+ /*
+ Copy the next least incidence element. The queue implementation
+ reserves root[0] for temporary purposes. root[1] is the top.
+ */
+ b= (my_off_t*) queue.root[1];
+ /* Create a new element in a local (automatic) buffer. */
+ new_huff_el= element_buffer + i;
+ /* The new element gets the sum of the two least incidence elements. */
+ new_huff_el->count= *a + *b;
+ /*
+ The Huffman algorithm assigns another bit to the code for a byte
+ every time that bytes incidence is combined (directly or indirectly)
+ to a new element as one of the two least incidence elements.
+ This means that one more bit per incidence of that uchar is required
+ in the resulting file. So we add the new combined incidence as the
+ number of bits by which the result grows.
+ */
+ bits_packed+=(uint) (new_huff_el->count & 7);
+ bytes_packed+=new_huff_el->count/8;
+ /*
+ Replace the copied top element by the new element and re-order the
+ queue. This successively replaces the references to counts by
+ references to HUFF_ELEMENTs.
+ */
+ queue.root[1]=(uchar*) new_huff_el;
+ queue_replaced(&queue);
+ }
+ DBUG_RETURN(bytes_packed+(bits_packed+7)/8);
+}
+
+
+ /* Remove trees that don't give any compression */
+
+static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees)
+{
+ uint k,tree_number;
+ HUFF_COUNTS count,*i,*j,*last_count;
+
+ last_count=huff_counts+trees;
+ for (tree_number=0, i=huff_counts ; i < last_count ; i++)
+ {
+ if (!i->tree->tree_number)
+ {
+ i->tree->tree_number= ++tree_number;
+ if (i->tree_buff)
+ continue; /* Don't join intervall */
+ for (j=i+1 ; j < last_count ; j++)
+ {
+ if (! j->tree->tree_number && ! j->tree_buff)
+ {
+ for (k=0 ; k < 256 ; k++)
+ count.counts[k]=i->counts[k]+j->counts[k];
+ if (calc_packed_length(&count,1) <=
+ i->tree->bytes_packed + j->tree->bytes_packed+
+ i->tree->tree_pack_length+j->tree->tree_pack_length+
+ ALLOWED_JOIN_DIFF)
+ {
+ memcpy_fixed((uchar*) i->counts,(uchar*) count.counts,
+ sizeof(count.counts[0])*256);
+ my_free((uchar*) j->tree->element_buffer,MYF(0));
+ j->tree->element_buffer=0;
+ j->tree=i->tree;
+ bmove((uchar*) i->counts,(uchar*) count.counts,
+ sizeof(count.counts[0])*256);
+ if (make_huff_tree(i->tree,i))
+ return (uint) -1;
+ }
+ }
+ }
+ }
+ }
+ DBUG_PRINT("info", ("Original trees: %d After join: %d",
+ trees, tree_number));
+ if (verbose)
+ VOID(printf("Original trees: %d After join: %d\n", trees, tree_number));
+ return tree_number; /* Return trees left */
+}
+
+
+/*
+ Fill in huff_tree encode tables.
+
+ SYNOPSIS
+ make_huff_decode_table()
+ huff_tree An array of HUFF_TREE which are to be encoded.
+ trees The number of HUFF_TREE in the array.
+
+ RETURN
+ 0 success
+ != 0 error
+*/
+
+static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees)
+{
+ uint elements;
+ for ( ; trees-- ; huff_tree++)
+ {
+ if (huff_tree->tree_number > 0)
+ {
+ elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256;
+ if (!(huff_tree->code =
+ (ulonglong*) my_malloc(elements*
+ (sizeof(ulonglong) + sizeof(uchar)),
+ MYF(MY_WME | MY_ZEROFILL))))
+ return 1;
+ huff_tree->code_len=(uchar*) (huff_tree->code+elements);
+ make_traverse_code_tree(huff_tree, huff_tree->root,
+ 8 * sizeof(ulonglong), LL(0));
+ }
+ }
+ return 0;
+}
+
+
+static void make_traverse_code_tree(HUFF_TREE *huff_tree,
+ HUFF_ELEMENT *element,
+ uint size, ulonglong code)
+{
+ uint chr;
+ if (!element->a.leaf.null)
+ {
+ chr=element->a.leaf.element_nr;
+ huff_tree->code_len[chr]= (uchar) (8 * sizeof(ulonglong) - size);
+ huff_tree->code[chr]= (code >> size);
+ if (huff_tree->height < 8 * sizeof(ulonglong) - size)
+ huff_tree->height= 8 * sizeof(ulonglong) - size;
+ }
+ else
+ {
+ size--;
+ make_traverse_code_tree(huff_tree,element->a.nod.left,size,code);
+ make_traverse_code_tree(huff_tree, element->a.nod.right, size,
+ code + (((ulonglong) 1) << size));
+ }
+ return;
+}
+
+
+/*
+ Convert a value into binary digits.
+
+ SYNOPSIS
+ bindigits()
+ value The value.
+ length The number of low order bits to convert.
+
+ NOTE
+ The result string is in static storage. It is reused on every call.
+ So you cannot use it twice in one expression.
+
+ RETURN
+ A pointer to a static NUL-terminated string.
+ */
+
+static char *bindigits(ulonglong value, uint bits)
+{
+ static char digits[72];
+ char *ptr= digits;
+ uint idx= bits;
+
+ DBUG_ASSERT(idx < sizeof(digits));
+ while (idx)
+ *(ptr++)= '0' + ((char) (value >> (--idx)) & (char) 1);
+ *ptr= '\0';
+ return digits;
+}
+
+
+/*
+ Convert a value into hexadecimal digits.
+
+ SYNOPSIS
+ hexdigits()
+ value The value.
+
+ NOTE
+ The result string is in static storage. It is reused on every call.
+ So you cannot use it twice in one expression.
+
+ RETURN
+ A pointer to a static NUL-terminated string.
+ */
+
+static char *hexdigits(ulonglong value)
+{
+ static char digits[20];
+ char *ptr= digits;
+ uint idx= 2 * sizeof(value); /* Two hex digits per byte. */
+
+ DBUG_ASSERT(idx < sizeof(digits));
+ while (idx)
+ {
+ if ((*(ptr++)= '0' + ((char) (value >> (4 * (--idx))) & (char) 0xf)) > '9')
+ *(ptr - 1)+= 'a' - '9' - 1;
+ }
+ *ptr= '\0';
+ return digits;
+}
+
+
+ /* Write header to new packed data file */
+
+static int write_header(PACK_MRG_INFO *mrg,uint head_length,uint trees,
+ my_off_t tot_elements,my_off_t filelength)
+{
+ uchar *buff= (uchar*) file_buffer.pos;
+
+ bzero(buff,HEAD_LENGTH);
+ memcpy_fixed(buff,maria_pack_file_magic,4);
+ int4store(buff+4,head_length);
+ int4store(buff+8, mrg->min_pack_length);
+ int4store(buff+12,mrg->max_pack_length);
+ int4store(buff+16,tot_elements);
+ int4store(buff+20,intervall_length);
+ int2store(buff+24,trees);
+ buff[26]=(char) mrg->ref_length;
+ /* Save record pointer length */
+ buff[27]= (uchar) maria_get_pointer_length((ulonglong) filelength,2);
+ if (test_only)
+ return 0;
+ VOID(my_seek(file_buffer.file,0L,MY_SEEK_SET,MYF(0)));
+ return my_write(file_buffer.file,(const uchar *) file_buffer.pos,HEAD_LENGTH,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0;
+}
+
+ /* Write fieldinfo to new packed file */
+
+static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees)
+{
+ reg1 uint i;
+ uint huff_tree_bits;
+ huff_tree_bits=max_bit(trees ? trees-1 : 0);
+
+ DBUG_PRINT("info", (" "));
+ DBUG_PRINT("info", ("column types:"));
+ DBUG_PRINT("info", ("FIELD_NORMAL 0"));
+ DBUG_PRINT("info", ("FIELD_SKIP_ENDSPACE 1"));
+ DBUG_PRINT("info", ("FIELD_SKIP_PRESPACE 2"));
+ DBUG_PRINT("info", ("FIELD_SKIP_ZERO 3"));
+ DBUG_PRINT("info", ("FIELD_BLOB 4"));
+ DBUG_PRINT("info", ("FIELD_CONSTANT 5"));
+ DBUG_PRINT("info", ("FIELD_INTERVALL 6"));
+ DBUG_PRINT("info", ("FIELD_ZERO 7"));
+ DBUG_PRINT("info", ("FIELD_VARCHAR 8"));
+ DBUG_PRINT("info", ("FIELD_CHECK 9"));
+ DBUG_PRINT("info", (" "));
+ DBUG_PRINT("info", ("pack type as a set of flags:"));
+ DBUG_PRINT("info", ("PACK_TYPE_SELECTED 1"));
+ DBUG_PRINT("info", ("PACK_TYPE_SPACE_FIELDS 2"));
+ DBUG_PRINT("info", ("PACK_TYPE_ZERO_FILL 4"));
+ DBUG_PRINT("info", (" "));
+ if (verbose >= 2)
+ {
+ VOID(printf("\n"));
+ VOID(printf("column types:\n"));
+ VOID(printf("FIELD_NORMAL 0\n"));
+ VOID(printf("FIELD_SKIP_ENDSPACE 1\n"));
+ VOID(printf("FIELD_SKIP_PRESPACE 2\n"));
+ VOID(printf("FIELD_SKIP_ZERO 3\n"));
+ VOID(printf("FIELD_BLOB 4\n"));
+ VOID(printf("FIELD_CONSTANT 5\n"));
+ VOID(printf("FIELD_INTERVALL 6\n"));
+ VOID(printf("FIELD_ZERO 7\n"));
+ VOID(printf("FIELD_VARCHAR 8\n"));
+ VOID(printf("FIELD_CHECK 9\n"));
+ VOID(printf("\n"));
+ VOID(printf("pack type as a set of flags:\n"));
+ VOID(printf("PACK_TYPE_SELECTED 1\n"));
+ VOID(printf("PACK_TYPE_SPACE_FIELDS 2\n"));
+ VOID(printf("PACK_TYPE_ZERO_FILL 4\n"));
+ VOID(printf("\n"));
+ }
+ for (i=0 ; i++ < fields ; counts++)
+ {
+ write_bits((ulonglong) (int) counts->field_type, 5);
+ write_bits(counts->pack_type,6);
+ if (counts->pack_type & PACK_TYPE_ZERO_FILL)
+ write_bits(counts->max_zero_fill,5);
+ else
+ write_bits(counts->length_bits,5);
+ write_bits((ulonglong) counts->tree->tree_number - 1, huff_tree_bits);
+ DBUG_PRINT("info", ("column: %3u type: %2u pack: %2u zero: %4u "
+ "lbits: %2u tree: %2u length: %4u",
+ i , counts->field_type, counts->pack_type,
+ counts->max_zero_fill, counts->length_bits,
+ counts->tree->tree_number, counts->field_length));
+ if (verbose >= 2)
+ VOID(printf("column: %3u type: %2u pack: %2u zero: %4u lbits: %2u "
+ "tree: %2u length: %4u\n", i , counts->field_type,
+ counts->pack_type, counts->max_zero_fill, counts->length_bits,
+ counts->tree->tree_number, counts->field_length));
+ }
+ flush_bits();
+ return;
+}
+
+ /* Write all huff_trees to new datafile. Return tot count of
+ elements in all trees
+ Returns 0 on error */
+
+static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees)
+{
+ uint i,int_length;
+ uint tree_no;
+ uint codes;
+ uint errors= 0;
+ uint *packed_tree,*offset,length;
+ my_off_t elements;
+
+ /* Find the highest number of elements in the trees. */
+ for (i=length=0 ; i < trees ; i++)
+ if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length)
+ length=huff_tree[i].elements;
+ /*
+ Allocate a buffer for packing a decode tree. Two numbers per element
+ (left child and right child).
+ */
+ if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2)))
+ {
+ my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2);
+ return 0;
+ }
+
+ DBUG_PRINT("info", (" "));
+ if (verbose >= 2)
+ VOID(printf("\n"));
+ tree_no= 0;
+ intervall_length=0;
+ for (elements=0; trees-- ; huff_tree++)
+ {
+ /* Skip columns that have been joined with other columns. */
+ if (huff_tree->tree_number == 0)
+ continue; /* Deleted tree */
+ tree_no++;
+ DBUG_PRINT("info", (" "));
+ if (verbose >= 3)
+ VOID(printf("\n"));
+ /* Count the total number of elements (byte codes or column values). */
+ elements+=huff_tree->elements;
+ huff_tree->max_offset=2;
+ /* Build a tree of offsets and codes for decoding in 'packed_tree'. */
+ if (huff_tree->elements <= 1)
+ offset=packed_tree;
+ else
+ offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree);
+
+ /* This should be the same as 'length' above. */
+ huff_tree->offset_bits=max_bit(huff_tree->max_offset);
+
+ /*
+ Since we check this during collecting the distinct column values,
+ this should never happen.
+ */
+ if (huff_tree->max_offset >= IS_OFFSET)
+ { /* This should be impossible */
+ VOID(fprintf(stderr, "Tree offset got too big: %d, aborted\n",
+ huff_tree->max_offset));
+ my_afree((uchar*) packed_tree);
+ return 0;
+ }
+
+ DBUG_PRINT("info", ("pos: %lu elements: %u tree-elements: %lu "
+ "char_bits: %u\n",
+ (ulong) (file_buffer.pos - file_buffer.buffer),
+ huff_tree->elements, (ulong) (offset - packed_tree),
+ huff_tree->char_bits));
+ if (!huff_tree->counts->tree_buff)
+ {
+ /* We do a uchar compression on this column. Mark with bit 0. */
+ write_bits(0,1);
+ write_bits(huff_tree->min_chr,8);
+ write_bits(huff_tree->elements,9);
+ write_bits(huff_tree->char_bits,5);
+ write_bits(huff_tree->offset_bits,5);
+ int_length=0;
+ }
+ else
+ {
+ int_length=(uint) (huff_tree->counts->tree_pos -
+ huff_tree->counts->tree_buff);
+ /* We have distinct column values for this column. Mark with bit 1. */
+ write_bits(1,1);
+ write_bits(huff_tree->elements,15);
+ write_bits(int_length,16);
+ write_bits(huff_tree->char_bits,5);
+ write_bits(huff_tree->offset_bits,5);
+ intervall_length+=int_length;
+ }
+ DBUG_PRINT("info", ("tree: %2u elements: %4u char_bits: %2u "
+ "offset_bits: %2u %s: %5u codelen: %2u",
+ tree_no, huff_tree->elements, huff_tree->char_bits,
+ huff_tree->offset_bits, huff_tree->counts->tree_buff ?
+ "bufflen" : "min_chr", huff_tree->counts->tree_buff ?
+ int_length : huff_tree->min_chr, huff_tree->height));
+ if (verbose >= 2)
+ VOID(printf("tree: %2u elements: %4u char_bits: %2u offset_bits: %2u "
+ "%s: %5u codelen: %2u\n", tree_no, huff_tree->elements,
+ huff_tree->char_bits, huff_tree->offset_bits,
+ huff_tree->counts->tree_buff ? "bufflen" : "min_chr",
+ huff_tree->counts->tree_buff ? int_length :
+ huff_tree->min_chr, huff_tree->height));
+
+ /* Check that the code tree length matches the element count. */
+ length=(uint) (offset-packed_tree);
+ if (length != huff_tree->elements*2-2)
+ {
+ VOID(fprintf(stderr, "error: Huff-tree-length: %d != calc_length: %d\n",
+ length, huff_tree->elements * 2 - 2));
+ errors++;
+ break;
+ }
+
+ for (i=0 ; i < length ; i++)
+ {
+ if (packed_tree[i] & IS_OFFSET)
+ write_bits(packed_tree[i] - IS_OFFSET+ (1 << huff_tree->offset_bits),
+ huff_tree->offset_bits+1);
+ else
+ write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1);
+ DBUG_PRINT("info", ("tree[0x%04x]: %s0x%04x",
+ i, (packed_tree[i] & IS_OFFSET) ?
+ " -> " : "", (packed_tree[i] & IS_OFFSET) ?
+ packed_tree[i] - IS_OFFSET + i : packed_tree[i]));
+ if (verbose >= 3)
+ VOID(printf("tree[0x%04x]: %s0x%04x\n",
+ i, (packed_tree[i] & IS_OFFSET) ? " -> " : "",
+ (packed_tree[i] & IS_OFFSET) ?
+ packed_tree[i] - IS_OFFSET + i : packed_tree[i]));
+ }
+ flush_bits();
+
+ /*
+ Display coding tables and check their correctness.
+ */
+ codes= huff_tree->counts->tree_buff ? huff_tree->elements : 256;
+ for (i= 0; i < codes; i++)
+ {
+ ulonglong code;
+ uint bits;
+ uint len;
+ uint idx;
+
+ if (! (len= huff_tree->code_len[i]))
+ continue;
+ DBUG_PRINT("info", ("code[0x%04x]: 0x%s bits: %2u bin: %s", i,
+ hexdigits(huff_tree->code[i]), huff_tree->code_len[i],
+ bindigits(huff_tree->code[i],
+ huff_tree->code_len[i])));
+ if (verbose >= 3)
+ VOID(printf("code[0x%04x]: 0x%s bits: %2u bin: %s\n", i,
+ hexdigits(huff_tree->code[i]), huff_tree->code_len[i],
+ bindigits(huff_tree->code[i], huff_tree->code_len[i])));
+
+ /* Check that the encode table decodes correctly. */
+ code= 0;
+ bits= 0;
+ idx= 0;
+ DBUG_EXECUTE_IF("forcechkerr1", len--;);
+ DBUG_EXECUTE_IF("forcechkerr2", bits= 8 * sizeof(code););
+ DBUG_EXECUTE_IF("forcechkerr3", idx= length;);
+ for (;;)
+ {
+ if (! len)
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: code 0x%s with %u bits not found\n",
+ hexdigits(huff_tree->code[i]), huff_tree->code_len[i]));
+ errors++;
+ break;
+ }
+ code<<= 1;
+ code|= (huff_tree->code[i] >> (--len)) & 1;
+ bits++;
+ if (bits > 8 * sizeof(code))
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: Huffman code too long: %u/%u\n",
+ bits, (uint) (8 * sizeof(code))));
+ errors++;
+ break;
+ }
+ idx+= (uint) code & 1;
+ if (idx >= length)
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: illegal tree offset: %u/%u\n",
+ idx, length));
+ errors++;
+ break;
+ }
+ if (packed_tree[idx] & IS_OFFSET)
+ idx+= packed_tree[idx] & ~IS_OFFSET;
+ else
+ break; /* Hit a leaf. This contains the result value. */
+ }
+ if (errors)
+ break;
+
+ DBUG_EXECUTE_IF("forcechkerr4", packed_tree[idx]++;);
+ if (packed_tree[idx] != i)
+ {
+ VOID(fflush(stdout));
+ VOID(fprintf(stderr, "error: decoded value 0x%04x should be: 0x%04x\n",
+ packed_tree[idx], i));
+ errors++;
+ break;
+ }
+ } /*end for (codes)*/
+ if (errors)
+ break;
+
+ /* Write column values in case of distinct column value compression. */
+ if (huff_tree->counts->tree_buff)
+ {
+ for (i=0 ; i < int_length ; i++)
+ {
+ write_bits((ulonglong) (uchar) huff_tree->counts->tree_buff[i], 8);
+ DBUG_PRINT("info", ("column_values[0x%04x]: 0x%02x",
+ i, (uchar) huff_tree->counts->tree_buff[i]));
+ if (verbose >= 3)
+ VOID(printf("column_values[0x%04x]: 0x%02x\n",
+ i, (uchar) huff_tree->counts->tree_buff[i]));
+ }
+ }
+ flush_bits();
+ }
+ DBUG_PRINT("info", (" "));
+ if (verbose >= 2)
+ VOID(printf("\n"));
+ my_afree((uchar*) packed_tree);
+ if (errors)
+ {
+ VOID(fprintf(stderr, "Error: Generated decode trees are corrupt. Stop.\n"));
+ return 0;
+ }
+ return elements;
+}
+
+
+static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,
+ uint *offset)
+{
+ uint *prev_offset;
+
+ prev_offset= offset;
+ /*
+ 'a.leaf.null' takes the same place as 'a.nod.left'. If this is null,
+ then there is no left child and, hence no right child either. This
+ is a property of a binary tree. An element is either a node with two
+ childs, or a leaf without childs.
+
+ The current element is always a node with two childs. Go left first.
+ */
+ if (!element->a.nod.left->a.leaf.null)
+ {
+ /* Store the uchar code or the index of the column value. */
+ prev_offset[0] =(uint) element->a.nod.left->a.leaf.element_nr;
+ offset+=2;
+ }
+ else
+ {
+ /*
+ Recursively traverse the tree to the left. Mark it as an offset to
+ another tree node (in contrast to a uchar code or column value index).
+ */
+ prev_offset[0]= IS_OFFSET+2;
+ offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2);
+ }
+
+ /* Now, check the right child. */
+ if (!element->a.nod.right->a.leaf.null)
+ {
+ /* Store the uchar code or the index of the column value. */
+ prev_offset[1]=element->a.nod.right->a.leaf.element_nr;
+ return offset;
+ }
+ else
+ {
+ /*
+ Recursively traverse the tree to the right. Mark it as an offset to
+ another tree node (in contrast to a uchar code or column value index).
+ */
+ uint temp=(uint) (offset-prev_offset-1);
+ prev_offset[1]= IS_OFFSET+ temp;
+ if (huff_tree->max_offset < temp)
+ huff_tree->max_offset = temp;
+ return make_offset_code_tree(huff_tree,element->a.nod.right,offset);
+ }
+}
+
+ /* Get number of bits neaded to represent value */
+
+static uint max_bit(register uint value)
+{
+ reg2 uint power=1;
+
+ while ((value>>=1))
+ power++;
+ return (power);
+}
+
+
+static int compress_maria_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
+{
+ int error;
+ uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length;
+ uint intervall,field_length,max_pack_length,pack_blob_length, null_bytes;
+ my_off_t record_count;
+ char llbuf[32];
+ ulong length,pack_length;
+ uchar *record,*pos,*end_pos,*record_pos,*start_pos;
+ HUFF_COUNTS *count,*end_count;
+ HUFF_TREE *tree;
+ MARIA_HA *isam_file=mrg->file[0];
+ uint pack_version= (uint) isam_file->s->pack.version;
+ DBUG_ENTER("compress_maria_file");
+
+ /* Allocate a buffer for the records (excluding blobs). */
+ if (!(record=(uchar*) my_alloca(isam_file->s->base.reclength)))
+ return -1;
+
+ end_count=huff_counts+isam_file->s->base.fields;
+ min_record_length= (uint) ~0;
+ max_record_length=0;
+ null_bytes= isam_file->s->base.null_bytes;
+
+ /*
+ Calculate the maximum number of bits required to pack the records.
+ Remember to understand 'max_zero_fill' as 'min_zero_fill'.
+ The tree height determines the maximum number of bits per value.
+ Some fields skip leading or trailing spaces or zeroes. The skipped
+ number of bytes is encoded by 'length_bits' bits.
+ Empty blobs and varchar are encoded with a single 1 bit. Other blobs
+ and varchar get a leading 0 bit.
+ */
+ max_calc_length= null_bytes;
+ for (i= 0 ; i < isam_file->s->base.fields ; i++)
+ {
+ if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL))
+ huff_counts[i].max_zero_fill=0;
+ if (huff_counts[i].field_type == FIELD_CONSTANT ||
+ huff_counts[i].field_type == FIELD_ZERO ||
+ huff_counts[i].field_type == FIELD_CHECK)
+ continue;
+ if (huff_counts[i].field_type == FIELD_INTERVALL)
+ max_calc_length+=huff_counts[i].tree->height;
+ else if (huff_counts[i].field_type == FIELD_BLOB ||
+ huff_counts[i].field_type == FIELD_VARCHAR)
+ max_calc_length+=huff_counts[i].tree->height*huff_counts[i].max_length + huff_counts[i].length_bits +1;
+ else
+ max_calc_length+=
+ (huff_counts[i].field_length - huff_counts[i].max_zero_fill)*
+ huff_counts[i].tree->height+huff_counts[i].length_bits;
+ }
+ max_calc_length= (max_calc_length + 7) / 8;
+ pack_ref_length= _ma_calc_pack_length(pack_version, max_calc_length);
+ record_count=0;
+ /* 'max_blob_length' is the max length of all blobs of a record. */
+ pack_blob_length= isam_file->s->base.blobs ?
+ _ma_calc_pack_length(pack_version, mrg->max_blob_length) : 0;
+ max_pack_length=pack_ref_length+pack_blob_length;
+
+ DBUG_PRINT("fields", ("==="));
+ mrg_reset(mrg);
+ while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE)
+ {
+ ulong tot_blob_length=0;
+ if (! error)
+ {
+ if (flush_buffer((ulong) max_calc_length + (ulong) max_pack_length +
+ null_bytes))
+ break;
+ record_pos= (uchar*) file_buffer.pos;
+ file_buffer.pos+= max_pack_length;
+ if (null_bytes)
+ {
+ /* Copy null bits 'as is' */
+ memcpy(file_buffer.pos, record, null_bytes);
+ file_buffer.pos+= null_bytes;
+ }
+ for (start_pos=record+null_bytes, count= huff_counts;
+ count < end_count ;
+ count++)
+ {
+ end_pos=start_pos+(field_length=count->field_length);
+ tree=count->tree;
+
+ DBUG_PRINT("fields", ("column: %3lu type: %2u pack: %2u zero: %4u "
+ "lbits: %2u tree: %2u length: %4u",
+ (ulong) (count - huff_counts + 1),
+ count->field_type,
+ count->pack_type, count->max_zero_fill,
+ count->length_bits, count->tree->tree_number,
+ count->field_length));
+
+ /* Check if the column contains spaces only. */
+ if (count->pack_type & PACK_TYPE_SPACE_FIELDS)
+ {
+ for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ;
+ if (pos == end_pos)
+ {
+ DBUG_PRINT("fields",
+ ("PACK_TYPE_SPACE_FIELDS spaces only, bits: 1"));
+ DBUG_PRINT("fields", ("---"));
+ write_bits(1,1);
+ start_pos=end_pos;
+ continue;
+ }
+ DBUG_PRINT("fields",
+ ("PACK_TYPE_SPACE_FIELDS not only spaces, bits: 1"));
+ write_bits(0,1);
+ }
+ end_pos-=count->max_zero_fill;
+ field_length-=count->max_zero_fill;
+
+ switch (count->field_type) {
+ case FIELD_SKIP_ZERO:
+ if (!memcmp((uchar*) start_pos,zero_string,field_length))
+ {
+ DBUG_PRINT("fields", ("FIELD_SKIP_ZERO zeroes only, bits: 1"));
+ write_bits(1,1);
+ start_pos=end_pos;
+ break;
+ }
+ DBUG_PRINT("fields", ("FIELD_SKIP_ZERO not only zeroes, bits: 1"));
+ write_bits(0,1);
+ /* Fall through */
+ case FIELD_NORMAL:
+ DBUG_PRINT("fields", ("FIELD_NORMAL %lu bytes",
+ (ulong) (end_pos - start_pos)));
+ for ( ; start_pos < end_pos ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos])));
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ }
+ break;
+ case FIELD_SKIP_ENDSPACE:
+ for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ;
+ length= (ulong) (end_pos - pos);
+ if (count->pack_type & PACK_TYPE_SELECTED)
+ {
+ if (length > count->min_space)
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE more than min_space, bits: 1"));
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
+ write_bits(1,1);
+ write_bits(length,count->length_bits);
+ }
+ else
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE not more than min_space, "
+ "bits: 1"));
+ write_bits(0,1);
+ pos=end_pos;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_ENDSPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
+ write_bits(length,count->length_bits);
+ }
+ /* Encode all significant bytes. */
+ DBUG_PRINT("fields", ("FIELD_SKIP_ENDSPACE %lu bytes",
+ (ulong) (pos - start_pos)));
+ for ( ; start_pos < pos ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos])));
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ }
+ start_pos=end_pos;
+ break;
+ case FIELD_SKIP_PRESPACE:
+ for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ;
+ length= (ulong) (pos - start_pos);
+ if (count->pack_type & PACK_TYPE_SELECTED)
+ {
+ if (length > count->min_space)
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE more than min_space, bits: 1"));
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
+ write_bits(1,1);
+ write_bits(length,count->length_bits);
+ }
+ else
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE not more than min_space, "
+ "bits: 1"));
+ pos=start_pos;
+ write_bits(0,1);
+ }
+ }
+ else
+ {
+ DBUG_PRINT("fields",
+ ("FIELD_SKIP_PRESPACE skip %lu/%u bytes, bits: %2u",
+ length, field_length, count->length_bits));
+ write_bits(length,count->length_bits);
+ }
+ /* Encode all significant bytes. */
+ DBUG_PRINT("fields", ("FIELD_SKIP_PRESPACE %lu bytes",
+ (ulong) (end_pos - start_pos)));
+ for (start_pos=pos ; start_pos < end_pos ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos])));
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ }
+ break;
+ case FIELD_CONSTANT:
+ case FIELD_ZERO:
+ case FIELD_CHECK:
+ DBUG_PRINT("fields", ("FIELD_CONSTANT/ZERO/CHECK"));
+ start_pos=end_pos;
+ break;
+ case FIELD_INTERVALL:
+ global_count=count;
+ pos=(uchar*) tree_search(&count->int_tree, start_pos,
+ count->int_tree.custom_arg);
+ intervall=(uint) (pos - count->tree_buff)/field_length;
+ DBUG_PRINT("fields", ("FIELD_INTERVALL"));
+ DBUG_PRINT("fields", ("index: %4u code: 0x%s bits: %2u",
+ intervall, hexdigits(tree->code[intervall]),
+ (uint) tree->code_len[intervall]));
+ write_bits(tree->code[intervall],(uint) tree->code_len[intervall]);
+ start_pos=end_pos;
+ break;
+ case FIELD_BLOB:
+ {
+ ulong blob_length= _ma_calc_blob_length(field_length-
+ portable_sizeof_char_ptr,
+ start_pos);
+ /* Empty blobs are encoded with a single 1 bit. */
+ if (!blob_length)
+ {
+ DBUG_PRINT("fields", ("FIELD_BLOB empty, bits: 1"));
+ write_bits(1,1);
+ }
+ else
+ {
+ uchar *blob,*blob_end;
+ DBUG_PRINT("fields", ("FIELD_BLOB not empty, bits: 1"));
+ write_bits(0,1);
+ /* Write the blob length. */
+ DBUG_PRINT("fields", ("FIELD_BLOB %lu bytes, bits: %2u",
+ blob_length, count->length_bits));
+ write_bits(blob_length,count->length_bits);
+ memcpy_fixed(&blob,end_pos-portable_sizeof_char_ptr,
+ sizeof(char*));
+ blob_end=blob+blob_length;
+ /* Encode the blob bytes. */
+ for ( ; blob < blob_end ; blob++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *blob, hexdigits(tree->code[(uchar) *blob]),
+ (uint) tree->code_len[(uchar) *blob],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint)tree->code_len[(uchar) *start_pos])));
+ write_bits(tree->code[(uchar) *blob],
+ (uint) tree->code_len[(uchar) *blob]);
+ }
+ tot_blob_length+=blob_length;
+ }
+ start_pos= end_pos;
+ break;
+ }
+ case FIELD_VARCHAR:
+ {
+ uint var_pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
+ ulong col_length= (var_pack_length == 1 ?
+ (uint) *(uchar*) start_pos :
+ uint2korr(start_pos));
+ /* Empty varchar are encoded with a single 1 bit. */
+ if (!col_length)
+ {
+ DBUG_PRINT("fields", ("FIELD_VARCHAR empty, bits: 1"));
+ write_bits(1,1); /* Empty varchar */
+ }
+ else
+ {
+ uchar *end= start_pos + var_pack_length + col_length;
+ DBUG_PRINT("fields", ("FIELD_VARCHAR not empty, bits: 1"));
+ write_bits(0,1);
+ /* Write the varchar length. */
+ DBUG_PRINT("fields", ("FIELD_VARCHAR %lu bytes, bits: %2u",
+ col_length, count->length_bits));
+ write_bits(col_length,count->length_bits);
+ /* Encode the varchar bytes. */
+ for (start_pos+= var_pack_length ; start_pos < end ; start_pos++)
+ {
+ DBUG_PRINT("fields",
+ ("value: 0x%02x code: 0x%s bits: %2u bin: %s",
+ (uchar) *start_pos,
+ hexdigits(tree->code[(uchar) *start_pos]),
+ (uint) tree->code_len[(uchar) *start_pos],
+ bindigits(tree->code[(uchar) *start_pos],
+ (uint)tree->code_len[(uchar) *start_pos])));
+ write_bits(tree->code[(uchar) *start_pos],
+ (uint) tree->code_len[(uchar) *start_pos]);
+ }
+ }
+ start_pos= end_pos;
+ break;
+ }
+ case FIELD_LAST:
+ case FIELD_enum_val_count:
+ abort(); /* Impossible */
+ }
+ start_pos+=count->max_zero_fill;
+ DBUG_PRINT("fields", ("---"));
+ }
+ flush_bits();
+ length=(ulong) ((uchar*) file_buffer.pos - record_pos) - max_pack_length;
+ pack_length= _ma_save_pack_length(pack_version, record_pos, length);
+ if (pack_blob_length)
+ pack_length+= _ma_save_pack_length(pack_version,
+ record_pos + pack_length,
+ tot_blob_length);
+ DBUG_PRINT("fields", ("record: %lu length: %lu blob-length: %lu "
+ "length-bytes: %lu", (ulong) record_count, length,
+ tot_blob_length, pack_length));
+ DBUG_PRINT("fields", ("==="));
+
+ /* Correct file buffer if the header was smaller */
+ if (pack_length != max_pack_length)
+ {
+ bmove(record_pos+pack_length,record_pos+max_pack_length,length);
+ file_buffer.pos-= (max_pack_length-pack_length);
+ }
+ if (length < (ulong) min_record_length)
+ min_record_length=(uint) length;
+ if (length > (ulong) max_record_length)
+ max_record_length=(uint) length;
+ record_count++;
+ if (write_loop && record_count % WRITE_COUNT == 0)
+ {
+ VOID(printf("%lu\r", (ulong) record_count));
+ VOID(fflush(stdout));
+ }
+ }
+ else if (error != HA_ERR_RECORD_DELETED)
+ break;
+ }
+ if (error == HA_ERR_END_OF_FILE)
+ error=0;
+ else
+ {
+ VOID(fprintf(stderr, "%s: Got error %d reading records\n",
+ my_progname, error));
+ }
+ if (verbose >= 2)
+ VOID(printf("wrote %s records.\n", llstr((longlong) record_count, llbuf)));
+
+ my_afree((uchar*) record);
+ mrg->ref_length=max_pack_length;
+ mrg->min_pack_length=max_record_length ? min_record_length : 0;
+ mrg->max_pack_length=max_record_length;
+ DBUG_RETURN(error || error_on_write || flush_buffer(~(ulong) 0));
+}
+
+
+static char *make_new_name(char *new_name, char *old_name)
+{
+ return fn_format(new_name,old_name,"",DATA_TMP_EXT,2+4);
+}
+
+static char *make_old_name(char *new_name, char *old_name)
+{
+ return fn_format(new_name,old_name,"",OLD_EXT,2+4);
+}
+
+ /* rutines for bit writing buffer */
+
+static void init_file_buffer(File file, pbool read_buffer)
+{
+ file_buffer.file=file;
+ file_buffer.buffer= (uchar*) my_malloc(ALIGN_SIZE(RECORD_CACHE_SIZE),
+ MYF(MY_WME));
+ file_buffer.end=file_buffer.buffer+ALIGN_SIZE(RECORD_CACHE_SIZE)-8;
+ file_buffer.pos_in_file=0;
+ error_on_write=0;
+ if (read_buffer)
+ {
+
+ file_buffer.pos=file_buffer.end;
+ file_buffer.bits=0;
+ }
+ else
+ {
+ file_buffer.pos=file_buffer.buffer;
+ file_buffer.bits=BITS_SAVED;
+ }
+ file_buffer.bitbucket= 0;
+}
+
+
+static int flush_buffer(ulong neaded_length)
+{
+ ulong length;
+
+ /*
+ file_buffer.end is 8 bytes lower than the real end of the buffer.
+ This is done so that the end-of-buffer condition does not need to be
+ checked for every uchar (see write_bits()). Consequently,
+ file_buffer.pos can become greater than file_buffer.end. The
+ algorithms in the other functions ensure that there will never be
+ more than 8 bytes written to the buffer without an end-of-buffer
+ check. So the buffer cannot be overrun. But we need to check for the
+ near-to-buffer-end condition to avoid a negative result, which is
+ casted to unsigned and thus becomes giant.
+ */
+ if ((file_buffer.pos < file_buffer.end) &&
+ ((ulong) (file_buffer.end - file_buffer.pos) > neaded_length))
+ return 0;
+ length=(ulong) (file_buffer.pos-file_buffer.buffer);
+ file_buffer.pos=file_buffer.buffer;
+ file_buffer.pos_in_file+=length;
+ if (test_only)
+ return 0;
+ if (error_on_write|| my_write(file_buffer.file,
+ (const uchar*) file_buffer.buffer,
+ length,
+ MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ error_on_write=1;
+ return 1;
+ }
+
+ if (neaded_length != ~(ulong) 0 &&
+ (ulong) (file_buffer.end-file_buffer.buffer) < neaded_length)
+ {
+ char *tmp;
+ neaded_length+=256; /* some margin */
+ tmp= my_realloc((char*) file_buffer.buffer, neaded_length,MYF(MY_WME));
+ if (!tmp)
+ return 1;
+ file_buffer.pos= ((uchar*) tmp +
+ (ulong) (file_buffer.pos - file_buffer.buffer));
+ file_buffer.buffer= (uchar*) tmp;
+ file_buffer.end= (uchar*) (tmp+neaded_length-8);
+ }
+ return 0;
+}
+
+
+static void end_file_buffer(void)
+{
+ my_free((uchar*) file_buffer.buffer,MYF(0));
+}
+
+ /* output `bits` low bits of `value' */
+
+static void write_bits(register ulonglong value, register uint bits)
+{
+ DBUG_ASSERT(((bits < 8 * sizeof(value)) && ! (value >> bits)) ||
+ (bits == 8 * sizeof(value)));
+
+ if ((file_buffer.bits-= (int) bits) >= 0)
+ {
+ file_buffer.bitbucket|= value << file_buffer.bits;
+ }
+ else
+ {
+ reg3 ulonglong bit_buffer;
+ bits= (uint) -file_buffer.bits;
+ bit_buffer= (file_buffer.bitbucket |
+ ((bits != 8 * sizeof(value)) ? (value >> bits) : 0));
+#if BITS_SAVED == 64
+ *file_buffer.pos++= (uchar) (bit_buffer >> 56);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 48);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 40);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 32);
+#endif
+ *file_buffer.pos++= (uchar) (bit_buffer >> 24);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 16);
+ *file_buffer.pos++= (uchar) (bit_buffer >> 8);
+ *file_buffer.pos++= (uchar) (bit_buffer);
+
+ if (bits != 8 * sizeof(value))
+ value&= (((ulonglong) 1) << bits) - 1;
+ if (file_buffer.pos >= file_buffer.end)
+ VOID(flush_buffer(~ (ulong) 0));
+ file_buffer.bits=(int) (BITS_SAVED - bits);
+ file_buffer.bitbucket= value << (BITS_SAVED - bits);
+ }
+ return;
+}
+
+ /* Flush bits in bit_buffer to buffer */
+
+static void flush_bits(void)
+{
+ int bits;
+ ulonglong bit_buffer;
+
+ bits= file_buffer.bits & ~7;
+ bit_buffer= file_buffer.bitbucket >> bits;
+ bits= BITS_SAVED - bits;
+ while (bits > 0)
+ {
+ bits-= 8;
+ *file_buffer.pos++= (uchar) (bit_buffer >> bits);
+ }
+ if (file_buffer.pos >= file_buffer.end)
+ VOID(flush_buffer(~ (ulong) 0));
+ file_buffer.bits= BITS_SAVED;
+ file_buffer.bitbucket= 0;
+}
+
+
+/****************************************************************************
+** functions to handle the joined files
+****************************************************************************/
+
+static int save_state(MARIA_HA *isam_file,PACK_MRG_INFO *mrg,
+ my_off_t new_length,
+ ha_checksum crc)
+{
+ MARIA_SHARE *share=isam_file->s;
+ uint options=mi_uint2korr(share->state.header.options);
+ uint key;
+ DBUG_ENTER("save_state");
+
+ options|= HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA;
+ mi_int2store(share->state.header.options,options);
+ /* Save the original file type of we have to undo the packing later */
+ share->state.header.org_data_file_type= share->state.header.data_file_type;
+ share->state.header.data_file_type= COMPRESSED_RECORD;
+
+ share->state.state.data_file_length=new_length;
+ share->state.state.del=0;
+ share->state.state.empty=0;
+ share->state.dellink= HA_OFFSET_ERROR;
+ share->state.split=(ha_rows) mrg->records;
+ share->state.version=(ulong) time((time_t*) 0);
+ if (share->base.born_transactional)
+ share->state.create_rename_lsn= share->state.is_of_horizon=
+ share->state.skip_redo_lsn= LSN_NEEDS_NEW_STATE_LSNS;
+ if (! maria_is_all_keys_active(share->state.key_map, share->base.keys))
+ {
+ /*
+ Some indexes are disabled, cannot use current key_file_length value
+ as an estimate of upper bound of index file size. Use packed data file
+ size instead.
+ */
+ share->state.state.key_file_length= new_length;
+ }
+ /*
+ If there are no disabled indexes, keep key_file_length value from
+ original file so "maria_chk -rq" can use this value (this is necessary
+ because index size cannot be easily calculated for fulltext keys)
+ */
+ maria_clear_all_keys_active(share->state.key_map);
+ for (key=0 ; key < share->base.keys ; key++)
+ share->state.key_root[key]= HA_OFFSET_ERROR;
+ share->state.key_del= HA_OFFSET_ERROR;
+ share->state.state.checksum= crc; /* Save crc in file */
+ share->changed=1; /* Force write of header */
+ share->state.open_count=0;
+ share->global_changed=0;
+ VOID(my_chsize(share->kfile.file, share->base.keystart, 0, MYF(0)));
+ if (share->base.keys)
+ isamchk_neaded=1;
+ DBUG_RETURN(_ma_state_info_write_sub(share->kfile.file,
+ &share->state,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO));
+}
+
+
+static int save_state_mrg(File file,PACK_MRG_INFO *mrg,my_off_t new_length,
+ ha_checksum crc)
+{
+ MARIA_STATE_INFO state;
+ MARIA_HA *isam_file=mrg->file[0];
+ uint options;
+ DBUG_ENTER("save_state_mrg");
+
+ state= isam_file->s->state;
+ options= (mi_uint2korr(state.header.options) | HA_OPTION_COMPRESS_RECORD |
+ HA_OPTION_READ_ONLY_DATA);
+ mi_int2store(state.header.options,options);
+ /* Save the original file type of we have to undo the packing later */
+ state.header.org_data_file_type= state.header.data_file_type;
+ state.header.data_file_type= COMPRESSED_RECORD;
+
+ state.state.data_file_length=new_length;
+ state.state.del=0;
+ state.state.empty=0;
+ state.state.records=state.split=(ha_rows) mrg->records;
+ state.create_rename_lsn= state.is_of_horizon= state.skip_redo_lsn=
+ LSN_NEEDS_NEW_STATE_LSNS;
+
+ /* See comment above in save_state about key_file_length handling. */
+ if (mrg->src_file_has_indexes_disabled)
+ {
+ isam_file->s->state.state.key_file_length=
+ max(isam_file->s->state.state.key_file_length, new_length);
+ }
+ state.dellink= HA_OFFSET_ERROR;
+ state.version=(ulong) time((time_t*) 0);
+ maria_clear_all_keys_active(state.key_map);
+ state.state.checksum=crc;
+ if (isam_file->s->base.keys)
+ isamchk_neaded=1;
+ state.changed=STATE_CHANGED | STATE_NOT_ANALYZED; /* Force check of table */
+ DBUG_RETURN (_ma_state_info_write_sub(file, &state,
+ MA_STATE_INFO_WRITE_DONT_MOVE_OFFSET |
+ MA_STATE_INFO_WRITE_FULL_INFO));
+}
+
+
+/* reset for mrg_rrnd */
+
+static void mrg_reset(PACK_MRG_INFO *mrg)
+{
+ if (mrg->current)
+ {
+ maria_extra(*mrg->current, HA_EXTRA_NO_CACHE, 0);
+ mrg->current=0;
+ }
+}
+
+static int mrg_rrnd(PACK_MRG_INFO *info,uchar *buf)
+{
+ int error;
+ MARIA_HA *isam_info;
+ my_off_t filepos;
+
+ if (!info->current)
+ {
+ isam_info= *(info->current=info->file);
+ info->end=info->current+info->count;
+ maria_reset(isam_info);
+ maria_extra(isam_info, HA_EXTRA_CACHE, 0);
+ if ((error= maria_scan_init(isam_info)))
+ return(error);
+ }
+ else
+ isam_info= *info->current;
+
+ for (;;)
+ {
+ if (!(error= maria_scan(isam_info, buf)) ||
+ error != HA_ERR_END_OF_FILE)
+ return (error);
+ maria_scan_end(isam_info);
+ maria_extra(isam_info,HA_EXTRA_NO_CACHE, 0);
+ if (info->current+1 == info->end)
+ return(HA_ERR_END_OF_FILE);
+ info->current++;
+ isam_info= *info->current;
+ filepos=isam_info->s->pack.header_length;
+ maria_reset(isam_info);
+ maria_extra(isam_info,HA_EXTRA_CACHE, 0);
+ if ((error= maria_scan_init(isam_info)))
+ return(error);
+ }
+}
+
+
+static int mrg_close(PACK_MRG_INFO *mrg)
+{
+ uint i;
+ int error=0;
+ DBUG_ENTER("mrg_close");
+
+ for (i=0 ; i < mrg->count ; i++)
+ error|=maria_close(mrg->file[i]);
+ if (mrg->free_file)
+ my_free((uchar*) mrg->file,MYF(0));
+ DBUG_RETURN(error);
+}
+
+
+#if !defined(DBUG_OFF)
+/*
+ Fake the counts to get big Huffman codes.
+
+ SYNOPSIS
+ fakebigcodes()
+ huff_counts A pointer to the counts array.
+ end_count A pointer past the counts array.
+
+ DESCRIPTION
+
+ Huffman coding works by removing the two least frequent values from
+ the list of values and add a new value with the sum of their
+ incidences in a loop until only one value is left. Every time a
+ value is reused for a new value, it gets one more bit for its
+ encoding. Hence, the least frequent values get the longest codes.
+
+ To get a maximum code length for a value, two of the values must
+ have an incidence of 1. As their sum is 2, the next infrequent value
+ must have at least an incidence of 2, then 4, 8, 16 and so on. This
+ means that one needs 2**n bytes (values) for a code length of n
+ bits. However, using more distinct values forces the use of longer
+ codes, or reaching the code length with less total bytes (values).
+
+ To get 64(32)-bit codes, I sort the counts by decreasing incidence.
+ I assign counts of 1 to the two most frequent values, a count of 2
+ for the next one, then 4, 8, and so on until 2**64-1(2**30-1). All
+ the remaining values get 1. That way every possible uchar has an
+ assigned code, though not all codes are used if not all uchar values
+ are present in the column.
+
+ This strategy would work with distinct column values too, but
+ requires that at least 64(32) values are present. To make things
+ easier here, I cancel all distinct column values and force byte
+ compression for all columns.
+
+ RETURN
+ void
+*/
+
+static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count)
+{
+ HUFF_COUNTS *count;
+ my_off_t *cur_count_p;
+ my_off_t *end_count_p;
+ my_off_t **cur_sort_p;
+ my_off_t **end_sort_p;
+ my_off_t *sort_counts[256];
+ my_off_t total;
+ DBUG_ENTER("fakebigcodes");
+
+ for (count= huff_counts; count < end_count; count++)
+ {
+ /*
+ Remove distinct column values.
+ */
+ if (huff_counts->tree_buff)
+ {
+ my_free((uchar*) huff_counts->tree_buff, MYF(0));
+ delete_tree(&huff_counts->int_tree);
+ huff_counts->tree_buff= NULL;
+ DBUG_PRINT("fakebigcodes", ("freed distinct column values"));
+ }
+
+ /*
+ Sort counts by decreasing incidence.
+ */
+ cur_count_p= count->counts;
+ end_count_p= cur_count_p + 256;
+ cur_sort_p= sort_counts;
+ while (cur_count_p < end_count_p)
+ *(cur_sort_p++)= cur_count_p++;
+ (void) my_qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp);
+
+ /*
+ Assign faked counts.
+ */
+ cur_sort_p= sort_counts;
+#if SIZEOF_LONG_LONG > 4
+ end_sort_p= sort_counts + 8 * sizeof(ulonglong) - 1;
+#else
+ end_sort_p= sort_counts + 8 * sizeof(ulonglong) - 2;
+#endif
+ /* Most frequent value gets a faked count of 1. */
+ **(cur_sort_p++)= 1;
+ total= 1;
+ while (cur_sort_p < end_sort_p)
+ {
+ **(cur_sort_p++)= total;
+ total<<= 1;
+ }
+ /* Set the last value. */
+ **(cur_sort_p++)= --total;
+ /*
+ Set the remaining counts.
+ */
+ end_sort_p= sort_counts + 256;
+ while (cur_sort_p < end_sort_p)
+ **(cur_sort_p++)= 1;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Compare two counts for reverse sorting.
+
+ SYNOPSIS
+ fakecmp()
+ count1 One count.
+ count2 Another count.
+
+ RETURN
+ 1 count1 < count2
+ 0 count1 == count2
+ -1 count1 > count2
+*/
+
+static int fakecmp(my_off_t **count1, my_off_t **count2)
+{
+ return ((**count1 < **count2) ? 1 :
+ (**count1 > **count2) ? -1 : 0);
+}
+#endif
diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c
new file mode 100644
index 00000000000..2b2fa692f24
--- /dev/null
+++ b/storage/maria/maria_read_log.c
@@ -0,0 +1,278 @@
+/* Copyright (C) 2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "maria_def.h"
+#include "ma_recovery.h"
+#include <my_getopt.h>
+
+#define LOG_FLAGS 0
+
+static const char *load_default_groups[]= { "maria_read_log",0 };
+static void get_options(int *argc,char * * *argv);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+const char *default_dbug_option= "d:t:O,\\maria_read_log.trace";
+#else
+const char *default_dbug_option= "d:t:o,/tmp/maria_read_log.trace";
+#endif
+#endif /* DBUG_OFF */
+static my_bool opt_display_only, opt_apply, opt_apply_undo, opt_silent;
+static my_bool opt_check;
+static const char *opt_tmpdir;
+static ulong opt_page_buffer_size;
+static ulonglong opt_start_from_lsn;
+static MY_TMPDIR maria_chk_tmpdir;
+
+
+int main(int argc, char **argv)
+{
+ LSN lsn;
+ char **default_argv;
+ uint warnings_count;
+ MY_INIT(argv[0]);
+
+ load_defaults("my", load_default_groups, &argc, &argv);
+ default_argv= argv;
+ maria_data_root= (char *)".";
+ get_options(&argc, &argv);
+
+ maria_in_recovery= TRUE;
+
+ if (maria_init())
+ {
+ fprintf(stderr, "Can't init Maria engine (%d)\n", errno);
+ goto err;
+ }
+ /* we don't want to create a control file, it MUST exist */
+ if (ma_control_file_open(FALSE, TRUE))
+ {
+ fprintf(stderr, "Can't open control file (%d)\n", errno);
+ goto err;
+ }
+ if (last_logno == FILENO_IMPOSSIBLE)
+ {
+ fprintf(stderr, "Can't find any log\n");
+ goto err;
+ }
+ if (init_pagecache(maria_pagecache, opt_page_buffer_size, 0, 0,
+ TRANSLOG_PAGE_SIZE, MY_WME) == 0)
+ {
+ fprintf(stderr, "Got error in init_pagecache() (errno: %d)\n", errno);
+ goto err;
+ }
+ /*
+ If log handler does not find the "last_logno" log it will return error,
+ which is good.
+ But if it finds a log and this log was crashed, it will create a new log,
+ which is useless. TODO: start log handler in read-only mode.
+ */
+ if (init_pagecache(maria_log_pagecache,
+ TRANSLOG_PAGECACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, MY_WME) == 0 ||
+ translog_init(maria_data_root, TRANSLOG_FILE_SIZE,
+ 0, 0, maria_log_pagecache, TRANSLOG_DEFAULT_FLAGS,
+ opt_display_only))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ goto err;
+ }
+
+ if (opt_display_only)
+ printf("You are using --display-only, NOTHING will be written to disk\n");
+
+ /* LSN could be also --start-from-lsn=# */
+ lsn= translog_first_lsn_in_log();
+ if (lsn == LSN_ERROR)
+ {
+ fprintf(stderr, "Opening transaction log failed\n");
+ goto end;
+ }
+ if (lsn == LSN_IMPOSSIBLE)
+ {
+ fprintf(stdout, "The transaction log is empty\n");
+ }
+ fprintf(stdout, "The transaction log starts from lsn (%lu,0x%lx)\n",
+ LSN_IN_PARTS(lsn));
+
+ if (opt_start_from_lsn)
+ {
+ if (opt_start_from_lsn < (ulonglong) lsn)
+ {
+ fprintf(stderr, "start_from_lsn is too small. Aborting\n");
+ maria_end();
+ goto err;
+ }
+ lsn= (LSN) opt_start_from_lsn;
+ fprintf(stdout, "Starting reading log from lsn (%lu,0x%lx)\n",
+ LSN_IN_PARTS(lsn));
+ }
+
+ fprintf(stdout, "TRACE of the last maria_read_log\n");
+ if (maria_apply_log(lsn, opt_apply ? MARIA_LOG_APPLY :
+ (opt_check ? MARIA_LOG_CHECK :
+ MARIA_LOG_DISPLAY_HEADER), opt_silent ? NULL : stdout,
+ opt_apply_undo, FALSE, FALSE, &warnings_count))
+ goto err;
+ if (warnings_count == 0)
+ fprintf(stdout, "%s: SUCCESS\n", my_progname_short);
+ else
+ fprintf(stdout, "%s: DOUBTFUL (%u warnings, check previous output)\n",
+ my_progname_short, warnings_count);
+
+end:
+ maria_end();
+ free_tmpdir(&maria_chk_tmpdir);
+ free_defaults(default_argv);
+ my_end(0);
+ exit(0);
+ return 0; /* No compiler warning */
+
+err:
+ /* don't touch anything more, in case we hit a bug */
+ fprintf(stderr, "%s: FAILED\n", my_progname_short);
+ free_tmpdir(&maria_chk_tmpdir);
+ free_defaults(default_argv);
+ exit(1);
+}
+
+
+#include "ma_check_standalone.h"
+
+
+static struct my_option my_long_options[] =
+{
+ {"apply", 'a',
+ "Apply log to tables: modifies tables! you should make a backup first! "
+ " Displays a lot of information if not run with --silent",
+ (uchar **) &opt_apply, (uchar **) &opt_apply, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"check", 'c',
+ "if --display-only, check if record is fully readable (for debugging)",
+ (uchar **) &opt_check, (uchar **) &opt_check, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifndef DBUG_OFF
+ {"debug", '#', "Output debug log. Often the argument is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"help", '?', "Display this help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"display-only", 'd', "display brief info read from records' header",
+ (uchar **) &opt_display_only, (uchar **) &opt_display_only, 0, GET_BOOL,
+ NO_ARG,0, 0, 0, 0, 0, 0},
+ {"maria_log_dir_path", 'l',
+ "Path to the directory where to store transactional log",
+ (uchar **) &maria_data_root, (uchar **) &maria_data_root, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ { "page_buffer_size", 'P', "",
+ (uchar**) &opt_page_buffer_size, (uchar**) &opt_page_buffer_size, 0,
+ GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT,
+ (long) USE_BUFFER_INIT, (long) ~(ulong) 0, (long) MALLOC_OVERHEAD,
+ (long) IO_SIZE, 0},
+ { "start_from_lsn", 'o', "Start reading log from this lsn",
+ (uchar**) &opt_start_from_lsn, (uchar**) &opt_start_from_lsn,
+ 0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 },
+ {"silent", 's', "Print less information during apply/undo phase",
+ (uchar **) &opt_silent, (uchar **) &opt_silent, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"tmpdir", 't', "Path for temporary files. Multiple paths can be specified, "
+ "separated by "
+#if defined( __WIN__) || defined(__NETWARE__)
+ "semicolon (;)"
+#else
+ "colon (:)"
+#endif
+ , (uchar**) &opt_tmpdir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"undo", 'u', "Apply UNDO records to tables. (disable with --disable-undo)",
+ (uchar **) &opt_apply_undo, (uchar **) &opt_apply_undo, 0,
+ GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+#include <help_start.h>
+
+static void print_version(void)
+{
+ VOID(printf("%s Ver 1.2 for %s on %s\n",
+ my_progname_short, SYSTEM_TYPE, MACHINE_TYPE));
+ NETWARE_SET_SCREEN_MODE(1);
+}
+
+
+static void usage(void)
+{
+ print_version();
+ puts("Copyright (C) 2007 MySQL AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
+ puts("and you are welcome to modify and redistribute it under the GPL license\n");
+
+ puts("Display and apply log records from a MARIA transaction log");
+ puts("found in the current directory (for now)");
+#ifndef IDENTICAL_PAGES_AFTER_RECOVERY
+ puts("\nNote: Maria is compiled without -DIDENTICAL_PAGES_AFTER_RECOVERY\n"
+ "which means that the table files are not byte-to-byte identical to\n"
+ "files created during normal execution. This should be ok, except for\n"
+ "test scripts that tries to compare files before and after recovery.");
+#endif
+ VOID(printf("\nUsage: %s OPTIONS\n", my_progname_short));
+ puts("You need to use one of -d or -a");
+ my_print_help(my_long_options);
+ print_defaults("my", load_default_groups);
+ my_print_variables(my_long_options);
+}
+
+#include <help_end.h>
+
+static my_bool
+get_one_option(int optid __attribute__((unused)),
+ const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch (optid) {
+ case '?':
+ usage();
+ exit(0);
+ case 'V':
+ print_version();
+ exit(0);
+#ifndef DBUG_OFF
+ case '#':
+ DBUG_SET_INITIAL(argument ? argument : default_dbug_option);
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void get_options(int *argc,char ***argv)
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ if (!opt_apply)
+ opt_apply_undo= FALSE;
+
+ if (((opt_display_only + opt_apply) != 1) || (*argc > 0))
+ {
+ usage();
+ exit(1);
+ }
+ if (init_tmpdir(&maria_chk_tmpdir, opt_tmpdir))
+ exit(1);
+ maria_tmpdir= &maria_chk_tmpdir;
+}
diff --git a/storage/maria/maria_rename.sh b/storage/maria/maria_rename.sh
new file mode 100755
index 00000000000..fb20e47e635
--- /dev/null
+++ b/storage/maria/maria_rename.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+replace myisam maria MYISAM MARIA MyISAM MARIA -- mysql-test/t/*maria*test mysql-test/r/*maria*result
+
+FILES=`echo sql/ha_maria.{cc,h} include/maria*h storage/maria/*.{c,h}`
+
+replace myisam maria MYISAM MARIA MyISAM MARIA myisam.h maria.h myisamdef.h maria_def.h mi_ maria_ ft_ maria_ft_ "Copyright (C) 2000" "Copyright (C) 2006" MI_ISAMINFO MARIA_INFO MI_CREATE_INFO MARIA_CREATE_INFO maria_isam_ maria_ MI_INFO MARIA_HA MI_ MARIA_ MARIACHK MARIA_CHK rt_index.h ma_rt_index.h rtree_ maria_rtree rt_key.h ma_rt_key.h rt_mbr.h ma_rt_mbr.h -- $FILES
+
+replace check_table_is_closed _ma_check_table_is_closed test_if_reopen _ma_test_if_reopen my_n_base_info_read maria_n_base_info_read update_auto_increment _ma_update_auto_increment save_pack_length _ma_save_packlength calc_pack_length _ma_calc_pack_length -- $FILES
+
+replace mi_ ma_ ft_ ma_ft_ rt_ ma_rt_ myisam maria myisamchk maria_chk myisampack maria_pack myisamlog maria_log -- storage/maria/Makefile.am
+
+#
+# Restore wrong replaces
+#
+
+replace maria_sint1korr mi_sint1korr maria_uint1korr mi_uint1korr maria_sint2korr mi_sint2korr maria_sint3korr mi_sint3korr maria_sint4korr mi_sint4korr maria_sint8korr mi_sint8korr maria_uint2korr mi_uint2korr maria_uint3korr mi_uint3korr maria_uint4korr mi_uint4korr maria_uint5korr mi_uint5korr maria_uint6korr mi_uint6korr maria_uint7korr mi_uint7korr maria_uint8korr mi_uint8korr maria_int1store mi_int1store maria_int2store mi_int2store maria_int3store mi_int3store maria_int4store mi_int4store maria_int5store mi_int5store maria_int6store mi_int6store maria_int7store mi_int7store maria_int8store mi_int8store maria_float4store mi_float4store maria_float4get mi_float4get maria_float8store mi_float8store maria_float8get mi_float8get maria_rowstore mi_rowstore maria_rowkorr mi_rowkorr maria_sizestore mi_sizestore maria_sizekorr mi_sizekorr _maria_maria_ _maria MARIA_MAX_POSSIBLE_KEY HA_MAX_POSSIBLE_KEY MARIA_MAX_KEY_BUFF HA_MAX_KEY_BUFF MARIA_MAX_KEY_SEG HA_MAX_KEY_SEG maria_ft_sintXkorr ft_sintXkorr maria_ft_intXstore ft_intXstore maria_ft_boolean_syntax ft_boolean_syntax maria_ft_min_word_len ft_min_word_len maria_ft_max_word_len ft_max_word_len -- $FILES
diff --git a/storage/maria/plug.in b/storage/maria/plug.in
new file mode 100644
index 00000000000..02a6466bddc
--- /dev/null
+++ b/storage/maria/plug.in
@@ -0,0 +1,21 @@
+MYSQL_STORAGE_ENGINE(maria,, [Maria Storage Engine],
+ [Crash-safe tables with MyISAM heritage], [default,max,max-no-ndb])
+MYSQL_PLUGIN_DIRECTORY(maria, [storage/maria])
+MYSQL_PLUGIN_STATIC(maria, [libmaria.a])
+# Maria will probably go first into max builds, not all builds,
+# so we don't declare it mandatory.
+MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(maria, [ha_maria.cc])
+
+MYSQL_PLUGIN_ACTIONS(maria, [
+AC_CONFIG_FILES(storage/maria/unittest/Makefile)
+AC_ARG_WITH(maria-tmp-tables,
+ AC_HELP_STRING([--with-maria-tmp-tables],[Use Maria for internal temporary tables]),
+ [with_maria_tmp_tables=$withval],
+ [with_maria_tmp_tables=yes]
+)
+
+if test "$with_maria_tmp_tables" = "yes"
+then
+ AC_DEFINE([USE_MARIA_FOR_TMP_TABLES], [1], [Maria is used for internal temporary tables])
+fi
+])
diff --git a/storage/maria/tablockman.c b/storage/maria/tablockman.c
new file mode 100644
index 00000000000..1bb8889aaa7
--- /dev/null
+++ b/storage/maria/tablockman.c
@@ -0,0 +1,674 @@
+/* QQ: TODO - allocate everything from dynarrays !!! (benchmark) */
+/* QQ: automatically place S instead of LS if possible */
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_base.h>
+#include <hash.h>
+#include "tablockman.h"
+
+/*
+ Lock Manager for Table Locks
+
+ The code below handles locks on resources - but it is optimized for a
+ case when a number of resources is not very large, and there are many of
+ locks per resource - that is a resource is likely to be a table or a
+ database, but hardly a row in a table.
+
+ Locks belong to "lock owners". A Lock Owner is uniquely identified by a
+ 16-bit number - loid (lock owner identifier). A function loid_to_tlo must
+ be provided by the application that takes such a number as an argument
+ and returns a TABLE_LOCK_OWNER structure.
+
+ Lock levels are completely defined by three tables. Lock compatibility
+ matrix specifies which locks can be held at the same time on a resource.
+ Lock combining matrix specifies what lock level has the same behaviour as
+ a pair of two locks of given levels. getlock_result matrix simplifies
+ intention locking and lock escalation for an application, basically it
+ defines which locks are intention locks and which locks are "loose"
+ locks. It is only used to provide better diagnostics for the
+ application, lock manager itself does not differentiate between normal,
+ intention, and loose locks.
+
+ The assumptions are: few distinct resources, many locks are held at the
+ same time on one resource. Thus: a lock structure _per resource_ can be
+ rather large; a lock structure _per lock_ does not need to be very small
+ either; we need to optimize for _speed_. Operations we need are: place a
+ lock, check if a particular transaction already has a lock on this
+ resource, check if a conflicting lock exists, if yes - find who owns it.
+
+ Solution: every resource has a structure with
+ 1. Hash of latest (see the lock upgrade section below) granted locks with
+ loid as a key. Thus, checking if a given transaction has a lock on
+ this resource is O(1) operation.
+ 2. Doubly-linked lists of all granted locks - one list for every lock
+ type. Thus, checking if a conflicting lock exists is a check whether
+ an appropriate list head pointer is not null, also O(1).
+ 3. Every lock has a loid of the owner, thus checking who owns a
+ conflicting lock is also O(1).
+ 4. Deque of waiting locks. It's a deque (double-ended queue) not a fifo,
+ because for lock upgrades requests are added to the queue head, not
+ tail. This is a single place where there it gets O(N) on number
+ of locks - when a transaction wakes up from waiting on a condition,
+ it may need to scan the queue backward to the beginning to find
+ a conflicting lock. It is guaranteed though that "all transactions
+ before it" received the same - or earlier - signal. In other words a
+ transaction needs to scan all transactions before it that received the
+ signal but didn't have a chance to resume the execution yet, so
+ practically OS scheduler won't let the scan to be O(N).
+
+ Waiting: if there is a conflicting lock or if wait queue is not empty, a
+ requested lock cannot be granted at once. It is added to the end of the
+ wait queue. If a queue was empty and there is a conflicting lock - the
+ "blocker" transaction is the owner of this lock. If a queue is not empty,
+ an owner of the previous lock in the queue is the "blocker". But if the
+ previous lock is compatible with the request, then the "blocker" is the
+ transaction that the owner of the lock at the end of the queue is waiting
+ for (in other words, our lock is added to the end of the wait queue, and
+ our blocker is the same as of the lock right before us).
+
+ Lock upgrades: when a thread that has a lock on a given resource,
+ requests a new lock on the same resource and the old lock is not enough
+ to satisfy new lock requirements (which is defined by
+ lock_combining_matrix[old_lock][new_lock] != old_lock), a new lock
+ (defined by lock_combining_matrix as above) is placed. Depending on
+ other granted locks it is immediately granted or it has to wait. Here the
+ lock is added to the start of the waiting queue, not to the end. Old
+ lock, is removed from the hash, but not from the doubly-linked lists.
+ (indeed, a transaction checks "do I have a lock on this resource ?" by
+ looking in a hash, and it should find a latest lock, so old locks must be
+ removed; but a transaction checks "are there conflicting locks ?" by
+ checking doubly-linked lists, it doesn't matter if it will find an old
+ lock - if it would be removed, a new lock would be also a conflict).
+ So, a hash contains only "latest" locks - there can be only one latest
+ lock per resource per transaction. But doubly-linked lists contain all
+ locks, even "obsolete" ones, because it doesnt't hurt. Note that old
+ locks can not be freed early, in particular they stay in the
+ 'active_locks' list of a lock owner, because they may be "re-enabled"
+ on a savepoint rollback.
+
+ To better support table-row relations where one needs to lock the table
+ with an intention lock before locking the row, extended diagnostics is
+ provided. When an intention lock (presumably on a table) is granted,
+ lockman_getlock() returns one of GOT_THE_LOCK (no need to lock the row,
+ perhaps the thread already has a normal lock on this table),
+ GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE (need to lock the row, as usual),
+ GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE (only need to check
+ whether it's possible to lock the row, but no need to lock it - perhaps
+ the thread has a loose lock on this table). This is defined by
+ getlock_result[] table.
+
+ Instant duration locks are not supported. Though they're trivial to add,
+ they are normally only used on rows, not on tables. So, presumably,
+ they are not needed here.
+
+ Mutexes: there're table mutexes (LOCKED_TABLE::mutex), lock owner mutexes
+ (TABLE_LOCK_OWNER::mutex), and a pool mutex (TABLOCKMAN::pool_mutex).
+ table mutex protects operations on the table lock structures, and lock
+ owner pointers waiting_for and waiting_for_loid.
+ lock owner mutex is only used to wait on lock owner condition
+ (TABLE_LOCK_OWNER::cond), there's no need to protect owner's lock
+ structures, and only lock owner itself may access them.
+ The pool mutex protects a pool of unused locks. Note the locking order:
+ first the table mutex, then the owner mutex or a pool mutex.
+ Table mutex lock cannot be attempted when owner or pool mutex are locked.
+ No mutex lock can be attempted if owner or pool mutex are locked.
+*/
+
+/*
+ Lock compatibility matrix.
+
+ It's asymmetric. Read it as "Somebody has the lock <value in the row
+ label>, can I set the lock <value in the column label> ?"
+
+ ') Though you can take LS lock while somebody has S lock, it makes no
+ sense - it's simpler to take S lock too.
+
+ 1 - compatible
+ 0 - incompatible
+ -1 - "impossible", so that we can assert the impossibility.
+*/
+static const int lock_compatibility_matrix[10][10]=
+{ /* N S X IS IX SIX LS LX SLX LSIX */
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* N */
+ { -1, 1, 0, 1, 0, 0, 1, 0, 0, 0 }, /* S */
+ { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* X */
+ { -1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, /* IS */
+ { -1, 0, 0, 1, 1, 0, 1, 1, 0, 1 }, /* IX */
+ { -1, 0, 0, 1, 0, 0, 1, 0, 0, 0 }, /* SIX */
+ { -1, 1, 0, 1, 0, 0, 1, 0, 0, 0 }, /* LS */
+ { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* LX */
+ { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* SLX */
+ { -1, 0, 0, 1, 0, 0, 1, 0, 0, 0 } /* LSIX */
+};
+
+/*
+ Lock combining matrix.
+
+ It's symmetric. Read it as "what lock level L is identical to the
+ set of two locks A and B"
+
+ One should never get N from it, we assert the impossibility
+*/
+static const enum lockman_lock_type lock_combining_matrix[10][10]=
+{/* N S X IS IX SIX LS LX SLX LSIX */
+ { N, N, N, N, N, N, N, N, N, N}, /* N */
+ { N, S, X, S, SIX, SIX, S, SLX, SLX, SIX}, /* S */
+ { N, X, X, X, X, X, X, X, X, X}, /* X */
+ { N, S, X, IS, IX, SIX, LS, LX, SLX, LSIX}, /* IS */
+ { N, SIX, X, IX, IX, SIX, LSIX, LX, SLX, LSIX}, /* IX */
+ { N, SIX, X, SIX, SIX, SIX, SIX, SLX, SLX, SIX}, /* SIX */
+ { N, S, X, LS, LSIX, SIX, LS, LX, SLX, LSIX}, /* LS */
+ { N, SLX, X, LX, LX, SLX, LX, LX, SLX, LX}, /* LX */
+ { N, SLX, X, SLX, SLX, SLX, SLX, SLX, SLX, SLX}, /* SLX */
+ { N, SIX, X, LSIX, LSIX, SIX, LSIX, LX, SLX, LSIX} /* LSIX */
+};
+
+/*
+ the return codes for lockman_getlock
+
+ It's asymmetric. Read it as "I have the lock <value in the row label>,
+ what value should be returned for <value in the column label> ?"
+
+ 0 means impossible combination (assert!)
+
+ Defines below help to preserve the table structure.
+ I/L/A values are self explanatory
+ x means the combination is possible (assert should not crash)
+ but it cannot happen in row locks, only in table locks (S,X),
+ or lock escalations (LS,LX)
+*/
+#define I GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE
+#define L GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE
+#define A GOT_THE_LOCK
+#define x GOT_THE_LOCK
+static const enum lockman_getlock_result getlock_result[10][10]=
+{/* N S X IS IX SIX LS LX SLX LSIX */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* N */
+ { 0, x, 0, A, 0, 0, x, 0, 0, 0}, /* S */
+ { 0, x, x, A, A, 0, x, x, 0, 0}, /* X */
+ { 0, 0, 0, I, 0, 0, 0, 0, 0, 0}, /* IS */
+ { 0, 0, 0, I, I, 0, 0, 0, 0, 0}, /* IX */
+ { 0, x, 0, A, I, 0, x, 0, 0, 0}, /* SIX */
+ { 0, 0, 0, L, 0, 0, x, 0, 0, 0}, /* LS */
+ { 0, 0, 0, L, L, 0, x, x, 0, 0}, /* LX */
+ { 0, x, 0, A, L, 0, x, x, 0, 0}, /* SLX */
+ { 0, 0, 0, L, I, 0, x, 0, 0, 0} /* LSIX */
+};
+#undef I
+#undef L
+#undef A
+#undef x
+
+/*
+ this structure is optimized for a case when there're many locks
+ on the same resource - e.g. a table
+*/
+
+struct st_table_lock {
+ /* QQ: do we need upgraded_from ? */
+ struct st_table_lock *next_in_lo, *upgraded_from, *next, *prev;
+ struct st_locked_table *table;
+ uint16 loid;
+ uchar lock_type;
+};
+
+#define hash_insert my_hash_insert /* for consistency :) */
+
+static inline
+TABLE_LOCK *find_by_loid(LOCKED_TABLE *table, uint16 loid)
+{
+ return (TABLE_LOCK *)hash_search(& table->latest_locks,
+ (uchar *)& loid, sizeof(loid));
+}
+
+static inline
+void remove_from_wait_queue(TABLE_LOCK *lock, LOCKED_TABLE *table)
+{
+ DBUG_ASSERT(table == lock->table);
+ if (lock->prev)
+ {
+ DBUG_ASSERT(table->wait_queue_out != lock);
+ lock->prev->next= lock->next;
+ }
+ else
+ {
+ DBUG_ASSERT(table->wait_queue_out == lock);
+ table->wait_queue_out= lock->next;
+ }
+ if (lock->next)
+ {
+ DBUG_ASSERT(table->wait_queue_in != lock);
+ lock->next->prev= lock->prev;
+ }
+ else
+ {
+ DBUG_ASSERT(table->wait_queue_in == lock);
+ table->wait_queue_in= lock->prev;
+ }
+}
+
+/*
+ DESCRIPTION
+ tries to lock a resource 'table' with a lock level 'lock'.
+
+ RETURN
+ see enum lockman_getlock_result
+*/
+enum lockman_getlock_result
+tablockman_getlock(TABLOCKMAN *lm, TABLE_LOCK_OWNER *lo,
+ LOCKED_TABLE *table, enum lockman_lock_type lock)
+{
+ TABLE_LOCK *old, *new, *blocker, *blocker2;
+ TABLE_LOCK_OWNER *wait_for;
+ struct timespec timeout;
+ enum lockman_lock_type new_lock;
+ enum lockman_getlock_result res;
+ int i;
+
+ DBUG_ASSERT(lo->waiting_lock == 0);
+ DBUG_ASSERT(lo->waiting_for == 0);
+ DBUG_ASSERT(lo->waiting_for_loid == 0);
+
+ pthread_mutex_lock(& table->mutex);
+ /* do we already have a lock on this resource ? */
+ old= find_by_loid(table, lo->loid);
+
+ /* calculate the level of the upgraded lock, if yes */
+ new_lock= old ? lock_combining_matrix[old->lock_type][lock] : lock;
+
+ /* and check if old lock is enough to satisfy the new request */
+ if (old && new_lock == old->lock_type)
+ {
+ /* yes */
+ res= getlock_result[old->lock_type][lock];
+ goto ret;
+ }
+
+ /* no, placing a new lock. first - take a free lock structure from the pool */
+ pthread_mutex_lock(& lm->pool_mutex);
+ new= lm->pool;
+ if (new)
+ {
+ lm->pool= new->next;
+ pthread_mutex_unlock(& lm->pool_mutex);
+ }
+ else
+ {
+ pthread_mutex_unlock(& lm->pool_mutex);
+ new= (TABLE_LOCK *)my_malloc(sizeof(*new), MYF(MY_WME));
+ if (unlikely(!new))
+ {
+ res= NO_MEMORY_FOR_LOCK;
+ goto ret;
+ }
+ }
+
+ new->loid= lo->loid;
+ new->lock_type= new_lock;
+ new->table= table;
+
+ /* and try to place it */
+ for (new->prev= table->wait_queue_in;;)
+ {
+ wait_for= 0;
+ if (!old)
+ {
+ /* not upgrading - a lock must be added to the _end_ of the wait queue */
+ for (blocker= new->prev; blocker && !wait_for; blocker= blocker->prev)
+ {
+ TABLE_LOCK_OWNER *tmp= lm->loid_to_tlo(blocker->loid);
+
+ /* find a blocking lock */
+ DBUG_ASSERT(table->wait_queue_out);
+ DBUG_ASSERT(table->wait_queue_in);
+ if (!lock_compatibility_matrix[blocker->lock_type][lock])
+ {
+ /* found! */
+ wait_for= tmp;
+ break;
+ }
+
+ /*
+ hmm, the lock before doesn't block us, let's look one step further.
+ the condition below means:
+
+ if we never waited on a condition yet
+ OR
+ the lock before ours (blocker) waits on a lock (blocker2) that is
+ present in the hash AND and conflicts with 'blocker'
+
+ the condition after OR may fail if 'blocker2' was removed from
+ the hash, its signal woke us up, but 'blocker' itself didn't see
+ the signal yet.
+ */
+ if (!lo->waiting_lock ||
+ ((blocker2= find_by_loid(table, tmp->waiting_for_loid)) &&
+ !lock_compatibility_matrix[blocker2->lock_type]
+ [blocker->lock_type]))
+ {
+ /* but it's waiting for a real lock. we'll wait for the same lock */
+ wait_for= tmp->waiting_for;
+ /*
+ We don't really need tmp->waiting_for, as tmp->waiting_for_loid
+ is enough. waiting_for is just a local cache to avoid calling
+ loid_to_tlo().
+ But it's essensial that tmp->waiting_for pointer can ONLY
+ be dereferenced if find_by_loid() above returns a non-null
+ pointer, because a TABLE_LOCK_OWNER object that it points to
+ may've been freed when we come here after a signal.
+ In particular tmp->waiting_for_loid cannot be replaced
+ with tmp->waiting_for->loid.
+ */
+ DBUG_ASSERT(wait_for == lm->loid_to_tlo(tmp->waiting_for_loid));
+ break;
+ }
+
+ /*
+ otherwise - a lock it's waiting for doesn't exist.
+ We've no choice but to scan the wait queue backwards, looking
+ for a conflicting lock or a lock waiting for a real lock.
+ QQ is there a way to avoid this scanning ?
+ */
+ }
+ }
+
+ if (wait_for == 0)
+ {
+ /* checking for compatibility with existing locks */
+ for (blocker= 0, i= 0; i < LOCK_TYPES; i++)
+ {
+ if (table->active_locks[i] && !lock_compatibility_matrix[i+1][lock])
+ {
+ blocker= table->active_locks[i];
+ /* if the first lock in the list is our own - skip it */
+ if (blocker->loid == lo->loid)
+ blocker= blocker->next;
+ if (blocker) /* found a conflicting lock, need to wait */
+ break;
+ }
+ }
+ if (!blocker) /* free to go */
+ break;
+ wait_for= lm->loid_to_tlo(blocker->loid);
+ }
+
+ /* ok, we're here - the wait is inevitable */
+ lo->waiting_for= wait_for;
+ lo->waiting_for_loid= wait_for->loid;
+ if (!lo->waiting_lock) /* first iteration of the for() loop */
+ {
+ /* lock upgrade or new lock request ? */
+ if (old)
+ {
+ /* upgrade - add the lock to the _start_ of the wait queue */
+ new->prev= 0;
+ if ((new->next= table->wait_queue_out))
+ new->next->prev= new;
+ table->wait_queue_out= new;
+ if (!table->wait_queue_in)
+ table->wait_queue_in= table->wait_queue_out;
+ }
+ else
+ {
+ /* new lock - add the lock to the _end_ of the wait queue */
+ new->next= 0;
+ if ((new->prev= table->wait_queue_in))
+ new->prev->next= new;
+ table->wait_queue_in= new;
+ if (!table->wait_queue_out)
+ table->wait_queue_out= table->wait_queue_in;
+ }
+ lo->waiting_lock= new;
+
+ set_timespec_nsec(timeout,lm->lock_timeout * 1000000);
+
+ }
+
+ /*
+ prepare to wait.
+ we must lock blocker's mutex to wait on blocker's cond.
+ and we must release table's mutex.
+ note that blocker's mutex is locked _before_ table's mutex is released
+ */
+ pthread_mutex_lock(wait_for->mutex);
+ pthread_mutex_unlock(& table->mutex);
+
+ /* now really wait */
+ i= pthread_cond_timedwait(wait_for->cond, wait_for->mutex, & timeout);
+
+ pthread_mutex_unlock(wait_for->mutex);
+
+ if (i == ETIMEDOUT || i == ETIME)
+ {
+ /* we rely on the caller to rollback and release all locks */
+ res= LOCK_TIMEOUT;
+ goto ret2;
+ }
+
+ pthread_mutex_lock(& table->mutex);
+
+ /* ... and repeat from the beginning */
+ }
+ /* yeah! we can place the lock now */
+
+ /* remove the lock from the wait queue, if it was there */
+ if (lo->waiting_lock)
+ {
+ remove_from_wait_queue(new, table);
+ lo->waiting_lock= 0;
+ lo->waiting_for= 0;
+ lo->waiting_for_loid= 0;
+ }
+
+ /* add it to the list of all locks of this lock owner */
+ new->next_in_lo= lo->active_locks;
+ lo->active_locks= new;
+
+ /* and to the list of active locks of this lock type */
+ new->prev= 0;
+ if ((new->next= table->active_locks[new_lock-1]))
+ new->next->prev= new;
+ table->active_locks[new_lock-1]= new;
+
+ /* update the latest_locks hash */
+ if (old)
+ hash_delete(& table->latest_locks, (uchar *)old);
+ hash_insert(& table->latest_locks, (uchar *)new);
+
+ new->upgraded_from= old;
+
+ res= getlock_result[lock][lock];
+
+ret:
+ pthread_mutex_unlock(& table->mutex);
+ret2:
+ DBUG_ASSERT(res);
+ return res;
+}
+
+/*
+ DESCRIPTION
+ release all locks belonging to a transaction.
+ signal waiters to continue
+*/
+void tablockman_release_locks(TABLOCKMAN *lm, TABLE_LOCK_OWNER *lo)
+{
+ TABLE_LOCK *lock, *local_pool= 0, *local_pool_end;
+
+ /*
+ instead of adding released locks to a pool one by one, we'll link
+ them in a list and add to a pool in one short action (under a mutex)
+ */
+ local_pool_end= lo->waiting_lock ? lo->waiting_lock : lo->active_locks;
+ if (!local_pool_end)
+ return;
+
+ /* release a waiting lock, if any */
+ if ((lock= lo->waiting_lock))
+ {
+ DBUG_ASSERT(lock->loid == lo->loid);
+ pthread_mutex_lock(& lock->table->mutex);
+ remove_from_wait_queue(lock, lock->table);
+
+ /*
+ a special case: if this lock was not the last in the wait queue
+ and it's compatible with the next lock, than the next lock
+ is waiting for our blocker though really it waits for us, indirectly.
+ Signal our blocker to release this next lock (after we removed our
+ lock from the wait queue, of course).
+ */
+ /*
+ An example to clarify the above:
+ trn1> S-lock the table. Granted.
+ trn2> IX-lock the table. Added to the wait queue. trn2 waits on trn1
+ trn3> IS-lock the table. The queue is not empty, so IS-lock is added
+ to the queue. It's compatible with the waiting IX-lock, so trn3
+ waits for trn2->waiting_for, that is trn1.
+ if trn1 releases the lock it signals trn1->cond and both waiting
+ transactions are awaken. But if trn2 times out, trn3 must be notified
+ too (as IS and S locks are compatible). So trn2 must signal trn1->cond.
+ */
+ if (lock->next &&
+ lock_compatibility_matrix[lock->next->lock_type][lock->lock_type])
+ {
+ pthread_mutex_lock(lo->waiting_for->mutex);
+ pthread_cond_broadcast(lo->waiting_for->cond);
+ pthread_mutex_unlock(lo->waiting_for->mutex);
+ }
+ lo->waiting_for= 0;
+ lo->waiting_for_loid= 0;
+ pthread_mutex_unlock(& lock->table->mutex);
+
+ lock->next= local_pool;
+ local_pool= lock;
+ }
+
+ /* now release granted locks */
+ lock= lo->active_locks;
+ while (lock)
+ {
+ TABLE_LOCK *cur= lock;
+ pthread_mutex_t *mutex= & lock->table->mutex;
+ DBUG_ASSERT(cur->loid == lo->loid);
+
+ DBUG_ASSERT(lock != lock->next_in_lo);
+ lock= lock->next_in_lo;
+
+ /* TODO ? group locks by table to reduce the number of mutex locks */
+ pthread_mutex_lock(mutex);
+ hash_delete(& cur->table->latest_locks, (uchar *)cur);
+
+ if (cur->prev)
+ cur->prev->next= cur->next;
+ if (cur->next)
+ cur->next->prev= cur->prev;
+ if (cur->table->active_locks[cur->lock_type-1] == cur)
+ cur->table->active_locks[cur->lock_type-1]= cur->next;
+
+ cur->next= local_pool;
+ local_pool= cur;
+
+ pthread_mutex_unlock(mutex);
+ }
+
+ lo->waiting_lock= lo->active_locks= 0;
+
+ /*
+ okay, all locks released. now signal that we're leaving,
+ in case somebody's waiting for it
+ */
+ pthread_mutex_lock(lo->mutex);
+ pthread_cond_broadcast(lo->cond);
+ pthread_mutex_unlock(lo->mutex);
+
+ /* and push all freed locks to the lockman's pool */
+ pthread_mutex_lock(& lm->pool_mutex);
+ local_pool_end->next= lm->pool;
+ lm->pool= local_pool;
+ pthread_mutex_unlock(& lm->pool_mutex);
+}
+
+void tablockman_init(TABLOCKMAN *lm, loid_to_tlo_func *func, uint timeout)
+{
+ lm->pool= 0;
+ lm->loid_to_tlo= func;
+ lm->lock_timeout= timeout;
+ pthread_mutex_init(& lm->pool_mutex, MY_MUTEX_INIT_FAST);
+ my_getsystime(); /* ensure that my_getsystime() is initialized */
+}
+
+void tablockman_destroy(TABLOCKMAN *lm)
+{
+ while (lm->pool)
+ {
+ TABLE_LOCK *tmp= lm->pool;
+ lm->pool= tmp->next;
+ my_free((void *)tmp, MYF(0));
+ }
+ pthread_mutex_destroy(& lm->pool_mutex);
+}
+
+/*
+ initialize a LOCKED_TABLE structure
+
+ SYNOPSYS
+ lt a LOCKED_TABLE to initialize
+ initial_hash_size initial size for 'latest_locks' hash
+*/
+void tablockman_init_locked_table(LOCKED_TABLE *lt, int initial_hash_size)
+{
+ bzero(lt, sizeof(*lt));
+ pthread_mutex_init(& lt->mutex, MY_MUTEX_INIT_FAST);
+ hash_init(& lt->latest_locks, & my_charset_bin, initial_hash_size,
+ offsetof(TABLE_LOCK, loid),
+ sizeof(((TABLE_LOCK*)0)->loid), 0, 0, 0);
+}
+
+void tablockman_destroy_locked_table(LOCKED_TABLE *lt)
+{
+ int i;
+
+ DBUG_ASSERT(lt->wait_queue_out == 0);
+ DBUG_ASSERT(lt->wait_queue_in == 0);
+ DBUG_ASSERT(lt->latest_locks.records == 0);
+ for (i= 0; i<LOCK_TYPES; i++)
+ DBUG_ASSERT(lt->active_locks[i] == 0);
+
+ hash_free(& lt->latest_locks);
+ pthread_mutex_destroy(& lt->mutex);
+}
+
+#ifdef EXTRA_DEBUG
+static const char *lock2str[LOCK_TYPES+1]= {"N", "S", "X", "IS", "IX", "SIX",
+ "LS", "LX", "SLX", "LSIX"};
+
+void tablockman_print_tlo(TABLE_LOCK_OWNER *lo)
+{
+ TABLE_LOCK *lock;
+
+ printf("lo%d>", lo->loid);
+ if ((lock= lo->waiting_lock))
+ printf(" (%s.0x%lx)", lock2str[lock->lock_type], (ulong)lock->table);
+ for (lock= lo->active_locks;
+ lock && lock != lock->next_in_lo;
+ lock= lock->next_in_lo)
+ printf(" %s.0x%lx", lock2str[lock->lock_type], (ulong)lock->table);
+ if (lock && lock == lock->next_in_lo)
+ printf("!");
+ printf("\n");
+}
+#endif
+
diff --git a/storage/maria/tablockman.h b/storage/maria/tablockman.h
new file mode 100644
index 00000000000..e33d1aa44e8
--- /dev/null
+++ b/storage/maria/tablockman.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _tablockman_h
+#define _tablockman_h
+
+/*
+ Lock levels:
+ ^^^^^^^^^^^
+
+ N - "no lock", not a lock, used sometimes internally to simplify the code
+ S - Shared
+ X - eXclusive
+ IS - Intention Shared
+ IX - Intention eXclusive
+ SIX - Shared + Intention eXclusive
+ LS - Loose Shared
+ LX - Loose eXclusive
+ SLX - Shared + Loose eXclusive
+ LSIX - Loose Shared + Intention eXclusive
+*/
+#ifndef _lockman_h
+/* QQ: TODO remove N-locks */
+enum lockman_lock_type { N, S, X, IS, IX, SIX, LS, LX, SLX, LSIX, LOCK_TYPE_LAST };
+enum lockman_getlock_result {
+ NO_MEMORY_FOR_LOCK=1, DEADLOCK, LOCK_TIMEOUT,
+ GOT_THE_LOCK,
+ GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE,
+ GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE
+};
+#endif
+
+#define LOCK_TYPES (LOCK_TYPE_LAST-1)
+
+typedef struct st_table_lock TABLE_LOCK;
+
+typedef struct st_table_lock_owner {
+ TABLE_LOCK *active_locks; /* list of active locks */
+ TABLE_LOCK *waiting_lock; /* waiting lock (one lock only) */
+ struct st_table_lock_owner *waiting_for; /* transaction we're waiting for */
+ pthread_cond_t *cond; /* transactions waiting for us, wait on 'cond' */
+ pthread_mutex_t *mutex; /* mutex is required to use 'cond' */
+ uint16 loid, waiting_for_loid; /* Lock Owner IDentifier */
+} TABLE_LOCK_OWNER;
+
+typedef struct st_locked_table {
+ pthread_mutex_t mutex; /* mutex for everything below */
+ HASH latest_locks; /* latest locks in a hash */
+ TABLE_LOCK *active_locks[LOCK_TYPES]; /* dl-list of locks per type */
+ TABLE_LOCK *wait_queue_in, *wait_queue_out; /* wait deque (double-end queue)*/
+} LOCKED_TABLE;
+
+typedef TABLE_LOCK_OWNER *loid_to_tlo_func(uint16);
+
+typedef struct {
+ pthread_mutex_t pool_mutex;
+ TABLE_LOCK *pool; /* lifo pool of free locks */
+ uint lock_timeout; /* lock timeout in milliseconds */
+ loid_to_tlo_func *loid_to_tlo; /* for mapping loid to TABLE_LOCK_OWNER */
+} TABLOCKMAN;
+
+void tablockman_init(TABLOCKMAN *, loid_to_tlo_func *, uint);
+void tablockman_destroy(TABLOCKMAN *);
+enum lockman_getlock_result tablockman_getlock(TABLOCKMAN *, TABLE_LOCK_OWNER *,
+ LOCKED_TABLE *, enum lockman_lock_type);
+void tablockman_release_locks(TABLOCKMAN *, TABLE_LOCK_OWNER *);
+void tablockman_init_locked_table(LOCKED_TABLE *, int);
+void tablockman_destroy_locked_table(LOCKED_TABLE *);
+
+#ifdef EXTRA_DEBUG
+void tablockman_print_tlo(TABLE_LOCK_OWNER *);
+#endif
+
+#endif
+
diff --git a/storage/maria/test_pack b/storage/maria/test_pack
new file mode 100755
index 00000000000..689645b1661
--- /dev/null
+++ b/storage/maria/test_pack
@@ -0,0 +1,10 @@
+silent="-s"
+suffix=""
+
+ma_test1$suffix -s ; maria_pack$suffix --force -s test1 ; maria_chk$suffix -es test1 ; maria_chk$suffix -rqs test1 ; maria_chk$suffix -es test1 ; maria_chk$suffix -us test1 ; maria_chk$suffix -es test1
+ma_test1$suffix -s -S ; maria_pack$suffix --force -s test1 ; maria_chk$suffix -es test1 ; maria_chk$suffix -rqs test1 ; maria_chk$suffix -es test1 ;maria_chk$suffix -us test1 ; maria_chk$suffix -es test1
+ma_test1$suffix -s -b ; maria_pack$suffix --force -s test1 ; maria_chk$suffix -es test1 ; maria_chk$suffix -rqs test1 ; maria_chk$suffix -es test1
+ma_test1$suffix -s -w ; maria_pack$suffix --force -s test1 ; maria_chk$suffix -es test1 ; maria_chk$suffix -ros test1 ; maria_chk$suffix -es test1
+
+ma_test2$suffix -s -t4 ; maria_pack$suffix --force -s test2 ; maria_chk$suffix -es test2 ; maria_chk$suffix -ros test2 ; maria_chk$suffix -es test2 ; maria_chk$suffix -s -u test2 ; maria_chk$suffix -sm test2
+ma_test2$suffix -s -t4 -b ; maria_pack$suffix --force -s test2 ; maria_chk$suffix -es test2 ; maria_chk$suffix -ros test2 ; maria_chk$suffix -es test2 ; maria_chk$suffix -s -u test2 ; maria_chk$suffix -sm test2
diff --git a/storage/maria/trnman.c b/storage/maria/trnman.c
new file mode 100644
index 00000000000..06b3b828d50
--- /dev/null
+++ b/storage/maria/trnman.c
@@ -0,0 +1,972 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "trnman.h"
+#include "ma_checkpoint.h"
+#include "ma_control_file.h"
+
+/*
+ status variables:
+ how many trns in the active list currently,
+ in the committed list currently, allocated since startup.
+*/
+uint trnman_active_transactions, trnman_committed_transactions,
+ trnman_allocated_transactions;
+
+/* list of active transactions in the trid order */
+static TRN active_list_min, active_list_max;
+/* list of committed transactions in the trid order */
+static TRN committed_list_min, committed_list_max;
+
+/* a counter, used to generate transaction ids */
+static TrID global_trid_generator;
+
+/*
+ The minimum existing transaction id for trnman_get_min_trid()
+ The default value is used when transaction manager not initialize;
+ Probably called from maria_chk
+*/
+static TrID trid_min_read_from= MAX_TRID;
+
+/* the mutex for everything above */
+static pthread_mutex_t LOCK_trn_list;
+
+/* LIFO pool of unused TRN structured for reuse */
+static TRN *pool;
+
+/* a hash for committed transactions that maps trid to a TRN structure */
+static LF_HASH trid_to_trn;
+
+/* an array that maps short_id of an active transaction to a TRN structure */
+static TRN **short_trid_to_active_trn;
+
+/* locks for short_trid_to_active_trn and pool */
+static my_atomic_rwlock_t LOCK_short_trid_to_trn, LOCK_pool;
+static my_bool default_trnman_end_trans_hook(TRN *, my_bool, my_bool);
+static void trnman_free_trn(TRN *);
+
+my_bool (*trnman_end_trans_hook)(TRN *, my_bool, my_bool)=
+ default_trnman_end_trans_hook;
+
+/*
+ Simple interface functions
+ QQ: if they stay so simple, should we make them inline?
+*/
+
+uint trnman_increment_locked_tables(TRN *trn)
+{
+ return trn->locked_tables++;
+}
+
+uint trnman_has_locked_tables(TRN *trn)
+{
+ return trn->locked_tables;
+}
+
+uint trnman_decrement_locked_tables(TRN *trn)
+{
+ return --trn->locked_tables;
+}
+
+void trnman_reset_locked_tables(TRN *trn, uint locked_tables)
+{
+ trn->locked_tables= locked_tables;
+}
+
+#ifdef EXTRA_DEBUG
+uint16 trnman_get_flags(TRN *trn)
+{
+ return trn->flags;
+}
+
+void trnman_set_flags(TRN *trn, uint16 flags)
+{
+ trn->flags= flags;
+}
+#endif
+
+/** Wake up threads waiting for this transaction */
+static void wt_thd_release_self(TRN *trn)
+{
+ if (trn->wt)
+ {
+ WT_RESOURCE_ID rc;
+ rc.type= &ma_rc_dup_unique;
+ rc.value= (intptr)trn;
+ wt_thd_release(trn->wt, & rc);
+ trn->wt= 0;
+ }
+}
+
+static my_bool
+default_trnman_end_trans_hook(TRN *trn __attribute__ ((unused)),
+ my_bool commit __attribute__ ((unused)),
+ my_bool active_transactions
+ __attribute__ ((unused)))
+{
+ return 0;
+}
+
+
+static uchar *trn_get_hash_key(const uchar *trn, size_t *len,
+ my_bool unused __attribute__ ((unused)))
+{
+ *len= sizeof(TrID);
+ return (uchar *) & ((*((TRN **)trn))->trid);
+}
+
+
+/**
+ @brief Initializes transaction manager.
+
+ @param initial_trid Generated TrIDs will start from initial_trid+1.
+
+ @return Operation status
+ @retval 0 OK
+ @retval !=0 Error
+*/
+
+int trnman_init(TrID initial_trid)
+{
+ DBUG_ENTER("trnman_init");
+
+ short_trid_to_active_trn= (TRN **)my_malloc(SHORT_TRID_MAX*sizeof(TRN*),
+ MYF(MY_WME|MY_ZEROFILL));
+ if (unlikely(!short_trid_to_active_trn))
+ DBUG_RETURN(1);
+ short_trid_to_active_trn--; /* min short_id is 1 */
+
+ /*
+ Initialize lists.
+ active_list_max.min_read_from must be larger than any trid,
+ so that when an active list is empty we would could free
+ all committed list.
+ And committed_list_max itself can not be freed so
+ committed_list_max.commit_trid must not be smaller that
+ active_list_max.min_read_from
+ */
+
+ active_list_max.trid= active_list_min.trid= 0;
+ active_list_max.min_read_from= MAX_TRID;
+ active_list_max.next= active_list_min.prev= 0;
+ active_list_max.prev= &active_list_min;
+ active_list_min.next= &active_list_max;
+
+ committed_list_max.commit_trid= MAX_TRID;
+ committed_list_max.next= committed_list_min.prev= 0;
+ committed_list_max.prev= &committed_list_min;
+ committed_list_min.next= &committed_list_max;
+
+ trnman_active_transactions= 0;
+ trnman_committed_transactions= 0;
+ trnman_allocated_transactions= 0;
+
+ pool= 0;
+ global_trid_generator= initial_trid;
+ trid_min_read_from= initial_trid;
+ lf_hash_init(&trid_to_trn, sizeof(TRN*), LF_HASH_UNIQUE,
+ 0, 0, trn_get_hash_key, 0);
+ DBUG_PRINT("info", ("pthread_mutex_init LOCK_trn_list"));
+ pthread_mutex_init(&LOCK_trn_list, MY_MUTEX_INIT_FAST);
+ my_atomic_rwlock_init(&LOCK_short_trid_to_trn);
+ my_atomic_rwlock_init(&LOCK_pool);
+
+ DBUG_RETURN(0);
+}
+
+/*
+ NOTE
+ this could only be called in the "idle" state - no transaction can be
+ running. See asserts below.
+*/
+void trnman_destroy()
+{
+ DBUG_ENTER("trnman_destroy");
+
+ if (short_trid_to_active_trn == NULL) /* trnman already destroyed */
+ DBUG_VOID_RETURN;
+ DBUG_ASSERT(trid_to_trn.count == 0);
+ DBUG_ASSERT(trnman_active_transactions == 0);
+ DBUG_ASSERT(trnman_committed_transactions == 0);
+ DBUG_ASSERT(active_list_max.prev == &active_list_min);
+ DBUG_ASSERT(active_list_min.next == &active_list_max);
+ DBUG_ASSERT(committed_list_max.prev == &committed_list_min);
+ DBUG_ASSERT(committed_list_min.next == &committed_list_max);
+ while (pool)
+ {
+ TRN *trn= pool;
+ pool= pool->next;
+ DBUG_ASSERT(trn->wt == NULL);
+ pthread_mutex_destroy(&trn->state_lock);
+ my_free((void *)trn, MYF(0));
+ }
+ lf_hash_destroy(&trid_to_trn);
+ DBUG_PRINT("info", ("pthread_mutex_destroy LOCK_trn_list"));
+ pthread_mutex_destroy(&LOCK_trn_list);
+ my_atomic_rwlock_destroy(&LOCK_short_trid_to_trn);
+ my_atomic_rwlock_destroy(&LOCK_pool);
+ my_free((void *)(short_trid_to_active_trn+1), MYF(0));
+ short_trid_to_active_trn= NULL;
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ NOTE
+ TrID is limited to 6 bytes. Initial value of the generator
+ is set by the recovery code - being read from the last checkpoint
+ (or 1 on a first run).
+*/
+static TrID new_trid()
+{
+ DBUG_ENTER("new_trid");
+ DBUG_ASSERT(global_trid_generator < 0xffffffffffffLL);
+ DBUG_PRINT("info", ("safe_mutex_assert_owner LOCK_trn_list"));
+ safe_mutex_assert_owner(&LOCK_trn_list);
+ DBUG_RETURN(++global_trid_generator);
+}
+
+static uint get_short_trid(TRN *trn)
+{
+ int i= (int) ((global_trid_generator + (intptr)trn) * 312089 %
+ SHORT_TRID_MAX) + 1;
+ uint res=0;
+
+ for ( ; !res ; i= 1)
+ {
+ my_atomic_rwlock_wrlock(&LOCK_short_trid_to_trn);
+ for ( ; i <= SHORT_TRID_MAX; i++) /* the range is [1..SHORT_TRID_MAX] */
+ {
+ void *tmp= NULL;
+ if (short_trid_to_active_trn[i] == NULL &&
+ my_atomic_casptr((void **)&short_trid_to_active_trn[i], &tmp, trn))
+ {
+ res= i;
+ break;
+ }
+ }
+ my_atomic_rwlock_wrunlock(&LOCK_short_trid_to_trn);
+ }
+ return res;
+}
+
+/**
+ Allocates and initialzies a new TRN object
+
+ @note the 'wt' parameter can only be 0 in a single-threaded code (or,
+ generally, where threads cannot block each other), otherwise the
+ first call to the deadlock detector will sigsegv.
+*/
+
+TRN *trnman_new_trn(WT_THD *wt)
+{
+ int res;
+ TRN *trn;
+ union { TRN *trn; void *v; } tmp;
+ DBUG_ENTER("trnman_new_trn");
+
+ /*
+ we have a mutex, to do simple things under it - allocate a TRN,
+ increment trnman_active_transactions, set trn->min_read_from.
+
+ Note that all the above is fast. generating short_id may be slow,
+ as it involves scanning a large array - so it's done outside of the
+ mutex.
+ */
+
+ DBUG_PRINT("info", ("pthread_mutex_lock LOCK_trn_list"));
+ pthread_mutex_lock(&LOCK_trn_list);
+
+ /* Allocating a new TRN structure */
+ tmp.trn= pool;
+ /*
+ Popping an unused TRN from the pool
+ (ABA isn't possible, we're behind a mutex
+ */
+ my_atomic_rwlock_wrlock(&LOCK_pool);
+ while (tmp.trn && !my_atomic_casptr((void **)&pool, &tmp.v,
+ (void *)tmp.trn->next))
+ /* no-op */;
+ my_atomic_rwlock_wrunlock(&LOCK_pool);
+
+ /* Nothing in the pool ? Allocate a new one */
+ if (!(trn= tmp.trn))
+ {
+ /*
+ trn should be completely initalized at create time to allow
+ one to keep a known state on it.
+ (Like redo_lns, which is assumed to be 0 at start of row handling
+ and reset to zero before end of row handling)
+ */
+ trn= (TRN *)my_malloc(sizeof(TRN), MYF(MY_WME | MY_ZEROFILL));
+ if (unlikely(!trn))
+ {
+ DBUG_PRINT("info", ("pthread_mutex_unlock LOCK_trn_list"));
+ pthread_mutex_unlock(&LOCK_trn_list);
+ return 0;
+ }
+ trnman_allocated_transactions++;
+ pthread_mutex_init(&trn->state_lock, MY_MUTEX_INIT_FAST);
+ }
+ trn->wt= wt;
+ trn->pins= lf_hash_get_pins(&trid_to_trn);
+ if (!trn->pins)
+ {
+ trnman_free_trn(trn);
+ pthread_mutex_unlock(&LOCK_trn_list);
+ return 0;
+ }
+
+ trnman_active_transactions++;
+
+ trn->min_read_from= active_list_min.next->trid;
+
+ trn->trid= new_trid();
+
+ trn->next= &active_list_max;
+ trn->prev= active_list_max.prev;
+ active_list_max.prev= trn->prev->next= trn;
+ trid_min_read_from= active_list_min.next->min_read_from;
+ DBUG_PRINT("info", ("pthread_mutex_unlock LOCK_trn_list"));
+ pthread_mutex_unlock(&LOCK_trn_list);
+
+ if (unlikely(!trn->min_read_from))
+ {
+ /*
+ We are the only transaction. Set min_read_from so that we can read
+ our own rows
+ */
+ trn->min_read_from= trn->trid + 1;
+ }
+
+ /* no other transaction can read changes done by this one */
+ trn->commit_trid= MAX_TRID;
+ trn->rec_lsn= trn->undo_lsn= trn->first_undo_lsn= 0;
+ trn->used_tables= 0;
+
+ trn->locked_tables= 0;
+
+ /*
+ only after the following function TRN is considered initialized,
+ so it must be done the last
+ */
+ pthread_mutex_lock(&trn->state_lock);
+ trn->short_id= get_short_trid(trn);
+ pthread_mutex_unlock(&trn->state_lock);
+
+ res= lf_hash_insert(&trid_to_trn, trn->pins, &trn);
+ DBUG_ASSERT(res <= 0);
+ if (res)
+ {
+ trnman_end_trn(trn, 0);
+ return 0;
+ }
+
+ DBUG_PRINT("exit", ("trn: 0x%lx trid: 0x%lu",
+ (ulong) trn, (ulong) trn->trid));
+
+ DBUG_RETURN(trn);
+}
+
+/*
+ remove a trn from the active list.
+ if necessary - move to committed list and set commit_trid
+
+ NOTE
+ Locks are released at the end. In particular, after placing the
+ transaction in commit list, and after setting commit_trid. It's
+ important, as commit_trid affects visibility. Locks don't affect
+ anything they simply delay execution of other threads - they could be
+ released arbitrarily late. In other words, when locks are released it
+ serves as a start banner for other threads, they start to run. So
+ everything they may need must be ready at that point.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+my_bool trnman_end_trn(TRN *trn, my_bool commit)
+{
+ int res= 1;
+ uint16 cached_short_id= trn->short_id; /* we have to cache it, see below */
+ TRN *free_me= 0;
+ LF_PINS *pins= trn->pins;
+ DBUG_ENTER("trnman_end_trn");
+ DBUG_PRINT("enter", ("trn=0x%lx commit=%d", (ulong) trn, commit));
+
+ /* if a rollback, all UNDO records should have been executed */
+ DBUG_ASSERT(commit || trn->undo_lsn == 0);
+ DBUG_ASSERT(trn != &dummy_transaction_object);
+ DBUG_PRINT("info", ("pthread_mutex_lock LOCK_trn_list"));
+
+ pthread_mutex_lock(&LOCK_trn_list);
+
+ /* remove from active list */
+ trn->next->prev= trn->prev;
+ trn->prev->next= trn->next;
+
+ /*
+ if trn was the oldest active transaction, now that it goes away there
+ may be committed transactions in the list which no active transaction
+ needs to bother about - clean up the committed list
+ */
+ if (trn->prev == &active_list_min)
+ {
+ uint free_me_count;
+ TRN *t;
+ for (t= committed_list_min.next, free_me_count= 0;
+ t->commit_trid < active_list_min.next->min_read_from;
+ t= t->next, free_me_count++) /* no-op */;
+
+ DBUG_ASSERT((t != committed_list_min.next && free_me_count > 0) ||
+ (t == committed_list_min.next && free_me_count == 0));
+ /* found transactions committed before the oldest active one */
+ if (t != committed_list_min.next)
+ {
+ free_me= committed_list_min.next;
+ committed_list_min.next= t;
+ t->prev->next= 0;
+ t->prev= &committed_list_min;
+ trnman_committed_transactions-= free_me_count;
+ }
+ }
+
+ pthread_mutex_lock(&trn->state_lock);
+ if (commit)
+ trn->commit_trid= global_trid_generator;
+ wt_thd_release_self(trn);
+ pthread_mutex_unlock(&trn->state_lock);
+
+ /*
+ if transaction is committed and it was not the only active transaction -
+ add it to the committed list
+ */
+ if (commit && active_list_min.next != &active_list_max)
+ {
+ trn->next= &committed_list_max;
+ trn->prev= committed_list_max.prev;
+ trnman_committed_transactions++;
+ committed_list_max.prev= trn->prev->next= trn;
+ }
+ else
+ {
+ trn->next= free_me;
+ free_me= trn;
+ }
+ trid_min_read_from= active_list_min.next->min_read_from;
+
+ if ((*trnman_end_trans_hook)(trn, commit,
+ active_list_min.next != &active_list_max))
+ res= -1;
+ trnman_active_transactions--;
+
+ DBUG_PRINT("info", ("pthread_mutex_unlock LOCK_trn_list"));
+ pthread_mutex_unlock(&LOCK_trn_list);
+
+ /*
+ the rest is done outside of a critical section
+
+ note that we don't own trn anymore, it may be in a shared list now.
+ Thus, we cannot dereference it, and must use cached_short_id below.
+ */
+ my_atomic_rwlock_rdlock(&LOCK_short_trid_to_trn);
+ my_atomic_storeptr((void **)&short_trid_to_active_trn[cached_short_id], 0);
+ my_atomic_rwlock_rdunlock(&LOCK_short_trid_to_trn);
+
+ /*
+ we, under the mutex, removed going-in-free_me transactions from the
+ active and committed lists, thus nobody else may see them when it scans
+ those lists, and thus nobody may want to free them. Now we don't
+ need a mutex to access free_me list
+ */
+ /* QQ: send them to the purge thread */
+ while (free_me)
+ {
+ TRN *t= free_me;
+ free_me= free_me->next;
+
+ /* ignore OOM. it's harmless, and we can do nothing here anyway */
+ (void)lf_hash_delete(&trid_to_trn, pins, &t->trid, sizeof(TrID));
+
+ trnman_free_trn(t);
+ }
+
+ lf_hash_put_pins(pins);
+
+ DBUG_RETURN(res < 0);
+}
+
+/*
+ free a trn (add to the pool, that is)
+ note - we can never really free() a TRN if there's at least one other
+ running transaction - see, e.g., how lock waits are implemented in
+ lockman.c
+ The same is true for other lock-free data structures too. We may need some
+ kind of FLUSH command to reset them all - ensuring that no transactions are
+ running. It may even be called automatically on checkpoints if no
+ transactions are running.
+*/
+static void trnman_free_trn(TRN *trn)
+{
+ /*
+ union is to solve strict aliasing issue.
+ without it gcc 3.4.3 doesn't notice that updating *(void **)&tmp
+ modifies the value of tmp.
+ */
+ union { TRN *trn; void *v; } tmp;
+
+ pthread_mutex_lock(&trn->state_lock);
+ trn->short_id= 0;
+ pthread_mutex_unlock(&trn->state_lock);
+
+ tmp.trn= pool;
+
+ my_atomic_rwlock_wrlock(&LOCK_pool);
+ do
+ {
+ /*
+ without this volatile cast gcc-3.4.4 moves the assignment
+ down after the loop at -O2
+ */
+ *(TRN * volatile *)&(trn->next)= tmp.trn;
+ } while (!my_atomic_casptr((void **)&pool, &tmp.v, trn));
+ my_atomic_rwlock_wrunlock(&LOCK_pool);
+}
+
+/*
+ NOTE
+ here we access the hash in a lock-free manner.
+ It's safe, a 'found' TRN can never be freed/reused before we access it.
+ In fact, it cannot be freed before 'trn' ends, because a 'found' TRN
+ can only be removed from the hash when:
+ found->commit_trid < ALL (trn->min_read_from)
+ that is, at least
+ found->commit_trid < trn->min_read_from
+ but
+ found->trid >= trn->min_read_from
+ and
+ found->commit_trid > found->trid
+
+ RETURN
+ 1 can
+ 0 cannot
+ -1 error (OOM)
+*/
+int trnman_can_read_from(TRN *trn, TrID trid)
+{
+ TRN **found;
+ my_bool can;
+ LF_REQUIRE_PINS(3);
+
+ if (trid < trn->min_read_from)
+ return 1; /* Row is visible by all transactions in the system */
+
+ if (trid >= trn->trid)
+ {
+ /*
+ We have now two cases
+ trid > trn->trid, in which case the row is from a new transaction
+ and not visible, in which case we should return 0.
+ trid == trn->trid in which case the row is from the current transaction
+ and we should return 1
+ */
+ return trid == trn->trid;
+ }
+
+ found= lf_hash_search(&trid_to_trn, trn->pins, &trid, sizeof(trid));
+ if (found == NULL)
+ return 0; /* not in the hash of transactions = cannot read */
+ if (found == MY_ERRPTR)
+ return -1;
+
+ can= (*found)->commit_trid < trn->trid;
+ lf_hash_search_unpin(trn->pins);
+ return can;
+}
+
+/**
+ Finds a TRN by its TrID
+
+ @param trn current trn. Needed for pinning pointers (see lf_pin)
+ @param trid trid to search for
+
+ @return found trn or 0
+
+ @note that trn is returned with its state locked!
+*/
+TRN *trnman_trid_to_trn(TRN *trn, TrID trid)
+{
+ TRN **found;
+ LF_REQUIRE_PINS(3);
+
+ if (trid < trn->min_read_from)
+ return 0; /* it's committed eons ago */
+
+ found= lf_hash_search(&trid_to_trn, trn->pins, &trid, sizeof(trid));
+ if (found == NULL || found == MY_ERRPTR)
+ return 0; /* no luck */
+
+ /* we've found something */
+ pthread_mutex_lock(&(*found)->state_lock);
+
+ if ((*found)->short_id == 0)
+ {
+ pthread_mutex_unlock(&(*found)->state_lock);
+ lf_hash_search_unpin(trn->pins);
+ return 0; /* but it was a ghost */
+ }
+ lf_hash_search_unpin(trn->pins);
+
+ /* Gotcha! */
+ return *found;
+}
+
+/* TODO: the stubs below are waiting for savepoints to be implemented */
+
+void trnman_new_statement(TRN *trn __attribute__ ((unused)))
+{
+}
+
+void trnman_rollback_statement(TRN *trn __attribute__ ((unused)))
+{
+}
+
+
+/**
+ @brief Allocates buffers and stores in them some info about transactions
+
+ Does the allocation because the caller cannot know the size itself.
+ Memory freeing is to be done by the caller (if the "str" member of the
+ LEX_STRING is not NULL).
+ The caller has the intention of doing checkpoints.
+
+ @param[out] str_act pointer to where the allocated buffer,
+ and its size, will be put; buffer will be filled
+ with info about active transactions
+ @param[out] str_com pointer to where the allocated buffer,
+ and its size, will be put; buffer will be filled
+ with info about committed transactions
+ @param[out] min_first_undo_lsn pointer to where the minimum
+ first_undo_lsn of all transactions will be put
+
+ @return Operation status
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool trnman_collect_transactions(LEX_STRING *str_act, LEX_STRING *str_com,
+ LSN *min_rec_lsn, LSN *min_first_undo_lsn)
+{
+ my_bool error;
+ TRN *trn;
+ char *ptr;
+ uint stored_transactions= 0;
+ LSN minimum_rec_lsn= LSN_MAX, minimum_first_undo_lsn= LSN_MAX;
+ DBUG_ENTER("trnman_collect_transactions");
+
+ DBUG_ASSERT((NULL == str_act->str) && (NULL == str_com->str));
+
+ /* validate the use of read_non_atomic() in general: */
+ compile_time_assert((sizeof(LSN) == 8) && (sizeof(LSN_WITH_FLAGS) == 8));
+ pthread_mutex_lock(&LOCK_trn_list);
+ str_act->length= 2 + /* number of active transactions */
+ LSN_STORE_SIZE + /* minimum of their rec_lsn */
+ TRANSID_SIZE + /* current TrID generator value */
+ (2 + /* short id */
+ 6 + /* long id */
+ LSN_STORE_SIZE + /* undo_lsn */
+#ifdef MARIA_VERSIONING /* not enabled yet */
+ LSN_STORE_SIZE + /* undo_purge_lsn */
+#endif
+ LSN_STORE_SIZE /* first_undo_lsn */
+ ) * trnman_active_transactions;
+ str_com->length= 4 + /* number of committed transactions */
+ (6 + /* long id */
+#ifdef MARIA_VERSIONING /* not enabled yet */
+ LSN_STORE_SIZE + /* undo_purge_lsn */
+#endif
+ LSN_STORE_SIZE /* first_undo_lsn */
+ ) * trnman_committed_transactions;
+ if ((NULL == (str_act->str= my_malloc(str_act->length, MYF(MY_WME)))) ||
+ (NULL == (str_com->str= my_malloc(str_com->length, MYF(MY_WME)))))
+ goto err;
+ /* First, the active transactions */
+ ptr= str_act->str + 2 + LSN_STORE_SIZE;
+ transid_store(ptr, global_trid_generator);
+ ptr+= TRANSID_SIZE;
+ for (trn= active_list_min.next; trn != &active_list_max; trn= trn->next)
+ {
+ /*
+ trns with a short trid of 0 are not even initialized, we can ignore
+ them. trns with undo_lsn==0 have done no writes, we can ignore them
+ too. XID not needed now.
+ */
+ uint sid;
+ LSN rec_lsn, undo_lsn, first_undo_lsn;
+ pthread_mutex_lock(&trn->state_lock);
+ sid= trn->short_id;
+ pthread_mutex_unlock(&trn->state_lock);
+ if (sid == 0)
+ {
+ /*
+ Not even inited, has done nothing. Or it is the
+ dummy_transaction_object, which does only non-transactional
+ immediate-sync operations (CREATE/DROP/RENAME/REPAIR TABLE), and so
+ can be forgotten for Checkpoint.
+ */
+ continue;
+ }
+ /* needed for low-water mark calculation */
+ if (((rec_lsn= lsn_read_non_atomic(trn->rec_lsn)) > 0) &&
+ (cmp_translog_addr(rec_lsn, minimum_rec_lsn) < 0))
+ minimum_rec_lsn= rec_lsn;
+ /*
+ trn may have logged REDOs but not yet UNDO, that's why we read rec_lsn
+ before deciding to ignore if undo_lsn==0.
+ */
+ if ((undo_lsn= trn->undo_lsn) == 0) /* trn can be forgotten */
+ continue;
+ stored_transactions++;
+ int2store(ptr, sid);
+ ptr+= 2;
+ int6store(ptr, trn->trid);
+ ptr+= 6;
+ lsn_store(ptr, undo_lsn); /* needed for rollback */
+ ptr+= LSN_STORE_SIZE;
+ /* needed for low-water mark calculation */
+ if (((first_undo_lsn= lsn_read_non_atomic(trn->first_undo_lsn)) > 0) &&
+ (cmp_translog_addr(first_undo_lsn, minimum_first_undo_lsn) < 0))
+ minimum_first_undo_lsn= first_undo_lsn;
+ lsn_store(ptr, first_undo_lsn);
+ ptr+= LSN_STORE_SIZE;
+#ifdef MARIA_VERSIONING /* not enabled yet */
+ /* to know where purging should start (last delete of this trn) */
+ lsn_store(ptr, trn->undo_purge_lsn);
+ ptr+= LSN_STORE_SIZE;
+#endif
+ /**
+ @todo RECOVERY: add a comment explaining why we can dirtily read some
+ vars, inspired by the text of "assumption 8" in WL#3072
+ */
+ }
+ str_act->length= ptr - str_act->str; /* as we maybe over-estimated */
+ ptr= str_act->str;
+ DBUG_PRINT("info",("collected %u active transactions",
+ (uint)stored_transactions));
+ int2store(ptr, stored_transactions);
+ ptr+= 2;
+ /* this LSN influences how REDOs for any page can be ignored by Recovery */
+ lsn_store(ptr, minimum_rec_lsn);
+ /* one day there will also be a list of prepared transactions */
+ /* do the same for committed ones */
+ ptr= str_com->str;
+ int4store(ptr, trnman_committed_transactions);
+ ptr+= 4;
+ DBUG_PRINT("info",("collected %u committed transactions",
+ (uint)trnman_committed_transactions));
+ for (trn= committed_list_min.next; trn != &committed_list_max;
+ trn= trn->next)
+ {
+ LSN first_undo_lsn;
+ int6store(ptr, trn->trid);
+ ptr+= 6;
+#ifdef MARIA_VERSIONING /* not enabled yet */
+ lsn_store(ptr, trn->undo_purge_lsn);
+ ptr+= LSN_STORE_SIZE;
+#endif
+ first_undo_lsn= LSN_WITH_FLAGS_TO_LSN(trn->first_undo_lsn);
+ if (cmp_translog_addr(first_undo_lsn, minimum_first_undo_lsn) < 0)
+ minimum_first_undo_lsn= first_undo_lsn;
+ lsn_store(ptr, first_undo_lsn);
+ ptr+= LSN_STORE_SIZE;
+ }
+ /*
+ TODO: if we see there exists no transaction (active and committed) we can
+ tell the lock-free structures to do some freeing (my_free()).
+ */
+ error= 0;
+ *min_rec_lsn= minimum_rec_lsn;
+ *min_first_undo_lsn= minimum_first_undo_lsn;
+ goto end;
+err:
+ error= 1;
+end:
+ pthread_mutex_unlock(&LOCK_trn_list);
+ DBUG_RETURN(error);
+}
+
+
+TRN *trnman_recreate_trn_from_recovery(uint16 shortid, TrID longid)
+{
+ TrID old_trid_generator= global_trid_generator;
+ TRN *trn;
+ DBUG_ASSERT(maria_in_recovery && !maria_multi_threaded);
+ global_trid_generator= longid-1; /* force a correct trid in the new trn */
+ if (unlikely((trn= trnman_new_trn(NULL)) == NULL))
+ return NULL;
+ /* deallocate excessive allocations of trnman_new_trn() */
+ global_trid_generator= old_trid_generator;
+ set_if_bigger(global_trid_generator, longid);
+ short_trid_to_active_trn[trn->short_id]= 0;
+ DBUG_ASSERT(short_trid_to_active_trn[shortid] == NULL);
+ short_trid_to_active_trn[shortid]= trn;
+ trn->short_id= shortid;
+ return trn;
+}
+
+
+TRN *trnman_get_any_trn()
+{
+ TRN *trn= active_list_min.next;
+ return (trn != &active_list_max) ? trn : NULL;
+}
+
+
+/**
+ Returns the minimum existing transaction id. May return a too small
+ number in race conditions, but this is ok as the value is used to
+ remove not visible transid from index/rows.
+*/
+
+TrID trnman_get_min_trid()
+{
+ return trid_min_read_from;
+}
+
+
+/**
+ Returns the minimum possible transaction id
+
+ @notes
+ If there is no transactions running, returns number for next running
+ transaction.
+ If one has an active transaction, the returned number will be less or
+ equal to this. If one is not running in a transaction one will ge the
+ number for the next started transaction. This is used in create table
+ to get a safe minimum trid to use.
+*/
+
+TrID trnman_get_min_safe_trid()
+{
+ TrID trid;
+ pthread_mutex_lock(&LOCK_trn_list);
+ trid= min(active_list_min.next->min_read_from,
+ global_trid_generator);
+ pthread_mutex_unlock(&LOCK_trn_list);
+ return trid;
+}
+
+
+/**
+ Returns maximum transaction id given to a transaction so far.
+*/
+
+TrID trnman_get_max_trid()
+{
+ TrID id;
+ if (short_trid_to_active_trn == NULL)
+ return 0;
+ pthread_mutex_lock(&LOCK_trn_list);
+ id= global_trid_generator;
+ pthread_mutex_unlock(&LOCK_trn_list);
+ return id;
+}
+
+/**
+ @brief Check if there exist an active transaction between two commit_id's
+
+ @todo
+ Improve speed of this.
+ - Store transactions in tree or skip list
+ - Have function to copying all active transaction id's to b-tree
+ and use b-tree for checking states. This could be a big win
+ for checkpoint that will call this function for a lot of objects.
+
+ @return
+ 0 No transaction exists
+ 1 There is at least on active transaction in the given range
+*/
+
+my_bool trnman_exists_active_transactions(TrID min_id, TrID max_id,
+ my_bool trnman_is_locked)
+{
+ TRN *trn;
+ my_bool ret= 0;
+
+ if (!trnman_is_locked)
+ pthread_mutex_lock(&LOCK_trn_list);
+ safe_mutex_assert_owner(&LOCK_trn_list);
+ for (trn= active_list_min.next; trn != &active_list_max; trn= trn->next)
+ {
+ /*
+ We use <= for max_id as max_id is a commit_trid and trn->trid
+ is transaction id. When calculating commit_trid we use the
+ current value of global_trid_generator. global_trid_generator is
+ incremented for each new transaction.
+
+ For example, assuming we have
+ min_id = 5
+ max_id = 10
+
+ A trid of value 5 can't see the history event between 5 & 10
+ at it vas started before min_id 5 was committed.
+ A trid of value 10 can't see the next history event (max_id = 10)
+ as it started before this was committed. In this case it must use
+ the this event.
+ */
+ if (trn->trid > min_id && trn->trid <= max_id)
+ {
+ ret= 1;
+ break;
+ }
+ }
+ if (!trnman_is_locked)
+ pthread_mutex_unlock(&LOCK_trn_list);
+ return ret;
+}
+
+
+/**
+ lock transaction list
+*/
+
+void trnman_lock()
+{
+ pthread_mutex_lock(&LOCK_trn_list);
+}
+
+
+/**
+ unlock transaction list
+*/
+
+void trnman_unlock()
+{
+ pthread_mutex_unlock(&LOCK_trn_list);
+}
+
+
+/**
+ Is trman initialized
+*/
+
+my_bool trman_is_inited()
+{
+ return (short_trid_to_active_trn != NULL);
+}
diff --git a/storage/maria/trnman.h b/storage/maria/trnman.h
new file mode 100644
index 00000000000..afe01d4ad10
--- /dev/null
+++ b/storage/maria/trnman.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _trnman_h
+#define _trnman_h
+
+C_MODE_START
+
+#include <lf.h>
+#include "trnman_public.h"
+#include "ma_loghandler_lsn.h"
+
+/**
+ trid - 6 uchar transaction identifier. Assigned when a transaction
+ is created. Transaction can always be identified by its trid,
+ even after transaction has ended.
+
+ short_id - 2-byte transaction identifier, identifies a running
+ transaction, is reassigned when transaction ends.
+
+ when short_id is 0, TRN is not initialized, for all practical purposes
+ it could be considered unused.
+
+ when commit_trid is MAX_TRID the transaction is running, otherwise it's
+ committed.
+
+ state_lock mutex protects the state of a TRN, that is whether a TRN
+ is committed/running/unused. Meaning that modifications of short_id and
+ commit_trid happen under this mutex.
+*/
+
+struct st_ma_transaction
+{
+ LF_PINS *pins;
+ WT_THD *wt;
+ pthread_mutex_t state_lock;
+ void *used_tables; /**< Tables used by transaction */
+ TRN *next, *prev;
+ TrID trid, min_read_from, commit_trid;
+ LSN rec_lsn, undo_lsn;
+ LSN_WITH_FLAGS first_undo_lsn;
+ uint locked_tables;
+ uint16 short_id;
+ uint16 flags; /**< Various flags */
+};
+
+#define TRANSACTION_LOGGED_LONG_ID ULL(0x8000000000000000)
+#define MAX_TRID (~(TrID)0)
+
+extern WT_RESOURCE_TYPE ma_rc_dup_unique;
+
+C_MODE_END
+
+#endif
+
diff --git a/storage/maria/trnman_public.h b/storage/maria/trnman_public.h
new file mode 100644
index 00000000000..9523eb5de8f
--- /dev/null
+++ b/storage/maria/trnman_public.h
@@ -0,0 +1,85 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/*
+ External definitions for trnman.h
+ We need to split this into two files as gcc 4.1.2 gives error if it tries
+ to include my_atomic.h in C++ code.
+*/
+
+#ifndef _trnman_public_h
+#define _trnman_public_h
+
+#include "ma_loghandler_lsn.h"
+#include <waiting_threads.h>
+
+C_MODE_START
+typedef uint64 TrID; /* our TrID is 6 bytes */
+typedef struct st_ma_transaction TRN;
+
+#define SHORT_TRID_MAX 65535
+
+extern uint trnman_active_transactions, trnman_allocated_transactions;
+extern TRN dummy_transaction_object;
+extern my_bool (*trnman_end_trans_hook)(TRN *trn, my_bool commit,
+ my_bool active_transactions);
+
+int trnman_init(TrID);
+void trnman_destroy(void);
+TRN *trnman_new_trn(WT_THD *wt);
+my_bool trnman_end_trn(TRN *trn, my_bool commit);
+#define trnman_commit_trn(T) trnman_end_trn(T, TRUE)
+#define trnman_abort_trn(T) trnman_end_trn(T, FALSE)
+#define trnman_rollback_trn(T) trnman_end_trn(T, FALSE)
+int trnman_can_read_from(TRN *trn, TrID trid);
+TRN *trnman_trid_to_trn(TRN *trn, TrID trid);
+void trnman_new_statement(TRN *trn);
+void trnman_rollback_statement(TRN *trn);
+my_bool trnman_collect_transactions(LEX_STRING *str_act, LEX_STRING *str_com,
+ LSN *min_rec_lsn,
+ LSN *min_first_undo_lsn);
+
+uint trnman_increment_locked_tables(TRN *trn);
+uint trnman_decrement_locked_tables(TRN *trn);
+uint trnman_has_locked_tables(TRN *trn);
+void trnman_reset_locked_tables(TRN *trn, uint locked_tables);
+TRN *trnman_recreate_trn_from_recovery(uint16 shortid, TrID longid);
+TRN *trnman_get_any_trn(void);
+TrID trnman_get_min_trid(void);
+TrID trnman_get_max_trid(void);
+TrID trnman_get_min_safe_trid();
+my_bool trnman_exists_active_transactions(TrID min_id, TrID max_id,
+ my_bool trnman_is_locked);
+#define TRANSID_SIZE 6
+#define transid_store(dst, id) int6store(dst,id)
+#define transid_korr(P) uint6korr(P)
+void trnman_lock();
+void trnman_unlock();
+my_bool trman_is_inited();
+#ifdef EXTRA_DEBUG
+uint16 trnman_get_flags(TRN *);
+void trnman_set_flags(TRN *, uint16 flags);
+#else
+#define trnman_get_flags(A) 0
+#define trnman_set_flags(A, B) do { } while (0)
+#endif
+
+/* Flag bits */
+#define TRN_STATE_INFO_LOGGED 1 /* Query is logged */
+#define TRN_STATE_TABLES_CAN_CHANGE 2 /* Things can change during trans. */
+
+C_MODE_END
+#endif
diff --git a/storage/maria/unittest/CMakeLists.txt b/storage/maria/unittest/CMakeLists.txt
new file mode 100644
index 00000000000..3d732f6245d
--- /dev/null
+++ b/storage/maria/unittest/CMakeLists.txt
@@ -0,0 +1,98 @@
+# Copyright (C) 2007 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
+ ${CMAKE_SOURCE_DIR}/unittest/mytap)
+LINK_LIBRARIES(maria myisam mytap mysys dbug strings wsock32 zlib)
+
+ADD_EXECUTABLE(ma_control_file-t ma_control_file-t.c)
+ADD_EXECUTABLE(trnman-t trnman-t.c)
+ADD_EXECUTABLE(ma_test_loghandler-t
+ ma_test_loghandler-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+ADD_EXECUTABLE(ma_test_loghandler_multigroup-t
+ ma_test_loghandler_multigroup-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c sequence_storage.c)
+ADD_EXECUTABLE(ma_test_loghandler_multithread-t
+ ma_test_loghandler_multithread-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+ADD_EXECUTABLE(ma_test_loghandler_pagecache-t
+ ma_test_loghandler_pagecache-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+ADD_EXECUTABLE(ma_test_loghandler_long-t
+ ma_test_loghandler-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+SET_TARGET_PROPERTIES(ma_test_loghandler_long-t PROPERTIES COMPILE_FLAGS "-DLONG_LOG_TEST")
+
+ADD_EXECUTABLE(ma_test_loghandler_noflush-t
+ ma_test_loghandler_noflush-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+ADD_EXECUTABLE(ma_test_loghandler_first_lsn-t
+ ma_test_loghandler_first_lsn-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+ADD_EXECUTABLE(ma_test_loghandler_max_lsn-t
+ ma_test_loghandler_max_lsn-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+ADD_EXECUTABLE(ma_test_loghandler_purge-t
+ ma_test_loghandler_purge-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+ADD_EXECUTABLE(ma_test_loghandler_readonly-t
+ ma_test_loghandler_multigroup-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c sequence_storage.c)
+SET_TARGET_PROPERTIES(ma_test_loghandler_readonly-t PROPERTIES COMPILE_FLAGS "-DREADONLY_TEST")
+ADD_EXECUTABLE(ma_test_loghandler_nologs-t
+ ma_test_loghandler_nologs-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c)
+
+SET(ma_pagecache_single_src ma_pagecache_single.c test_file.c test_file.h)
+SET(ma_pagecache_consist_src ma_pagecache_consist.c test_file.c test_file.h)
+SET(ma_pagecache_common_cppflags "-DEXTRA_DEBUG -DPAGECACHE_DEBUG -DMAIN")
+
+ADD_EXECUTABLE(ma_pagecache_single_1k-t ${ma_pagecache_single_src})
+SET_TARGET_PROPERTIES(ma_pagecache_single_1k-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=1024")
+
+ADD_EXECUTABLE(ma_pagecache_single_8k-t ${ma_pagecache_single_src})
+SET_TARGET_PROPERTIES(ma_pagecache_single_8k-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=8192")
+
+ADD_EXECUTABLE(ma_pagecache_single_64k-t ${ma_pagecache_single_src})
+SET_TARGET_PROPERTIES(ma_pagecache_single_64k-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=65536")
+
+ADD_EXECUTABLE(ma_pagecache_consist_1k-t ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_1k-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=1024")
+
+ADD_EXECUTABLE(ma_pagecache_consist_64k-t ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_64k-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=65536")
+
+ADD_EXECUTABLE(ma_pagecache_consist_1kHC-t
+ ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_1kHC-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=1024 -DTEST_HIGH_CONCURENCY")
+ADD_EXECUTABLE(ma_pagecache_consist_64kHC-t
+ ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_64kHC-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=65536 -DTEST_HIGH_CONCURENCY")
+ADD_EXECUTABLE(ma_pagecache_consist_1kRD-t ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_1kRD-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=1024 -DTEST_READERS")
+ADD_EXECUTABLE(ma_pagecache_consist_64kRD-t ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_64kRD-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=65536 -DTEST_READERS")
+ADD_EXECUTABLE(ma_pagecache_consist_1kWR-t ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_1kWR-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=1024 -DTEST_WRITERS")
+ADD_EXECUTABLE(ma_pagecache_consist_64kWR-t ${ma_pagecache_consist_src})
+SET_TARGET_PROPERTIES(ma_pagecache_consist_64kWR-t
+ PROPERTIES COMPILE_FLAGS "${ma_pagecache_common_cppflags} -DTEST_PAGE_SIZE=65536 -DTEST_WRITERS")
+ADD_EXECUTABLE(ma_pagecache_rwconsist_1k-t ma_pagecache_rwconsist.c)
+SET_TARGET_PROPERTIES(ma_pagecache_rwconsist_1k-t PROPERTIES COMPILE_FLAGS "-DTEST_PAGE_SIZE=1024")
+ADD_EXECUTABLE(ma_pagecache_rwconsist2_1k-t ma_pagecache_rwconsist2.c)
+SET_TARGET_PROPERTIES(ma_pagecache_rwconsist2_1k-t PROPERTIES COMPILE_FLAGS "-DTEST_PAGE_SIZE=1024")
diff --git a/storage/maria/unittest/Makefile.am b/storage/maria/unittest/Makefile.am
new file mode 100644
index 00000000000..28c75a06b29
--- /dev/null
+++ b/storage/maria/unittest/Makefile.am
@@ -0,0 +1,115 @@
+# Copyright (C) 2006-2008 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
+ -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
+INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
+ -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
+EXTRA_DIST= ma_test_all-t CMakeLists.txt \
+ ma_test_recovery.pl ma_test_recovery.expected
+# Only reason to link with libmyisam.a here is that it's where some fulltext
+# pieces are (but soon we'll remove fulltext dependencies from Maria).
+LDADD= $(top_builddir)/unittest/mytap/libmytap.a \
+ $(top_builddir)/storage/maria/libmaria.a \
+ $(top_builddir)/storage/myisam/libmyisam.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@
+noinst_PROGRAMS = ma_control_file-t trnman-t \
+ ma_pagecache_single_1k-t ma_pagecache_single_8k-t \
+ ma_pagecache_single_64k-t \
+ ma_pagecache_consist_1k-t \
+ ma_pagecache_consist_64k-t \
+ ma_pagecache_consist_1kHC-t \
+ ma_pagecache_consist_64kHC-t \
+ ma_pagecache_consist_1kRD-t \
+ ma_pagecache_consist_64kRD-t \
+ ma_pagecache_consist_1kWR-t \
+ ma_pagecache_consist_64kWR-t \
+ ma_pagecache_rwconsist_1k-t \
+ ma_pagecache_rwconsist2_1k-t \
+ ma_test_loghandler-t \
+ ma_test_loghandler_multigroup-t \
+ ma_test_loghandler_multithread-t \
+ ma_test_loghandler_multiflush-t \
+ ma_test_loghandler_pagecache-t \
+ ma_test_loghandler_long-t \
+ ma_test_loghandler_noflush-t \
+ ma_test_loghandler_first_lsn-t \
+ ma_test_loghandler_max_lsn-t \
+ ma_test_loghandler_purge-t \
+ ma_test_loghandler_readonly-t\
+ ma_test_loghandler_nologs-t
+
+ma_test_loghandler_t_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_multigroup_t_SOURCES = ma_test_loghandler_multigroup-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c sequence_storage.c sequence_storage.h
+ma_test_loghandler_multithread_t_SOURCES = ma_test_loghandler_multithread-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_multiflush_t_SOURCES = ma_test_loghandler_multithread-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_multiflush_t_CPPFLAGS = -DMULTIFLUSH_TEST
+ma_test_loghandler_pagecache_t_SOURCES = ma_test_loghandler_pagecache-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_long_t_SOURCES = ma_test_loghandler-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_long_t_CPPFLAGS = -DLONG_LOG_TEST
+ma_test_loghandler_noflush_t_SOURCES = ma_test_loghandler_noflush-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_first_lsn_t_SOURCES = ma_test_loghandler_first_lsn-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_max_lsn_t_SOURCES = ma_test_loghandler_max_lsn-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_purge_t_SOURCES = ma_test_loghandler_purge-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+ma_test_loghandler_readonly_t_SOURCES = ma_test_loghandler_multigroup-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c sequence_storage.c sequence_storage.h
+ma_test_loghandler_readonly_t_CPPFLAGS = -DREADONLY_TEST
+ma_test_loghandler_nologs_t_SOURCES = ma_test_loghandler_nologs-t.c ma_maria_log_cleanup.c ma_loghandler_examples.c
+
+ma_pagecache_single_src = ma_pagecache_single.c test_file.c test_file.h
+ma_pagecache_consist_src = ma_pagecache_consist.c test_file.c test_file.h
+ma_pagecache_common_cppflags = -DEXTRA_DEBUG -DPAGECACHE_DEBUG -DMAIN
+
+ma_pagecache_single_1k_t_SOURCES = $(ma_pagecache_single_src)
+ma_pagecache_single_8k_t_SOURCES = $(ma_pagecache_single_src)
+ma_pagecache_single_64k_t_SOURCES = $(ma_pagecache_single_src)
+ma_pagecache_single_1k_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=1024
+ma_pagecache_single_8k_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=8192
+ma_pagecache_single_64k_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=65536 -DBIG
+
+ma_pagecache_consist_1k_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_1k_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=1024
+ma_pagecache_consist_64k_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_64k_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=65536
+
+ma_pagecache_consist_1kHC_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_1kHC_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=1024 -DTEST_HIGH_CONCURENCY
+ma_pagecache_consist_64kHC_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_64kHC_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=65536 -DTEST_HIGH_CONCURENCY
+
+ma_pagecache_consist_1kRD_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_1kRD_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=1024 -DTEST_READERS
+ma_pagecache_consist_64kRD_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_64kRD_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=65536 -DTEST_READERS
+
+ma_pagecache_consist_1kWR_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_1kWR_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=1024 -DTEST_WRITERS
+ma_pagecache_consist_64kWR_t_SOURCES = $(ma_pagecache_consist_src)
+ma_pagecache_consist_64kWR_t_CPPFLAGS = $(ma_pagecache_common_cppflags) -DTEST_PAGE_SIZE=65536 -DTEST_WRITERS
+
+ma_pagecache_rwconsist_1k_t_SOURCES = ma_pagecache_rwconsist.c
+ma_pagecache_rwconsist_1k_t_CPPFLAGS = -DTEST_PAGE_SIZE=1024
+ma_pagecache_rwconsist2_1k_t_SOURCES = ma_pagecache_rwconsist2.c
+ma_pagecache_rwconsist2_1k_t_CPPFLAGS = -DTEST_PAGE_SIZE=1024
+
+# the generic lock manager may not be used in the end and lockman1-t crashes,
+# and lockman2-t takes at least quarter an hour,
+# so we don't build lockman-t and lockman1-t and lockman2-t
+CLEANFILES = maria_log_control page_cache_test_file_1 \
+ maria_log.????????
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/storage/maria/unittest/lockman-t.c b/storage/maria/unittest/lockman-t.c
new file mode 100644
index 00000000000..9b54a3d8ff9
--- /dev/null
+++ b/storage/maria/unittest/lockman-t.c
@@ -0,0 +1,308 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ lockman for row and table locks
+*/
+
+/* #define EXTRA_VERBOSE */
+
+#include <tap.h>
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_atomic.h>
+#include <lf.h>
+#include "../lockman.h"
+
+#define Nlos 100
+LOCK_OWNER loarray[Nlos];
+pthread_mutex_t mutexes[Nlos];
+pthread_cond_t conds[Nlos];
+LOCKMAN lockman;
+
+#ifndef EXTRA_VERBOSE
+#define print_lockhash(X) /* no-op */
+#define DIAG(X) /* no-op */
+#else
+#define DIAG(X) diag X
+#endif
+
+LOCK_OWNER *loid2lo(uint16 loid)
+{
+ return loarray+loid-1;
+}
+
+#define unlock_all(O) diag("lo" #O "> release all locks"); \
+ lockman_release_locks(&lockman, loid2lo(O));print_lockhash(&lockman)
+#define test_lock(O, R, L, S, RES) \
+ ok(lockman_getlock(&lockman, loid2lo(O), R, L) == RES, \
+ "lo" #O "> " S "lock resource " #R " with " #L "-lock"); \
+ print_lockhash(&lockman)
+#define lock_ok_a(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK)
+#define lock_ok_i(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE)
+#define lock_ok_l(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE)
+#define lock_conflict(O, R, L) \
+ test_lock(O, R, L, "cannot ", DIDNT_GET_THE_LOCK);
+
+void test_lockman_simple()
+{
+ /* simple */
+ lock_ok_a(1, 1, S);
+ lock_ok_i(2, 2, IS);
+ lock_ok_i(1, 2, IX);
+ /* lock escalation */
+ lock_ok_a(1, 1, X);
+ lock_ok_i(2, 2, IX);
+ /* failures */
+ lock_conflict(2, 1, X);
+ unlock_all(2);
+ lock_ok_a(1, 2, S);
+ lock_ok_a(1, 2, IS);
+ lock_ok_a(1, 2, LS);
+ lock_ok_i(1, 3, IX);
+ lock_ok_a(2, 3, LS);
+ lock_ok_i(1, 3, IX);
+ lock_ok_l(2, 3, IS);
+ unlock_all(1);
+ unlock_all(2);
+
+ lock_ok_i(1, 1, IX);
+ lock_conflict(2, 1, S);
+ lock_ok_a(1, 1, LS);
+ unlock_all(1);
+ unlock_all(2);
+
+ lock_ok_i(1, 1, IX);
+ lock_ok_a(2, 1, LS);
+ lock_ok_a(1, 1, LS);
+ lock_ok_i(1, 1, IX);
+ lock_ok_i(3, 1, IS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+
+ lock_ok_i(1, 4, IS);
+ lock_ok_i(2, 4, IS);
+ lock_ok_i(3, 4, IS);
+ lock_ok_a(3, 4, LS);
+ lock_ok_i(4, 4, IS);
+ lock_conflict(4, 4, IX);
+ lock_conflict(2, 4, IX);
+ lock_ok_a(1, 4, LS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+ unlock_all(4);
+
+ lock_ok_i(1, 1, IX);
+ lock_ok_i(2, 1, IX);
+ lock_conflict(1, 1, S);
+ lock_conflict(2, 1, X);
+ unlock_all(1);
+ unlock_all(2);
+}
+
+int rt_num_threads;
+int litmus;
+int thread_number= 0, timeouts= 0;
+void run_test(const char *test, pthread_handler handler, int n, int m)
+{
+ pthread_t *threads;
+ ulonglong now= my_getsystime();
+ int i;
+
+ thread_number= timeouts= 0;
+ litmus= 0;
+
+ threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
+ if (!threads)
+ {
+ diag("Out of memory");
+ abort();
+ }
+
+ diag("Running %s with %d threads, %d iterations... ", test, n, m);
+ rt_num_threads= n;
+ for (i= 0; i < n ; i++)
+ if (pthread_create(threads+i, 0, handler, &m))
+ {
+ diag("Could not create thread");
+ abort();
+ }
+ for (i= 0 ; i < n ; i++)
+ pthread_join(threads[i], 0);
+ now= my_getsystime()-now;
+ ok(litmus == 0, "Finished %s in %g secs (%d)", test, ((double)now)/1e7, litmus);
+ my_free((void*)threads, MYF(0));
+}
+
+pthread_mutex_t rt_mutex;
+int Nrows= 100;
+int Ntables= 10;
+int table_lock_ratio= 10;
+enum lockman_lock_type lock_array[6]= {S, X, LS, LX, IS, IX};
+char *lock2str[6]= {"S", "X", "LS", "LX", "IS", "IX"};
+char *res2str[4]= {
+ "DIDN'T GET THE LOCK",
+ "GOT THE LOCK",
+ "GOT THE LOCK NEED TO LOCK A SUBRESOURCE",
+ "GOT THE LOCK NEED TO INSTANT LOCK A SUBRESOURCE"};
+pthread_handler_t test_lockman(void *arg)
+{
+ int m= (*(int *)arg);
+ uint x, loid, row, table, res, locklevel, timeout= 0;
+ LOCK_OWNER *lo;
+
+ pthread_mutex_lock(&rt_mutex);
+ loid= ++thread_number;
+ pthread_mutex_unlock(&rt_mutex);
+ lo= loid2lo(loid);
+
+ for (x= ((int)(intptr)(&m)); m > 0; m--)
+ {
+ x= (x*3628273133 + 1500450271) % 9576890767; /* three prime numbers */
+ row= x % Nrows + Ntables;
+ table= row % Ntables;
+ locklevel= (x/Nrows) & 3;
+ if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0)
+ { /* table lock */
+ res= lockman_getlock(&lockman, lo, table, lock_array[locklevel]);
+ DIAG(("loid %2d, table %d, lock %s, res %s", loid, table,
+ lock2str[locklevel], res2str[res]));
+ if (res == DIDNT_GET_THE_LOCK)
+ {
+ lockman_release_locks(&lockman, lo);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ DBUG_ASSERT(res == GOT_THE_LOCK);
+ }
+ else
+ { /* row lock */
+ locklevel&= 1;
+ res= lockman_getlock(&lockman, lo, table, lock_array[locklevel + 4]);
+ DIAG(("loid %2d, row %d, lock %s, res %s", loid, row,
+ lock2str[locklevel+4], res2str[res]));
+ switch (res)
+ {
+ case DIDNT_GET_THE_LOCK:
+ lockman_release_locks(&lockman, lo);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ case GOT_THE_LOCK:
+ continue;
+ case GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE:
+ /* not implemented, so take a regular lock */
+ case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE:
+ res= lockman_getlock(&lockman, lo, row, lock_array[locklevel]);
+ DIAG(("loid %2d, ROW %d, lock %s, res %s", loid, row,
+ lock2str[locklevel], res2str[res]));
+ if (res == DIDNT_GET_THE_LOCK)
+ {
+ lockman_release_locks(&lockman, lo);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ DBUG_ASSERT(res == GOT_THE_LOCK);
+ continue;
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ }
+
+ lockman_release_locks(&lockman, lo);
+
+ pthread_mutex_lock(&rt_mutex);
+ rt_num_threads--;
+ timeouts+= timeout;
+ if (!rt_num_threads)
+ diag("number of timeouts: %d", timeouts);
+ pthread_mutex_unlock(&rt_mutex);
+
+ return 0;
+}
+
+int main()
+{
+ int i;
+
+ my_init();
+ pthread_mutex_init(&rt_mutex, 0);
+
+ plan(35);
+
+ if (my_atomic_initialize())
+ return exit_status();
+
+
+ lockman_init(&lockman, &loid2lo, 50);
+
+ for (i= 0; i < Nlos; i++)
+ {
+ loarray[i].pins= lf_alloc_get_pins(&lockman.alloc);
+ loarray[i].all_locks= 0;
+ loarray[i].waiting_for= 0;
+ pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
+ pthread_cond_init (&conds[i], 0);
+ loarray[i].mutex= &mutexes[i];
+ loarray[i].cond= &conds[i];
+ loarray[i].loid= i+1;
+ }
+
+ test_lockman_simple();
+
+#define CYCLES 10000
+#define THREADS Nlos /* don't change this line */
+
+ /* mixed load, stress-test with random locks */
+ Nrows= 100;
+ Ntables= 10;
+ table_lock_ratio= 10;
+ run_test("\"random lock\" stress test", test_lockman, THREADS, CYCLES);
+
+ /* "real-life" simulation - many rows, no table locks */
+ Nrows= 1000000;
+ Ntables= 10;
+ table_lock_ratio= 0;
+ run_test("\"real-life\" simulation test", test_lockman, THREADS, CYCLES*10);
+
+ for (i= 0; i < Nlos; i++)
+ {
+ lockman_release_locks(&lockman, &loarray[i]);
+ pthread_mutex_destroy(loarray[i].mutex);
+ pthread_cond_destroy(loarray[i].cond);
+ lf_pinbox_put_pins(loarray[i].pins);
+ }
+
+ {
+ ulonglong now= my_getsystime();
+ lockman_destroy(&lockman);
+ now= my_getsystime()-now;
+ diag("lockman_destroy: %g secs", ((double)now)/1e7);
+ }
+
+ pthread_mutex_destroy(&rt_mutex);
+ my_end(0);
+ return exit_status();
+}
+
diff --git a/storage/maria/unittest/lockman1-t.c b/storage/maria/unittest/lockman1-t.c
new file mode 100644
index 00000000000..ca959c6e6e3
--- /dev/null
+++ b/storage/maria/unittest/lockman1-t.c
@@ -0,0 +1,334 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ lockman for row locks, tablockman for table locks
+*/
+
+/* #define EXTRA_VERBOSE */
+
+#include <tap.h>
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_atomic.h>
+#include <lf.h>
+#include "../lockman.h"
+#include "../tablockman.h"
+
+#define Nlos 100
+#define Ntbls 10
+LOCK_OWNER loarray[Nlos];
+TABLE_LOCK_OWNER loarray1[Nlos];
+pthread_mutex_t mutexes[Nlos];
+pthread_cond_t conds[Nlos];
+LOCKED_TABLE ltarray[Ntbls];
+LOCKMAN lockman;
+TABLOCKMAN tablockman;
+
+#ifndef EXTRA_VERBOSE
+#define print_lo1(X) /* no-op */
+#define DIAG(X) /* no-op */
+#else
+#define DIAG(X) diag X
+#endif
+
+LOCK_OWNER *loid2lo(uint16 loid)
+{
+ return loarray+loid-1;
+}
+TABLE_LOCK_OWNER *loid2lo1(uint16 loid)
+{
+ return loarray1+loid-1;
+}
+
+#define unlock_all(O) diag("lo" #O "> release all locks"); \
+ tablockman_release_locks(&tablockman, loid2lo1(O));
+#define test_lock(O, R, L, S, RES) \
+ ok(tablockman_getlock(&tablockman, loid2lo1(O), &ltarray[R], L) == RES, \
+ "lo" #O "> " S "lock resource " #R " with " #L "-lock"); \
+ print_lo1(loid2lo1(O));
+#define lock_ok_a(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK)
+#define lock_ok_i(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE)
+#define lock_ok_l(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE)
+#define lock_conflict(O, R, L) \
+ test_lock(O, R, L, "cannot ", LOCK_TIMEOUT);
+
+void test_tablockman_simple()
+{
+ /* simple */
+ lock_ok_a(1, 1, S);
+ lock_ok_i(2, 2, IS);
+ lock_ok_i(1, 2, IX);
+ /* lock escalation */
+ lock_ok_a(1, 1, X);
+ lock_ok_i(2, 2, IX);
+ /* failures */
+ lock_conflict(2, 1, X);
+ unlock_all(2);
+ lock_ok_a(1, 2, S);
+ lock_ok_a(1, 2, IS);
+ lock_ok_a(1, 2, LS);
+ lock_ok_i(1, 3, IX);
+ lock_ok_a(2, 3, LS);
+ lock_ok_i(1, 3, IX);
+ lock_ok_l(2, 3, IS);
+ unlock_all(1);
+ unlock_all(2);
+
+ lock_ok_i(1, 1, IX);
+ lock_conflict(2, 1, S);
+ lock_ok_a(1, 1, LS);
+ unlock_all(1);
+ unlock_all(2);
+
+ lock_ok_i(1, 1, IX);
+ lock_ok_a(2, 1, LS);
+ lock_ok_a(1, 1, LS);
+ lock_ok_i(1, 1, IX);
+ lock_ok_i(3, 1, IS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+
+ lock_ok_i(1, 4, IS);
+ lock_ok_i(2, 4, IS);
+ lock_ok_i(3, 4, IS);
+ lock_ok_a(3, 4, LS);
+ lock_ok_i(4, 4, IS);
+ lock_conflict(4, 4, IX);
+ lock_conflict(2, 4, IX);
+ lock_ok_a(1, 4, LS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+ unlock_all(4);
+
+ lock_ok_i(1, 1, IX);
+ lock_ok_i(2, 1, IX);
+ lock_conflict(1, 1, S);
+ lock_conflict(2, 1, X);
+ unlock_all(1);
+ unlock_all(2);
+}
+
+int rt_num_threads;
+int litmus;
+int thread_number= 0, timeouts= 0;
+void run_test(const char *test, pthread_handler handler, int n, int m)
+{
+ pthread_t *threads;
+ ulonglong now= my_getsystime();
+ int i;
+
+ thread_number= timeouts= 0;
+ litmus= 0;
+
+ threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
+ if (!threads)
+ {
+ diag("Out of memory");
+ abort();
+ }
+
+ diag("Running %s with %d threads, %d iterations... ", test, n, m);
+ rt_num_threads= n;
+ for (i= 0; i < n ; i++)
+ if (pthread_create(threads+i, 0, handler, &m))
+ {
+ diag("Could not create thread");
+ abort();
+ }
+ for (i= 0 ; i < n ; i++)
+ pthread_join(threads[i], 0);
+ now= my_getsystime()-now;
+ ok(litmus == 0, "Finished %s in %g secs (%d)", test, ((double)now)/1e7, litmus);
+ my_free((void*)threads, MYF(0));
+}
+
+pthread_mutex_t rt_mutex;
+int Nrows= 100;
+int Ntables= 10;
+int table_lock_ratio= 10;
+enum lockman_lock_type lock_array[6]= {S, X, LS, LX, IS, IX};
+char *lock2str[6]= {"S", "X", "LS", "LX", "IS", "IX"};
+char *res2str[]= {
+ "DIDN'T GET THE LOCK",
+ "OUT OF MEMORY",
+ "DEADLOCK",
+ "LOCK TIMEOUT",
+ "GOT THE LOCK",
+ "GOT THE LOCK NEED TO LOCK A SUBRESOURCE",
+ "GOT THE LOCK NEED TO INSTANT LOCK A SUBRESOURCE"};
+pthread_handler_t test_lockman(void *arg)
+{
+ int m= (*(int *)arg);
+ uint x, loid, row, table, res, locklevel, timeout= 0;
+ LOCK_OWNER *lo; TABLE_LOCK_OWNER *lo1; DBUG_ASSERT(Ntables <= Ntbls);
+
+ pthread_mutex_lock(&rt_mutex);
+ loid= ++thread_number;
+ pthread_mutex_unlock(&rt_mutex);
+ lo= loid2lo(loid); lo1= loid2lo1(loid);
+
+ for (x= ((int)(intptr)(&m)); m > 0; m--)
+ {
+ x= (x*3628273133 + 1500450271) % 9576890767; /* three prime numbers */
+ row= x % Nrows + Ntables;
+ table= row % Ntables;
+ locklevel= (x/Nrows) & 3;
+ if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0)
+ { /* table lock */
+ res= tablockman_getlock(&tablockman, lo1, ltarray+table, lock_array[locklevel]);
+ DIAG(("loid %2d, table %d, lock %s, res %s", loid, table,
+ lock2str[locklevel], res2str[res]));
+ if (res < GOT_THE_LOCK)
+ {
+ lockman_release_locks(&lockman, lo); tablockman_release_locks(&tablockman, lo1);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ DBUG_ASSERT(res == GOT_THE_LOCK);
+ }
+ else
+ { /* row lock */
+ locklevel&= 1;
+ res= tablockman_getlock(&tablockman, lo1, ltarray+table, lock_array[locklevel + 4]);
+ DIAG(("loid %2d, row %d, lock %s, res %s", loid, row,
+ lock2str[locklevel+4], res2str[res]));
+ switch (res)
+ {
+ case GOT_THE_LOCK:
+ continue;
+ case GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE:
+ /* not implemented, so take a regular lock */
+ case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE:
+ res= lockman_getlock(&lockman, lo, row, lock_array[locklevel]);
+ DIAG(("loid %2d, ROW %d, lock %s, res %s", loid, row,
+ lock2str[locklevel], res2str[res]));
+ if (res == DIDNT_GET_THE_LOCK)
+ {
+ lockman_release_locks(&lockman, lo);
+ tablockman_release_locks(&tablockman, lo1);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ DBUG_ASSERT(res == GOT_THE_LOCK);
+ continue;
+ default:
+ lockman_release_locks(&lockman, lo); tablockman_release_locks(&tablockman, lo1);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ }
+ }
+
+ lockman_release_locks(&lockman, lo);
+ tablockman_release_locks(&tablockman, lo1);
+
+ pthread_mutex_lock(&rt_mutex);
+ rt_num_threads--;
+ timeouts+= timeout;
+ if (!rt_num_threads)
+ diag("number of timeouts: %d", timeouts);
+ pthread_mutex_unlock(&rt_mutex);
+
+ return 0;
+}
+
+int main()
+{
+ int i;
+
+ my_init();
+ pthread_mutex_init(&rt_mutex, 0);
+
+ plan(35);
+
+ if (my_atomic_initialize())
+ return exit_status();
+
+
+ lockman_init(&lockman, &loid2lo, 50);
+ tablockman_init(&tablockman, &loid2lo1, 50);
+
+ for (i= 0; i < Nlos; i++)
+ {
+ pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
+ pthread_cond_init (&conds[i], 0);
+
+ loarray[i].pins= lf_alloc_get_pins(&lockman.alloc);
+ loarray[i].all_locks= 0;
+ loarray[i].waiting_for= 0;
+ loarray[i].mutex= &mutexes[i];
+ loarray[i].cond= &conds[i];
+ loarray[i].loid= i+1;
+
+ loarray1[i].active_locks= 0;
+ loarray1[i].waiting_lock= 0;
+ loarray1[i].waiting_for= 0;
+ loarray1[i].mutex= &mutexes[i];
+ loarray1[i].cond= &conds[i];
+ loarray1[i].loid= i+1;
+ }
+
+ for (i= 0; i < Ntbls; i++)
+ {
+ tablockman_init_locked_table(ltarray+i, Nlos);
+ }
+
+ test_tablockman_simple();
+
+#define CYCLES 10000
+#define THREADS Nlos /* don't change this line */
+
+ /* mixed load, stress-test with random locks */
+ Nrows= 100;
+ Ntables= 10;
+ table_lock_ratio= 10;
+ run_test("\"random lock\" stress test", test_lockman, THREADS, CYCLES);
+
+ /* "real-life" simulation - many rows, no table locks */
+ Nrows= 1000000;
+ Ntables= 10;
+ table_lock_ratio= 0;
+ run_test("\"real-life\" simulation test", test_lockman, THREADS, CYCLES*10);
+
+ for (i= 0; i < Nlos; i++)
+ {
+ lockman_release_locks(&lockman, &loarray[i]);
+ pthread_mutex_destroy(loarray[i].mutex);
+ pthread_cond_destroy(loarray[i].cond);
+ lf_pinbox_put_pins(loarray[i].pins);
+ }
+
+ {
+ ulonglong now= my_getsystime();
+ lockman_destroy(&lockman);
+ now= my_getsystime()-now;
+ diag("lockman_destroy: %g secs", ((double)now)/1e7);
+ }
+
+ pthread_mutex_destroy(&rt_mutex);
+ my_end(0);
+ return exit_status();
+}
+
diff --git a/storage/maria/unittest/lockman2-t.c b/storage/maria/unittest/lockman2-t.c
new file mode 100644
index 00000000000..c1d40159500
--- /dev/null
+++ b/storage/maria/unittest/lockman2-t.c
@@ -0,0 +1,361 @@
+/* Copyright (C) 2006 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ tablockman for row and table locks
+*/
+
+/* #define EXTRA_VERBOSE */
+
+#include <tap.h>
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_atomic.h>
+#include <lf.h>
+#include "../tablockman.h"
+
+#define Nlos 100
+#define Ntbls 110
+TABLE_LOCK_OWNER loarray1[Nlos];
+pthread_mutex_t mutexes[Nlos];
+pthread_cond_t conds[Nlos];
+LOCKED_TABLE ltarray[Ntbls];
+TABLOCKMAN tablockman;
+
+#ifndef EXTRA_VERBOSE
+#define print_lo1(X) /* no-op */
+#define DIAG(X) /* no-op */
+#else
+#define DIAG(X) diag X
+#endif
+
+TABLE_LOCK_OWNER *loid2lo1(uint16 loid)
+{
+ return loarray1+loid-1;
+}
+
+#define unlock_all(O) diag("lo" #O "> release all locks"); \
+ tablockman_release_locks(&tablockman, loid2lo1(O));
+#define test_lock(O, R, L, S, RES) \
+ ok(tablockman_getlock(&tablockman, loid2lo1(O), &ltarray[R], L) == RES, \
+ "lo" #O "> " S "lock resource " #R " with " #L "-lock"); \
+ print_lo1(loid2lo1(O));
+#define lock_ok_a(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK)
+#define lock_ok_i(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE)
+#define lock_ok_l(O, R, L) \
+ test_lock(O, R, L, "", GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE)
+#define lock_conflict(O, R, L) \
+ test_lock(O, R, L, "cannot ", LOCK_TIMEOUT);
+
+void test_tablockman_simple()
+{
+ /* simple */
+ lock_ok_a(1, 1, S);
+ lock_ok_i(2, 2, IS);
+ lock_ok_i(1, 2, IX);
+ /* lock escalation */
+ lock_ok_a(1, 1, X);
+ lock_ok_i(2, 2, IX);
+ /* failures */
+ lock_conflict(2, 1, X);
+ unlock_all(2);
+ lock_ok_a(1, 2, S);
+ lock_ok_a(1, 2, IS);
+ lock_ok_a(1, 2, LS);
+ lock_ok_i(1, 3, IX);
+ lock_ok_a(2, 3, LS);
+ lock_ok_i(1, 3, IX);
+ lock_ok_l(2, 3, IS);
+ unlock_all(1);
+ unlock_all(2);
+
+ lock_ok_i(1, 1, IX);
+ lock_conflict(2, 1, S);
+ lock_ok_a(1, 1, LS);
+ unlock_all(1);
+ unlock_all(2);
+
+ lock_ok_i(1, 1, IX);
+ lock_ok_a(2, 1, LS);
+ lock_ok_a(1, 1, LS);
+ lock_ok_i(1, 1, IX);
+ lock_ok_i(3, 1, IS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+
+ lock_ok_i(1, 4, IS);
+ lock_ok_i(2, 4, IS);
+ lock_ok_i(3, 4, IS);
+ lock_ok_a(3, 4, LS);
+ lock_ok_i(4, 4, IS);
+ lock_conflict(4, 4, IX);
+ lock_conflict(2, 4, IX);
+ lock_ok_a(1, 4, LS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+ unlock_all(4);
+
+ lock_ok_i(1, 1, IX);
+ lock_ok_i(2, 1, IX);
+ lock_conflict(1, 1, S);
+ lock_conflict(2, 1, X);
+ unlock_all(1);
+ unlock_all(2);
+
+ lock_ok_i(1, 1, IS);
+ lock_conflict(2, 1, X);
+ lock_conflict(3, 1, IS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+
+ lock_ok_a(1, 1, S);
+ lock_conflict(2, 1, IX);
+ lock_conflict(3, 1, IS);
+ unlock_all(1);
+ unlock_all(2);
+ unlock_all(3);
+}
+
+int rt_num_threads;
+int litmus;
+int thread_number= 0, timeouts= 0;
+void run_test(const char *test, pthread_handler handler, int n, int m)
+{
+ pthread_t *threads;
+ ulonglong now= my_getsystime();
+ int i;
+
+ thread_number= timeouts= 0;
+ litmus= 0;
+
+ threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
+ if (!threads)
+ {
+ diag("Out of memory");
+ abort();
+ }
+
+ diag("Running %s with %d threads, %d iterations... ", test, n, m);
+ rt_num_threads= n;
+ for (i= 0; i < n ; i++)
+ if (pthread_create(threads+i, 0, handler, &m))
+ {
+ diag("Could not create thread");
+ abort();
+ }
+ for (i= 0 ; i < n ; i++)
+ pthread_join(threads[i], 0);
+ now= my_getsystime()-now;
+ ok(litmus == 0, "Finished %s in %g secs (%d)", test, ((double)now)/1e7, litmus);
+ my_free((void*)threads, MYF(0));
+}
+
+static void reinit_tlo(TABLOCKMAN *lm, TABLE_LOCK_OWNER *lo)
+{
+#ifdef NOT_USED_YET
+ TABLE_LOCK_OWNER backup= *lo;
+#endif
+
+ tablockman_release_locks(lm, lo);
+#ifdef NOT_USED_YET
+ pthread_mutex_destroy(lo->mutex);
+ pthread_cond_destroy(lo->cond);
+ bzero(lo, sizeof(*lo));
+
+ lo->mutex= backup.mutex;
+ lo->cond= backup.cond;
+ lo->loid= backup.loid;
+ pthread_mutex_init(lo->mutex, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(lo->cond, 0);
+#endif
+}
+
+pthread_mutex_t rt_mutex;
+int Nrows= 100;
+int Ntables= 10;
+int table_lock_ratio= 10;
+enum lockman_lock_type lock_array[6]= {S, X, LS, LX, IS, IX};
+const char *lock2str[6]= {"S", "X", "LS", "LX", "IS", "IX"};
+const char *res2str[]= {
+ 0,
+ "OUT OF MEMORY",
+ "DEADLOCK",
+ "LOCK TIMEOUT",
+ "GOT THE LOCK",
+ "GOT THE LOCK NEED TO LOCK A SUBRESOURCE",
+ "GOT THE LOCK NEED TO INSTANT LOCK A SUBRESOURCE"};
+
+pthread_handler_t test_lockman(void *arg)
+{
+ int m= (*(int *)arg);
+ uint x, loid, row, table, res, locklevel, timeout= 0;
+ TABLE_LOCK_OWNER *lo1;
+ DBUG_ASSERT(Ntables <= Ntbls);
+ DBUG_ASSERT(Nrows + Ntables <= Ntbls);
+
+ pthread_mutex_lock(&rt_mutex);
+ loid= ++thread_number;
+ pthread_mutex_unlock(&rt_mutex);
+ lo1= loid2lo1(loid);
+
+ for (x= ((int)(intptr)(&m)); m > 0; m--)
+ {
+ /* three prime numbers */
+ x= (uint) ((x*LL(3628273133) + LL(1500450271)) % LL(9576890767));
+ row= x % Nrows + Ntables;
+ table= row % Ntables;
+ locklevel= (x/Nrows) & 3;
+ if (table_lock_ratio && (x/Nrows/4) % table_lock_ratio == 0)
+ {
+ /* table lock */
+ res= tablockman_getlock(&tablockman, lo1, ltarray+table,
+ lock_array[locklevel]);
+ DIAG(("loid %2d, table %d, lock %s, res %s", loid, table,
+ lock2str[locklevel], res2str[res]));
+ if (res < GOT_THE_LOCK)
+ {
+ reinit_tlo(&tablockman, lo1);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ DBUG_ASSERT(res == GOT_THE_LOCK);
+ }
+ else
+ { /* row lock */
+ locklevel&= 1;
+ res= tablockman_getlock(&tablockman, lo1, ltarray+table, lock_array[locklevel + 4]);
+ DIAG(("loid %2d, row %d, lock %s, res %s", loid, row,
+ lock2str[locklevel+4], res2str[res]));
+ switch (res)
+ {
+ case GOT_THE_LOCK:
+ continue;
+ case GOT_THE_LOCK_NEED_TO_INSTANT_LOCK_A_SUBRESOURCE:
+ /* not implemented, so take a regular lock */
+ case GOT_THE_LOCK_NEED_TO_LOCK_A_SUBRESOURCE:
+ res= tablockman_getlock(&tablockman, lo1, ltarray+row, lock_array[locklevel]);
+ DIAG(("loid %2d, ROW %d, lock %s, res %s", loid, row,
+ lock2str[locklevel], res2str[res]));
+ if (res < GOT_THE_LOCK)
+ {
+ reinit_tlo(&tablockman, lo1);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ DBUG_ASSERT(res == GOT_THE_LOCK);
+ continue;
+ default:
+ reinit_tlo(&tablockman, lo1);
+ DIAG(("loid %2d, release all locks", loid));
+ timeout++;
+ continue;
+ }
+ }
+ }
+
+ reinit_tlo(&tablockman, lo1);
+
+ pthread_mutex_lock(&rt_mutex);
+ rt_num_threads--;
+ timeouts+= timeout;
+ if (!rt_num_threads)
+ diag("number of timeouts: %d", timeouts);
+ pthread_mutex_unlock(&rt_mutex);
+
+ return 0;
+}
+
+int main(int argc __attribute__((unused)), char **argv)
+{
+ int i;
+ MY_INIT(argv[0]);
+
+ my_init();
+ pthread_mutex_init(&rt_mutex, 0);
+
+ plan(40);
+
+ if (my_atomic_initialize())
+ return exit_status();
+
+
+ tablockman_init(&tablockman, &loid2lo1, 50);
+
+ for (i= 0; i < Nlos; i++)
+ {
+ pthread_mutex_init(&mutexes[i], MY_MUTEX_INIT_FAST);
+ pthread_cond_init (&conds[i], 0);
+
+ loarray1[i].active_locks= 0;
+ loarray1[i].waiting_lock= 0;
+ loarray1[i].waiting_for= 0;
+ loarray1[i].mutex= &mutexes[i];
+ loarray1[i].cond= &conds[i];
+ loarray1[i].loid= i+1;
+ }
+
+ for (i= 0; i < Ntbls; i++)
+ {
+ tablockman_init_locked_table(ltarray+i, Nlos);
+ }
+
+ test_tablockman_simple();
+
+#define CYCLES 10000
+#define THREADS Nlos /* don't change this line */
+
+ /* mixed load, stress-test with random locks */
+ Nrows= 100;
+ Ntables= 10;
+ table_lock_ratio= 10;
+ run_test("\"random lock\" stress test", test_lockman, THREADS, CYCLES);
+#if 0
+ /* "real-life" simulation - many rows, no table locks */
+ Nrows= 1000000;
+ Ntables= 10;
+ table_lock_ratio= 0;
+ run_test("\"real-life\" simulation test", test_lockman, THREADS, CYCLES*10);
+#endif
+ for (i= 0; i < Nlos; i++)
+ {
+ tablockman_release_locks(&tablockman, &loarray1[i]);
+ pthread_mutex_destroy(loarray1[i].mutex);
+ pthread_cond_destroy(loarray1[i].cond);
+ }
+
+ {
+ ulonglong now= my_getsystime();
+ for (i= 0; i < Ntbls; i++)
+ {
+ tablockman_destroy_locked_table(ltarray+i);
+ }
+ tablockman_destroy(&tablockman);
+ now= my_getsystime()-now;
+ diag("lockman_destroy: %g secs", ((double)now)/1e7);
+ }
+
+ pthread_mutex_destroy(&rt_mutex);
+ my_end(0);
+ return exit_status();
+}
+
diff --git a/storage/maria/unittest/ma_control_file-t.c b/storage/maria/unittest/ma_control_file-t.c
new file mode 100644
index 00000000000..6702e4deb2f
--- /dev/null
+++ b/storage/maria/unittest/ma_control_file-t.c
@@ -0,0 +1,592 @@
+/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Unit test of the control file module of the Maria engine WL#3234 */
+
+/*
+ Note that it is not possible to test the durability of the write (can't
+ pull the plug programmatically :)
+*/
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <tap.h>
+
+#ifndef WITH_MARIA_STORAGE_ENGINE
+/*
+ If Maria is not compiled in, normally we don't come to building this test.
+*/
+#error "Maria engine is not compiled in, test cannot be built"
+#endif
+
+#include "maria.h"
+#include "../../../storage/maria/maria_def.h"
+#include <my_getopt.h>
+
+#define EXTRACT_DEFINITIONS
+#include "../ma_control_file.c"
+#undef EXTRACT_DEFINITIONS
+
+char file_name[FN_REFLEN];
+
+/* The values we'll set and expect the control file module to return */
+LSN expect_checkpoint_lsn;
+uint32 expect_logno;
+TrID expect_max_trid;
+uint8 expect_recovery_failures;
+
+static int delete_file(myf my_flags);
+/*
+ Those are test-specific wrappers around the module's API functions: after
+ calling the module's API functions they perform checks on the result.
+*/
+static int close_file(void); /* wraps ma_control_file_end */
+/* wraps ma_control_file_open_or_create */
+static int open_file(void);
+/* wraps ma_control_file_write_and_force */
+static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
+ uint8 rec_failures);
+
+/* Tests */
+static int test_one_log_and_recovery_failures(void);
+static int test_five_logs_and_max_trid(void);
+static int test_3_checkpoints_and_2_logs(void);
+static int test_binary_content(void);
+static int test_start_stop(void);
+static int test_2_open_and_2_close(void);
+static int test_bad_magic_string(void);
+static int test_bad_checksum(void);
+static int test_bad_hchecksum(void);
+static int test_future_size(void);
+static int test_bad_blocksize(void);
+static int test_bad_size(void);
+
+/* Utility */
+static int verify_module_values_match_expected(void);
+static int verify_module_values_are_impossible(void);
+static void usage(void);
+static void get_options(int argc, char *argv[]);
+
+/*
+ If "expr" is FALSE, this macro will make the function print a diagnostic
+ message and immediately return 1.
+ This is inspired from assert() but does not crash the binary (sometimes we
+ may want to see how other tests go even if one fails).
+ RET_ERR means "return error".
+*/
+
+#define RET_ERR_UNLESS(expr) \
+ {if (!(expr)) {diag("line %d: failure: '%s'", __LINE__, #expr); assert(0);return 1;}}
+
+
+/* Used to ignore error messages from ma_control_file_open() */
+
+static int my_ignore_message(uint error __attribute__((unused)),
+ const char *str __attribute__((unused)),
+ myf MyFlags __attribute__((unused)))
+{
+ DBUG_ENTER("my_message_no_curses");
+ DBUG_PRINT("enter",("message: %s",str));
+ DBUG_RETURN(0);
+}
+
+int (*default_error_handler_hook)(uint my_err, const char *str,
+ myf MyFlags) = 0;
+
+
+/* like ma_control_file_open(), but without error messages */
+
+static CONTROL_FILE_ERROR local_ma_control_file_open(void)
+{
+ CONTROL_FILE_ERROR error;
+ error_handler_hook= my_ignore_message;
+ error= ma_control_file_open(TRUE, TRUE);
+ error_handler_hook= default_error_handler_hook;
+ return error;
+}
+
+
+
+int main(int argc,char *argv[])
+{
+ MY_INIT(argv[0]);
+ my_init();
+
+ maria_data_root= (char *)".";
+ default_error_handler_hook= error_handler_hook;
+
+ plan(12);
+
+ diag("Unit tests for control file");
+
+ get_options(argc,argv);
+
+ diag("Deleting control file at startup, if there is an old one");
+ RET_ERR_UNLESS(0 == delete_file(0)); /* if fails, can't continue */
+
+ diag("Tests of normal conditions");
+ ok(0 == test_one_log_and_recovery_failures(),
+ "test of creating one log and recording recovery failures");
+ ok(0 == test_five_logs_and_max_trid(),
+ "test of creating five logs and many transactions");
+ ok(0 == test_3_checkpoints_and_2_logs(),
+ "test of creating three checkpoints and two logs");
+ ok(0 == test_binary_content(), "test of the binary content of the file");
+ ok(0 == test_start_stop(), "test of multiple starts and stops");
+ diag("Tests of abnormal conditions");
+ ok(0 == test_2_open_and_2_close(),
+ "test of two open and two close (strange call sequence)");
+ ok(0 == test_bad_magic_string(), "test of bad magic string");
+ ok(0 == test_bad_checksum(), "test of bad checksum");
+ ok(0 == test_bad_hchecksum(), "test of bad hchecksum");
+ ok(0 == test_future_size(), "test of ability to handlr future versions");
+ ok(0 == test_bad_blocksize(), "test of bad blocksize");
+ ok(0 == test_bad_size(), "test of too small/big file");
+
+ return exit_status();
+}
+
+
+static int delete_file(myf my_flags)
+{
+ RET_ERR_UNLESS(fn_format(file_name, CONTROL_FILE_BASE_NAME,
+ maria_data_root, "", MYF(MY_WME)) != NullS);
+ /*
+ Maybe file does not exist, ignore error.
+ The error will however be printed on stderr.
+ */
+ my_delete(file_name, my_flags);
+ expect_checkpoint_lsn= LSN_IMPOSSIBLE;
+ expect_logno= FILENO_IMPOSSIBLE;
+ expect_max_trid= expect_recovery_failures= 0;
+
+ return 0;
+}
+
+/*
+ Verifies that global values last_checkpoint_lsn, last_logno,
+ max_trid_in_control_file (belonging to the module) match what we expect.
+*/
+static int verify_module_values_match_expected(void)
+{
+ RET_ERR_UNLESS(last_logno == expect_logno);
+ RET_ERR_UNLESS(last_checkpoint_lsn == expect_checkpoint_lsn);
+ RET_ERR_UNLESS(max_trid_in_control_file == expect_max_trid);
+ RET_ERR_UNLESS(recovery_failures == expect_recovery_failures);
+ return 0;
+}
+
+
+/*
+ Verifies that global values last_checkpoint_lsn and last_logno (belonging
+ to the module) are impossible (this is used when the file has been closed).
+*/
+static int verify_module_values_are_impossible(void)
+{
+ RET_ERR_UNLESS(last_logno == FILENO_IMPOSSIBLE);
+ RET_ERR_UNLESS(last_checkpoint_lsn == LSN_IMPOSSIBLE);
+ RET_ERR_UNLESS(max_trid_in_control_file == 0);
+ return 0;
+}
+
+
+static int close_file(void)
+{
+ /* Simulate shutdown */
+ ma_control_file_end();
+ /* Verify amnesia */
+ RET_ERR_UNLESS(verify_module_values_are_impossible() == 0);
+ return 0;
+}
+
+static int open_file(void)
+{
+ RET_ERR_UNLESS(local_ma_control_file_open() == CONTROL_FILE_OK);
+ /* Check that the module reports expected information */
+ RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
+ return 0;
+}
+
+static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
+ uint8 rec_failures)
+{
+ RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno, trid,
+ rec_failures)
+ == 0);
+ /* Check that the module reports expected information */
+ RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
+ return 0;
+}
+
+static int test_one_log_and_recovery_failures(void)
+{
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ expect_logno= 123;
+ RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
+ max_trid_in_control_file,
+ recovery_failures) == 0);
+ expect_recovery_failures= 158;
+ RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
+ max_trid_in_control_file,
+ expect_recovery_failures) == 0);
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+static int test_five_logs_and_max_trid(void)
+{
+ uint i;
+
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ expect_logno= 100;
+ expect_max_trid= ULL(14111978111);
+ for (i= 0; i<5; i++)
+ {
+ expect_logno*= 3;
+ RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
+ expect_max_trid,
+ recovery_failures) == 0);
+ }
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+static int test_3_checkpoints_and_2_logs(void)
+{
+ /*
+ Simulate one checkpoint, one log creation, two checkpoints, one
+ log creation.
+ */
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ expect_checkpoint_lsn= MAKE_LSN(5, 10000);
+ RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
+ max_trid_in_control_file,
+ recovery_failures) == 0);
+
+ expect_logno= 17;
+ RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
+ max_trid_in_control_file,
+ recovery_failures) == 0);
+
+ expect_checkpoint_lsn= MAKE_LSN(17, 20000);
+ RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
+ max_trid_in_control_file,
+ recovery_failures) == 0);
+
+ expect_checkpoint_lsn= MAKE_LSN(17, 45000);
+ RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
+ max_trid_in_control_file,
+ recovery_failures) == 0);
+
+ expect_logno= 19;
+ RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
+ max_trid_in_control_file,
+ recovery_failures) == 0);
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+static int test_binary_content(void)
+{
+ uint i;
+ int fd;
+
+ /*
+ TEST4: actually check by ourselves the content of the file.
+ Note that constants (offsets) are hard-coded here, precisely to prevent
+ someone from changing them in the control file module and breaking
+ backward-compatibility.
+ TODO: when we reach the format-freeze state, we may even just do a
+ comparison with a raw binary string, to not depend on any uint4korr
+ future change/breakage.
+ */
+
+ uchar buffer[45];
+ RET_ERR_UNLESS((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) >= 0);
+ RET_ERR_UNLESS(my_read(fd, buffer, 45, MYF(MY_FNABP | MY_WME)) == 0);
+ RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ i= uint3korr(buffer + 34 );
+ RET_ERR_UNLESS(i == LSN_FILE_NO(last_checkpoint_lsn));
+ i= uint4korr(buffer + 37);
+ RET_ERR_UNLESS(i == LSN_OFFSET(last_checkpoint_lsn));
+ i= uint4korr(buffer + 41);
+ RET_ERR_UNLESS(i == last_logno);
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+static int test_start_stop(void)
+{
+ /* TEST5: Simulate start/nothing/stop/start/nothing/stop/start */
+
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+static int test_2_open_and_2_close(void)
+{
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+
+static int test_bad_magic_string(void)
+{
+ uchar buffer[4];
+ int fd;
+
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+
+ /* Corrupt magic string */
+ RET_ERR_UNLESS((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) >= 0);
+ RET_ERR_UNLESS(my_pread(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0);
+ RET_ERR_UNLESS(my_pwrite(fd, (const uchar *)"papa", 4, 0,
+ MYF(MY_FNABP | MY_WME)) == 0);
+
+ /* Check that control file module sees the problem */
+ RET_ERR_UNLESS(local_ma_control_file_open() ==
+ CONTROL_FILE_BAD_MAGIC_STRING);
+ /* Restore magic string */
+ RET_ERR_UNLESS(my_pwrite(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0);
+ RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+static int test_bad_checksum(void)
+{
+ uchar buffer[4];
+ int fd;
+
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+
+ /* Corrupt checksum */
+ RET_ERR_UNLESS((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) >= 0);
+ RET_ERR_UNLESS(my_pread(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
+ buffer[0]+= 3; /* mangle checksum */
+ RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
+ /* Check that control file module sees the problem */
+ RET_ERR_UNLESS(local_ma_control_file_open() ==
+ CONTROL_FILE_BAD_CHECKSUM);
+ /* Restore checksum */
+ buffer[0]-= 3;
+ RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
+ RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
+
+ return 0;
+}
+
+
+static int test_bad_blocksize(void)
+{
+ maria_block_size<<= 1;
+ /* Check that control file module sees the problem */
+ RET_ERR_UNLESS(local_ma_control_file_open() ==
+ CONTROL_FILE_WRONG_BLOCKSIZE);
+ /* Restore blocksize */
+ maria_block_size>>= 1;
+
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+ return 0;
+}
+
+
+static int test_future_size(void)
+{
+ /*
+ Here we check ability to add fields only so we can use
+ defined constants
+ */
+ uint32 sum;
+ int fd;
+ uchar buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 2];
+ RET_ERR_UNLESS((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) >= 0);
+ RET_ERR_UNLESS(my_read(fd, buffer,
+ CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE,
+ MYF(MY_FNABP | MY_WME)) == 0);
+ RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
+ /* "add" new field of 1 byte (value 1) to header and variable part */
+ memmove(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1,
+ buffer + CF_CREATE_TIME_TOTAL_SIZE,
+ CF_CHANGEABLE_TOTAL_SIZE);
+ buffer[CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE]= '\1';
+ buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 1]= '\1';
+ /* fix lengths */
+ int2store(buffer + CF_CREATE_TIME_SIZE_OFFSET, CF_CREATE_TIME_TOTAL_SIZE + 1);
+ int2store(buffer + CF_CHANGEABLE_SIZE_OFFSET, CF_CHANGEABLE_TOTAL_SIZE + 1);
+ /* recalculete checksums */
+ sum= (uint32) my_checksum(0, buffer, CF_CREATE_TIME_TOTAL_SIZE -
+ CF_CHECKSUM_SIZE + 1);
+ int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1, sum);
+ sum= (uint32) my_checksum(0, buffer + CF_CREATE_TIME_TOTAL_SIZE + 1 +
+ CF_CHECKSUM_SIZE,
+ CF_CHANGEABLE_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1);
+ int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1, sum);
+ /* write new file and check it */
+ RET_ERR_UNLESS((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) >= 0);
+ RET_ERR_UNLESS(my_pwrite(fd, buffer,
+ CF_CREATE_TIME_TOTAL_SIZE +
+ CF_CHANGEABLE_TOTAL_SIZE + 2,
+ 0, MYF(MY_FNABP | MY_WME)) == 0);
+ RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+
+ return(0);
+}
+
+static int test_bad_hchecksum(void)
+{
+ uchar buffer[4];
+ int fd;
+
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+
+ /* Corrupt checksum */
+ RET_ERR_UNLESS((fd= my_open(file_name,
+ O_BINARY | O_RDWR,
+ MYF(MY_WME))) >= 0);
+ RET_ERR_UNLESS(my_pread(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
+ buffer[0]+= 3; /* mangle checksum */
+ RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
+ /* Check that control file module sees the problem */
+ RET_ERR_UNLESS(local_ma_control_file_open() ==
+ CONTROL_FILE_BAD_HEAD_CHECKSUM);
+ /* Restore checksum */
+ buffer[0]-= 3;
+ RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
+ RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
+
+ return 0;
+}
+
+
+static int test_bad_size(void)
+{
+ uchar buffer[]=
+ "123456789012345678901234567890123456789012345678901234567890123456";
+ int fd, i;
+
+ /* A too short file */
+ RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0);
+ RET_ERR_UNLESS((fd= my_open(file_name,
+ O_BINARY | O_RDWR | O_CREAT,
+ MYF(MY_WME))) >= 0);
+ RET_ERR_UNLESS(my_write(fd, buffer, 10, MYF(MY_FNABP | MY_WME)) == 0);
+ /* Check that control file module sees the problem */
+ RET_ERR_UNLESS(local_ma_control_file_open() ==
+ CONTROL_FILE_TOO_SMALL);
+ for (i= 0; i < 8; i++)
+ {
+ RET_ERR_UNLESS(my_write(fd, buffer, 66, MYF(MY_FNABP | MY_WME)) == 0);
+ }
+ /* Check that control file module sees the problem */
+ RET_ERR_UNLESS(local_ma_control_file_open() ==
+ CONTROL_FILE_TOO_BIG);
+ RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
+
+ /* Leave a correct control file */
+ RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0);
+ RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
+ RET_ERR_UNLESS(close_file() == 0);
+
+ return 0;
+}
+
+
+static struct my_option my_long_options[] =
+{
+#ifndef DBUG_OFF
+ {"debug", '#', "Debug log.",
+ 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"help", '?', "Display help and exit",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"version", 'V', "Print version number and exit",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+static void version(void)
+{
+ printf("ma_control_file_test: unit test for the control file "
+ "module of the Maria storage engine. Ver 1.0 \n");
+}
+
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch(optid) {
+ case 'V':
+ version();
+ exit(0);
+ case '#':
+ DBUG_PUSH (argument);
+ break;
+ case '?':
+ version();
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+
+/* Read options */
+
+static void get_options(int argc, char *argv[])
+{
+ int ho_error;
+
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ get_one_option)))
+ exit(ho_error);
+
+ return;
+} /* get options */
+
+
+static void usage(void)
+{
+ printf("Usage: %s [options]\n\n", my_progname);
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
diff --git a/storage/maria/unittest/ma_loghandler_examples.c b/storage/maria/unittest/ma_loghandler_examples.c
new file mode 100644
index 00000000000..0c11a3b9a8e
--- /dev/null
+++ b/storage/maria/unittest/ma_loghandler_examples.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+
+static LOG_DESC INIT_LOGREC_FIXED_RECORD_0LSN_EXAMPLE=
+{LOGRECTYPE_FIXEDLENGTH, 6, 6, NULL, NULL, NULL, 0,
+ "fixed0example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 9, NULL, NULL, NULL, 0,
+"variable0example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_FIXED_RECORD_1LSN_EXAMPLE=
+{LOGRECTYPE_PSEUDOFIXEDLENGTH, 7, 7, NULL, NULL, NULL, 1,
+"fixed1example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 12, NULL, NULL, NULL, 1,
+"variable1example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_FIXED_RECORD_2LSN_EXAMPLE=
+{LOGRECTYPE_PSEUDOFIXEDLENGTH, 23, 23, NULL, NULL, NULL, 2,
+"fixed2example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+static LOG_DESC INIT_LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE=
+{LOGRECTYPE_VARIABLE_LENGTH, 0, 19, NULL, NULL, NULL, 2,
+"variable2example", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
+
+
+void translog_example_table_init()
+{
+ int i;
+ log_record_type_descriptor[LOGREC_FIXED_RECORD_0LSN_EXAMPLE]=
+ INIT_LOGREC_FIXED_RECORD_0LSN_EXAMPLE;
+ log_record_type_descriptor[LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE]=
+ INIT_LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE;
+ log_record_type_descriptor[LOGREC_FIXED_RECORD_1LSN_EXAMPLE]=
+ INIT_LOGREC_FIXED_RECORD_1LSN_EXAMPLE;
+ log_record_type_descriptor[LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE]=
+ INIT_LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE;
+ log_record_type_descriptor[LOGREC_FIXED_RECORD_2LSN_EXAMPLE]=
+ INIT_LOGREC_FIXED_RECORD_2LSN_EXAMPLE;
+ log_record_type_descriptor[LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE]=
+ INIT_LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE;
+ for (i= LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE + 1;
+ i < LOGREC_NUMBER_OF_TYPES;
+ i++)
+ log_record_type_descriptor[i].rclass= LOGRECTYPE_NOT_ALLOWED;
+}
+
+
+
diff --git a/storage/maria/unittest/ma_maria_log_cleanup.c b/storage/maria/unittest/ma_maria_log_cleanup.c
new file mode 100644
index 00000000000..7c78bf3a1a4
--- /dev/null
+++ b/storage/maria/unittest/ma_maria_log_cleanup.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <my_dir.h>
+
+my_bool maria_log_remove()
+{
+ MY_DIR *dirp;
+ uint i;
+ MY_STAT stat_buff;
+ char file_name[FN_REFLEN];
+
+ /* Removes control file */
+ if (fn_format(file_name, CONTROL_FILE_BASE_NAME,
+ maria_data_root, "", MYF(MY_WME)) == NullS)
+ return 1;
+ if (my_stat(file_name, &stat_buff, MYF(0)) &&
+ my_delete(file_name, MYF(MY_WME)) != 0)
+ return 1;
+
+ /* Finds and removes transaction log files */
+ if (!(dirp = my_dir(maria_data_root, MYF(MY_DONT_SORT))))
+ return 1;
+
+ for (i= 0; i < dirp->number_off_files; i++)
+ {
+ char *file= dirp->dir_entry[i].name;
+ if (strncmp(file, "maria_log.", 10) == 0 &&
+ file[10] >= '0' && file[10] <= '9' &&
+ file[11] >= '0' && file[11] <= '9' &&
+ file[12] >= '0' && file[12] <= '9' &&
+ file[13] >= '0' && file[13] <= '9' &&
+ file[14] >= '0' && file[14] <= '9' &&
+ file[15] >= '0' && file[15] <= '9' &&
+ file[16] >= '0' && file[16] <= '9' &&
+ file[17] >= '0' && file[17] <= '9' &&
+ file[18] == '\0')
+ {
+ if (fn_format(file_name, file,
+ maria_data_root, "", MYF(MY_WME)) == NullS ||
+ my_delete(file_name, MYF(MY_WME)) != 0)
+ {
+ my_dirend(dirp);
+ return 1;
+ }
+ }
+ }
+ my_dirend(dirp);
+ return 0;
+}
+
diff --git a/storage/maria/unittest/ma_pagecache_consist.c b/storage/maria/unittest/ma_pagecache_consist.c
new file mode 100644
index 00000000000..7dbdba433c6
--- /dev/null
+++ b/storage/maria/unittest/ma_pagecache_consist.c
@@ -0,0 +1,498 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ TODO: use pthread_join instead of wait_for_thread_count_to_be_zero, like in
+ my_atomic-t.c (see BUG#22320).
+*/
+
+#include <tap.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "test_file.h"
+#include <tap.h>
+
+#define PCACHE_SIZE (TEST_PAGE_SIZE*1024*8)
+
+#ifndef DBUG_OFF
+static const char* default_dbug_option;
+#endif
+
+static char *file1_name= (char*)"page_cache_test_file_1";
+static PAGECACHE_FILE file1;
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+static PAGECACHE pagecache;
+
+#ifdef TEST_HIGH_CONCURENCY
+static uint number_of_readers= 10;
+static uint number_of_writers= 20;
+static uint number_of_tests= 30000;
+static uint record_length_limit= TEST_PAGE_SIZE/200;
+static uint number_of_pages= 20;
+static uint flush_divider= 1000;
+#else /*TEST_HIGH_CONCURENCY*/
+#ifdef TEST_READERS
+static uint number_of_readers= 10;
+static uint number_of_writers= 1;
+static uint number_of_tests= 30000;
+static uint record_length_limit= TEST_PAGE_SIZE/200;
+static uint number_of_pages= 20;
+static uint flush_divider= 1000;
+#undef SKIP_BIG_TESTS
+#define SKIP_BIG_TESTS(X) /* no-op */
+#else /*TEST_READERS*/
+#ifdef TEST_WRITERS
+static uint number_of_readers= 0;
+static uint number_of_writers= 10;
+static uint number_of_tests= 30000;
+static uint record_length_limit= TEST_PAGE_SIZE/200;
+static uint number_of_pages= 20;
+static uint flush_divider= 1000;
+#undef SKIP_BIG_TESTS
+#define SKIP_BIG_TESTS(X) /* no-op */
+#else /*TEST_WRITERS*/
+static uint number_of_readers= 10;
+static uint number_of_writers= 10;
+static uint number_of_tests= 50000;
+static uint record_length_limit= TEST_PAGE_SIZE/200;
+static uint number_of_pages= 20000;
+static uint flush_divider= 1000;
+#endif /*TEST_WRITERS*/
+#endif /*TEST_READERS*/
+#endif /*TEST_HIGH_CONCURENCY*/
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static my_bool
+dummy_callback(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar* data_ptr __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static void
+dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
+{
+ return;
+}
+
+
+/*
+ Get pseudo-random length of the field in (0;limit)
+
+ SYNOPSYS
+ get_len()
+ limit limit for generated value
+
+ RETURN
+ length where length >= 0 & length < limit
+*/
+
+static uint get_len(uint limit)
+{
+ return (uint)((ulonglong)rand()*(limit-1)/RAND_MAX);
+}
+
+
+/*
+ Check page's consistency: layout is
+ 4 bytes: number 'num' of records in this page, then num occurences of
+ { 4 bytes: record's length 'len'; then 4 bytes unchecked ('tag') then
+ 'len' bytes each equal to the record's sequential number in this page,
+ modulo 256 }, then zeroes.
+ */
+uint check_page(uchar *buff, ulong offset, int page_locked, int page_no,
+ int tag)
+{
+ uint end= sizeof(uint);
+ uint num= uint4korr(buff);
+ uint i;
+ DBUG_ENTER("check_page");
+
+ for (i= 0; i < num; i++)
+ {
+ uint len= uint4korr(buff + end);
+ uint j;
+ end+= 4 + 4;
+ if (len + end > TEST_PAGE_SIZE)
+ {
+ diag("incorrect field header #%u by offset %lu\n", i, offset + end);
+ goto err;
+ }
+ for(j= 0; j < len; j++)
+ {
+ if (buff[end + j] != (uchar)((i+1) % 256))
+ {
+ diag("incorrect %lu byte\n", offset + end + j);
+ goto err;
+ }
+ }
+ end+= len;
+ }
+ for(i= end; i < TEST_PAGE_SIZE; i++)
+ {
+ if (buff[i] != 0)
+ {
+ int h;
+ DBUG_PRINT("err",
+ ("byte %lu (%lu + %u), page %u (%s, end: %u, recs: %u, tag: %d) should be 0\n",
+ offset + i, offset, i, page_no,
+ (page_locked ? "locked" : "unlocked"),
+ end, num, tag));
+ diag("byte %lu (%lu + %u), page %u (%s, end: %u, recs: %u, tag: %d) should be 0\n",
+ offset + i, offset, i, page_no,
+ (page_locked ? "locked" : "unlocked"),
+ end, num, tag);
+ h= my_open("wrong_page", O_CREAT | O_TRUNC | O_RDWR, MYF(0));
+ my_pwrite(h, (uchar*) buff, TEST_PAGE_SIZE, 0, MYF(0));
+ my_close(h, MYF(0));
+ goto err;
+ }
+ }
+ DBUG_RETURN(end);
+err:
+ DBUG_PRINT("err", ("try to flush"));
+ if (page_locked)
+ {
+ pagecache_delete(&pagecache, &file1, page_no,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, 1);
+ }
+ else
+ {
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_RELEASE);
+ }
+ exit(1);
+}
+
+void put_rec(uchar *buff, uint end, uint len, uint tag)
+{
+ uint i;
+ uint num;
+ num= uint4korr(buff);
+ if (!len)
+ len= 1;
+ if (end + 4*2 + len > TEST_PAGE_SIZE)
+ return;
+ int4store(buff + end, len);
+ end+= 4;
+ int4store(buff + end, tag);
+ end+= 4;
+ num++;
+ int4store(buff, num);
+ for (i= end; i < (len + end); i++)
+ {
+ buff[i]= (uchar) num % 256;
+ }
+}
+
+/*
+ Recreate and reopen a file for test
+
+ SYNOPSIS
+ reset_file()
+ file File to reset
+ file_name Path (and name) of file which should be reset
+*/
+
+void reset_file(PAGECACHE_FILE file, char *file_name)
+{
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_RELEASE);
+ if (my_close(file1.file, MYF(0)) != 0)
+ {
+ diag("Got error during %s closing from close() (errno: %d)\n",
+ file_name, errno);
+ exit(1);
+ }
+ my_delete(file_name, MYF(0));
+ if ((file.file= my_open(file_name,
+ O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
+ {
+ diag("Got error during %s creation from open() (errno: %d)\n",
+ file_name, errno);
+ exit(1);
+ }
+}
+
+
+void reader(int num)
+{
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ uint i;
+
+ for (i= 0; i < number_of_tests; i++)
+ {
+ uint page= get_len(number_of_pages);
+ pagecache_read(&pagecache, &file1, page, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ 0);
+ check_page(buffr, page * TEST_PAGE_SIZE, 0, page, -num);
+
+ }
+ free(buffr);
+}
+
+
+void writer(int num)
+{
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ uint i;
+
+ for (i= 0; i < number_of_tests; i++)
+ {
+ uint end;
+ uint page= get_len(number_of_pages);
+ pagecache_read(&pagecache, &file1, page, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ 0);
+ end= check_page(buffr, page * TEST_PAGE_SIZE, 1, page, num);
+ put_rec(buffr, end, get_len(record_length_limit), num);
+ pagecache_write(&pagecache, &file1, page, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+
+ if (i % flush_divider == 0)
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+ }
+ free(buffr);
+}
+
+
+static void *test_thread_reader(void *arg)
+{
+ int param=*((int*) arg);
+ my_thread_init();
+ {
+ DBUG_ENTER("test_reader");
+ DBUG_PRINT("enter", ("param: %d", param));
+
+ reader(param);
+
+ DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "reader%d: done", param);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ }
+ return 0;
+}
+
+
+static void *test_thread_writer(void *arg)
+{
+ int param=*((int*) arg);
+ my_thread_init();
+ {
+ DBUG_ENTER("test_writer");
+ DBUG_PRINT("enter", ("param: %d", param));
+
+ writer(param);
+
+ DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "writer%d: done", param);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ }
+ return 0;
+}
+
+
+int main(int argc __attribute__((unused)),
+ char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int *param, error, pagen;
+
+ MY_INIT(argv[0]);
+
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\test_pagecache_consist.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/test_pagecache_consist.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ {
+ DBUG_ENTER("main");
+ DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
+ plan(number_of_writers + number_of_readers);
+ SKIP_BIG_TESTS(number_of_writers + number_of_readers)
+ {
+
+ if ((file1.file= my_open(file1_name,
+ O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
+ {
+ diag( "Got error during file1 creation from open() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ pagecache_file_init(file1, &dummy_callback, &dummy_callback,
+ &dummy_fail_callback, &dummy_callback, NULL);
+ DBUG_PRINT("info", ("file1: %d", file1.file));
+ if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
+ exit(1);
+ my_pwrite(file1.file, (const uchar *)"test file", 9, 0, MYF(0));
+
+ if ((error= pthread_cond_init(&COND_thread_count, NULL)))
+ {
+ diag( "COND_thread_count: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+ if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
+ {
+ diag( "LOCK_thread_count: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+
+ if ((error= pthread_attr_init(&thr_attr)))
+ {
+ diag("Got error: %d from pthread_attr_init (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
+ {
+ diag(
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+
+#ifdef HAVE_THR_SETCONCURRENCY
+ VOID(thr_setconcurrency(2));
+#endif
+
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TEST_PAGE_SIZE, 0)) == 0)
+ {
+ diag("Got error: init_pagecache() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ DBUG_PRINT("info", ("Page cache %d pages", pagen));
+ {
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ uint i;
+ memset(buffr, '\0', TEST_PAGE_SIZE);
+ for (i= 0; i < number_of_pages; i++)
+ {
+ pagecache_write(&pagecache, &file1, i, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ }
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+ free(buffr);
+ }
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (number_of_readers != 0 || number_of_writers != 0)
+ {
+ if (number_of_readers != 0)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= number_of_readers;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_reader,
+ (void*) param)))
+ {
+ diag("Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_readers--;
+ }
+ if (number_of_writers != 0)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= number_of_writers;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
+ (void*) param)))
+ {
+ diag("Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_writers--;
+ }
+ }
+ DBUG_PRINT("info", ("Thread started"));
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ pthread_attr_destroy(&thr_attr);
+
+ /* wait finishing */
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ if ((error= pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
+ diag("COND_thread_count: %d from pthread_cond_wait\n",error);
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("info", ("thread ended"));
+
+ end_pagecache(&pagecache, 1);
+ DBUG_PRINT("info", ("Page cache ended"));
+
+ if (my_close(file1.file, MYF(0)) != 0)
+ {
+ diag( "Got error during file1 closing from close() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ my_delete(file1_name, MYF(0));
+
+ DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
+ DBUG_PRINT("info", ("Program end"));
+
+ } /* SKIP_BIG_TESTS */
+ my_end(0);
+
+ return exit_status();
+ }
+}
diff --git a/storage/maria/unittest/ma_pagecache_rwconsist.c b/storage/maria/unittest/ma_pagecache_rwconsist.c
new file mode 100644
index 00000000000..a1a22b5e18d
--- /dev/null
+++ b/storage/maria/unittest/ma_pagecache_rwconsist.c
@@ -0,0 +1,362 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ TODO: use pthread_join instead of wait_for_thread_count_to_be_zero, like in
+ my_atomic-t.c (see BUG#22320).
+*/
+
+#include <tap.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "test_file.h"
+#include <tap.h>
+
+#define PCACHE_SIZE (TEST_PAGE_SIZE*1024*8)
+
+#ifndef DBUG_OFF
+static const char* default_dbug_option;
+#endif
+
+
+#define SLEEP my_sleep(5)
+
+static char *file1_name= (char*)"page_cache_test_file_1";
+static PAGECACHE_FILE file1;
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count= 0;
+static PAGECACHE pagecache;
+
+static uint number_of_readers= 5;
+static uint number_of_writers= 5;
+static uint number_of_read_tests= 2000;
+static uint number_of_write_tests= 1000;
+static uint read_sleep_limit= 3;
+static uint report_divisor= 50;
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static my_bool
+dummy_callback(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar* data_ptr __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static void
+dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
+{
+ return;
+}
+
+
+/**
+ @brief Checks page consistency
+
+ @param buff pointer to the page content
+ @param task task ID
+*/
+void check_page(uchar *buff, int task)
+{
+ uint i;
+ DBUG_ENTER("check_page");
+
+ for (i= 1; i < TEST_PAGE_SIZE; i++)
+ {
+ if (buff[0] != buff[i])
+ goto err;
+ }
+ DBUG_VOID_RETURN;
+err:
+ diag("Task %d char #%u '%u' != '%u'", task, i, (uint) buff[0],
+ (uint) buff[i]);
+ DBUG_PRINT("err", ("try to flush"));
+ exit(1);
+}
+
+
+
+void reader(int num)
+{
+ unsigned char *buff;
+ uint i;
+ PAGECACHE_BLOCK_LINK *link;
+
+ for (i= 0; i < number_of_read_tests; i++)
+ {
+ if (i % report_divisor == 0)
+ diag("Reader %d - %u", num, i);
+ buff= pagecache_read(&pagecache, &file1, 0, 3, NULL,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_READ,
+ &link);
+ check_page(buff, num);
+ pagecache_unlock_by_link(&pagecache, link,
+ PAGECACHE_LOCK_READ_UNLOCK,
+ PAGECACHE_UNPIN, 0, 0, 0, FALSE);
+ {
+ int lim= rand() % read_sleep_limit;
+ int j;
+ for (j= 0; j < lim; j++)
+ SLEEP;
+ }
+ }
+}
+
+
+void writer(int num)
+{
+ uint i;
+ uchar *buff;
+ PAGECACHE_BLOCK_LINK *link;
+
+ for (i= 0; i < number_of_write_tests; i++)
+ {
+ uchar c= (uchar) rand() % 256;
+
+ if (i % report_divisor == 0)
+ diag("Writer %d - %u", num, i);
+ buff= pagecache_read(&pagecache, &file1, 0, 3, NULL,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ &link);
+
+ check_page(buff, num);
+ bfill(buff, TEST_PAGE_SIZE / 2, c);
+ SLEEP;
+ bfill(buff + TEST_PAGE_SIZE/2, TEST_PAGE_SIZE / 2, c);
+ check_page(buff, num);
+ pagecache_unlock_by_link(&pagecache, link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, 0, 0, 1, FALSE);
+ SLEEP;
+ }
+}
+
+
+static void *test_thread_reader(void *arg)
+{
+ int param=*((int*) arg);
+ my_thread_init();
+ {
+ DBUG_ENTER("test_reader");
+
+ DBUG_PRINT("enter", ("param: %d", param));
+
+ reader(param);
+
+ DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "reader%d: done", param);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ }
+ return 0;
+}
+
+
+static void *test_thread_writer(void *arg)
+{
+ int param=*((int*) arg);
+ my_thread_init();
+ {
+ DBUG_ENTER("test_writer");
+
+ writer(param);
+
+ DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "writer%d: done", param);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ }
+ return 0;
+}
+
+
+int main(int argc __attribute__((unused)),
+ char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int *param, error, pagen;
+
+ MY_INIT(argv[0]);
+
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\test_pagecache_consist.trace";
+#else
+ default_dbug_option= "d:t:i:O,/tmp/test_pagecache_consist.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ {
+ DBUG_ENTER("main");
+ DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
+ plan(number_of_writers + number_of_readers);
+ SKIP_BIG_TESTS(number_of_writers + number_of_readers)
+ {
+
+ if ((file1.file= my_open(file1_name,
+ O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
+ {
+ diag( "Got error during file1 creation from open() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ pagecache_file_init(file1, &dummy_callback, &dummy_callback,
+ &dummy_fail_callback, &dummy_callback, NULL);
+ DBUG_PRINT("info", ("file1: %d", file1.file));
+ if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
+ exit(1);
+ my_pwrite(file1.file, (const uchar*) "test file", 9, 0, MYF(0));
+
+ if ((error= pthread_cond_init(&COND_thread_count, NULL)))
+ {
+ diag( "COND_thread_count: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+ if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
+ {
+ diag( "LOCK_thread_count: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+
+ if ((error= pthread_attr_init(&thr_attr)))
+ {
+ diag("Got error: %d from pthread_attr_init (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
+ {
+ diag(
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+
+#ifdef HAVE_THR_SETCONCURRENCY
+ VOID(thr_setconcurrency(2));
+#endif
+
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TEST_PAGE_SIZE, 0)) == 0)
+ {
+ diag("Got error: init_pagecache() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ DBUG_PRINT("info", ("Page cache %d pages", pagen));
+ {
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ memset(buffr, '\0', TEST_PAGE_SIZE);
+ pagecache_write(&pagecache, &file1, 0, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ }
+ pthread_mutex_lock(&LOCK_thread_count);
+
+ while (number_of_readers != 0 || number_of_writers != 0)
+ {
+ if (number_of_readers != 0)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= number_of_readers + number_of_writers;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_reader,
+ (void*) param)))
+ {
+ diag("Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_readers--;
+ }
+ if (number_of_writers != 0)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= number_of_writers + number_of_readers;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
+ (void*) param)))
+ {
+ diag("Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_writers--;
+ }
+ }
+ DBUG_PRINT("info", ("Thread started"));
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ pthread_attr_destroy(&thr_attr);
+
+ /* wait finishing */
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ if ((error= pthread_cond_wait(&COND_thread_count, &LOCK_thread_count)))
+ diag("COND_thread_count: %d from pthread_cond_wait\n", error);
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("info", ("thread ended"));
+
+ end_pagecache(&pagecache, 1);
+ DBUG_PRINT("info", ("Page cache ended"));
+
+ if (my_close(file1.file, MYF(0)) != 0)
+ {
+ diag( "Got error during file1 closing from close() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ my_delete(file1_name, MYF(0));
+
+ DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
+ DBUG_PRINT("info", ("Program end"));
+ } /* SKIP_BIG_TESTS */
+ my_end(0);
+
+ return exit_status();
+ }
+}
diff --git a/storage/maria/unittest/ma_pagecache_rwconsist2.c b/storage/maria/unittest/ma_pagecache_rwconsist2.c
new file mode 100644
index 00000000000..34183a2d0ab
--- /dev/null
+++ b/storage/maria/unittest/ma_pagecache_rwconsist2.c
@@ -0,0 +1,358 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+/**
+ @file this unit tests consistence of long block writing under write lock
+ and simultaneous reading of this block with read request without read lock
+ requirement.
+*/
+
+/*
+ TODO: use pthread_join instead of wait_for_thread_count_to_be_zero, like in
+ my_atomic-t.c (see BUG#22320).
+*/
+
+#include <tap.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "test_file.h"
+#include <tap.h>
+
+#define PCACHE_SIZE (TEST_PAGE_SIZE*1024*8)
+
+#ifndef DBUG_OFF
+static const char* default_dbug_option;
+#endif
+
+
+#define SLEEP my_sleep(5)
+
+static char *file1_name= (char*)"page_cache_test_file_1";
+static PAGECACHE_FILE file1;
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count= 0;
+static PAGECACHE pagecache;
+
+static uint number_of_readers= 5;
+static uint number_of_writers= 5;
+static uint number_of_read_tests= 20000;
+static uint number_of_write_tests= 1000;
+static uint report_divisor= 50;
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static my_bool
+dummy_callback(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar* data_ptr __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static void
+dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
+{
+ return;
+}
+
+
+/**
+ @brief Checks page consistency
+
+ @param buff pointer to the page content
+ @param task task ID
+*/
+void check_page(uchar *buff, int task)
+{
+ uint i;
+ DBUG_ENTER("check_page");
+
+ for (i= 1; i < TEST_PAGE_SIZE; i++)
+ {
+ if (buff[0] != buff[i])
+ goto err;
+ }
+ DBUG_VOID_RETURN;
+err:
+ diag("Task %d char #%u '%u' != '%u'", task, i, (uint) buff[0],
+ (uint) buff[i]);
+ DBUG_PRINT("err", ("try to flush"));
+ exit(1);
+}
+
+
+
+void reader(int num)
+{
+ unsigned char buff[TEST_PAGE_SIZE];
+ uint i;
+
+ for (i= 0; i < number_of_read_tests; i++)
+ {
+ if (i % report_divisor == 0)
+ diag("Reader %d - %u", num, i);
+ pagecache_read(&pagecache, &file1, 0, 3, buff,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ NULL);
+ check_page(buff, num);
+ }
+}
+
+
+void writer(int num)
+{
+ uint i;
+ uchar *buff;
+ PAGECACHE_BLOCK_LINK *link;
+
+ for (i= 0; i < number_of_write_tests; i++)
+ {
+ uchar c= (uchar) rand() % 256;
+
+ if (i % report_divisor == 0)
+ diag("Writer %d - %u", num, i);
+ buff= pagecache_read(&pagecache, &file1, 0, 3, NULL,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ &link);
+
+ check_page(buff, num);
+ bfill(buff, TEST_PAGE_SIZE / 2, c);
+ SLEEP;
+ bfill(buff + TEST_PAGE_SIZE/2, TEST_PAGE_SIZE / 2, c);
+ check_page(buff, num);
+ pagecache_unlock_by_link(&pagecache, link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN, 0, 0, 1, FALSE);
+ SLEEP;
+ }
+}
+
+
+static void *test_thread_reader(void *arg)
+{
+ int param=*((int*) arg);
+ my_thread_init();
+ {
+ DBUG_ENTER("test_reader");
+
+ DBUG_PRINT("enter", ("param: %d", param));
+
+ reader(param);
+
+ DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "reader%d: done", param);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ }
+ return 0;
+}
+
+
+static void *test_thread_writer(void *arg)
+{
+ int param=*((int*) arg);
+ my_thread_init();
+ {
+ DBUG_ENTER("test_writer");
+
+ writer(param);
+
+ DBUG_PRINT("info", ("Thread %s ended", my_thread_name()));
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "writer%d: done", param);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ }
+ return 0;
+}
+
+
+int main(int argc __attribute__((unused)),
+ char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int *param, error, pagen;
+
+ MY_INIT(argv[0]);
+
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\test_pagecache_consist.trace";
+#else
+ default_dbug_option= "d:t:i:O,/tmp/test_pagecache_consist.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ {
+ DBUG_ENTER("main");
+ DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
+ plan(number_of_writers + number_of_readers);
+ SKIP_BIG_TESTS(number_of_writers + number_of_readers)
+ {
+
+ if ((file1.file= my_open(file1_name,
+ O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
+ {
+ diag( "Got error during file1 creation from open() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ pagecache_file_init(file1, &dummy_callback, &dummy_callback,
+ &dummy_fail_callback, &dummy_callback, NULL);
+ DBUG_PRINT("info", ("file1: %d", file1.file));
+ if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
+ exit(1);
+ my_pwrite(file1.file, (const uchar*) "test file", 9, 0, MYF(0));
+
+ if ((error= pthread_cond_init(&COND_thread_count, NULL)))
+ {
+ diag( "COND_thread_count: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+ if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
+ {
+ diag( "LOCK_thread_count: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+
+ if ((error= pthread_attr_init(&thr_attr)))
+ {
+ diag("Got error: %d from pthread_attr_init (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
+ {
+ diag(
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+
+#ifdef HAVE_THR_SETCONCURRENCY
+ VOID(thr_setconcurrency(2));
+#endif
+
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TEST_PAGE_SIZE, 0)) == 0)
+ {
+ diag("Got error: init_pagecache() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ DBUG_PRINT("info", ("Page cache %d pages", pagen));
+ {
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ memset(buffr, '\0', TEST_PAGE_SIZE);
+ pagecache_write(&pagecache, &file1, 0, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ }
+ pthread_mutex_lock(&LOCK_thread_count);
+
+ while (number_of_readers != 0 || number_of_writers != 0)
+ {
+ if (number_of_readers != 0)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= number_of_readers + number_of_writers;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_reader,
+ (void*) param)))
+ {
+ diag("Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_readers--;
+ }
+ if (number_of_writers != 0)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= number_of_writers + number_of_readers;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
+ (void*) param)))
+ {
+ diag("Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_writers--;
+ }
+ }
+ DBUG_PRINT("info", ("Thread started"));
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ pthread_attr_destroy(&thr_attr);
+
+ /* wait finishing */
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ if ((error= pthread_cond_wait(&COND_thread_count, &LOCK_thread_count)))
+ diag("COND_thread_count: %d from pthread_cond_wait\n", error);
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("info", ("thread ended"));
+
+ end_pagecache(&pagecache, 1);
+ DBUG_PRINT("info", ("Page cache ended"));
+
+ if (my_close(file1.file, MYF(0)) != 0)
+ {
+ diag( "Got error during file1 closing from close() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ my_delete(file1_name, MYF(0));
+
+ DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
+ DBUG_PRINT("info", ("Program end"));
+ } /* SKIP_BIG_TESTS */
+ my_end(0);
+
+ return exit_status();
+ }
+}
diff --git a/storage/maria/unittest/ma_pagecache_single.c b/storage/maria/unittest/ma_pagecache_single.c
new file mode 100644
index 00000000000..53c820dcd2e
--- /dev/null
+++ b/storage/maria/unittest/ma_pagecache_single.c
@@ -0,0 +1,765 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ TODO: use pthread_join instead of wait_for_thread_count_to_be_zero, like in
+ my_atomic-t.c (see BUG#22320).
+ Use diag() instead of fprintf(stderr).
+*/
+#include <tap.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include "test_file.h"
+#include <tap.h>
+
+#define PCACHE_SIZE (TEST_PAGE_SIZE*1024*10)
+
+#ifndef DBUG_OFF
+static const char* default_dbug_option;
+#endif
+
+#ifndef BIG
+#undef SKIP_BIG_TESTS
+#define SKIP_BIG_TESTS(X) /* no-op */
+#endif
+
+static char *file1_name= (char*)"page_cache_test_file_1";
+static char *file2_name= (char*)"page_cache_test_file_2";
+static PAGECACHE_FILE file1;
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+static PAGECACHE pagecache;
+
+/*
+ File contance descriptors
+*/
+static struct file_desc simple_read_write_test_file[]=
+{
+ { TEST_PAGE_SIZE, '\1'},
+ {0, 0}
+};
+static struct file_desc simple_read_change_write_read_test_file[]=
+{
+ { TEST_PAGE_SIZE/2, '\65'},
+ { TEST_PAGE_SIZE/2, '\1'},
+ {0, 0}
+};
+static struct file_desc simple_pin_test_file1[]=
+{
+ { TEST_PAGE_SIZE*2, '\1'},
+ {0, 0}
+};
+static struct file_desc simple_pin_test_file2[]=
+{
+ { TEST_PAGE_SIZE/2, '\1'},
+ { TEST_PAGE_SIZE/2, (unsigned char)129},
+ { TEST_PAGE_SIZE, '\1'},
+ {0, 0}
+};
+static struct file_desc simple_pin_no_lock_test_file1[]=
+{
+ { TEST_PAGE_SIZE, '\4'},
+ {0, 0}
+};
+static struct file_desc simple_pin_no_lock_test_file2[]=
+{
+ { TEST_PAGE_SIZE, '\5'},
+ {0, 0}
+};
+static struct file_desc simple_pin_no_lock_test_file3[]=
+{
+ { TEST_PAGE_SIZE, '\6'},
+ {0, 0}
+};
+static struct file_desc simple_delete_forget_test_file[]=
+{
+ { TEST_PAGE_SIZE, '\1'},
+ {0, 0}
+};
+static struct file_desc simple_delete_flush_test_file[]=
+{
+ { TEST_PAGE_SIZE, '\2'},
+ {0, 0}
+};
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static my_bool
+dummy_callback(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar* data_ptr __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static void
+dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
+{
+ return;
+}
+
+
+/*
+ Recreate and reopen a file for test
+
+ SYNOPSIS
+ reset_file()
+ file File to reset
+ file_name Path (and name) of file which should be reset
+*/
+
+void reset_file(PAGECACHE_FILE *file, const char *file_name)
+{
+ flush_pagecache_blocks(&pagecache, file, FLUSH_RELEASE);
+ if (my_close(file->file, MYF(MY_WME)))
+ exit(1);
+ my_delete(file_name, MYF(MY_WME));
+ if ((file->file= my_open(file_name,
+ O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
+ {
+ diag("Got error during %s creation from open() (errno: %d)\n",
+ file_name, my_errno);
+ exit(1);
+ }
+}
+
+/*
+ Write then read page, check file on disk
+*/
+
+int simple_read_write_test()
+{
+ unsigned char *buffw= malloc(TEST_PAGE_SIZE);
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ int res;
+ DBUG_ENTER("simple_read_write_test");
+ bfill(buffw, TEST_PAGE_SIZE, '\1');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ pagecache_read(&pagecache, &file1, 0, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ 0);
+ ok((res= test(memcmp(buffr, buffw, TEST_PAGE_SIZE) == 0)),
+ "Simple write-read page ");
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error during flushing pagecache\n");
+ exit(1);
+ }
+ ok((res&= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_read_write_test_file))),
+ "Simple write-read page file");
+ if (res)
+ reset_file(&file1, file1_name);
+ free(buffw);
+ free(buffr);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Prepare page, then read (and lock), change (write new value and unlock),
+ then check the page in the cache and on the disk
+*/
+int simple_read_change_write_read_test()
+{
+ unsigned char *buffw= malloc(TEST_PAGE_SIZE);
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ int res, res2;
+ DBUG_ENTER("simple_read_change_write_read_test");
+
+ /* prepare the file */
+ bfill(buffw, TEST_PAGE_SIZE, '\1');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error during flushing pagecache\n");
+ exit(1);
+ }
+ /* test */
+ pagecache_read(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ 0);
+ bfill(buffw, TEST_PAGE_SIZE/2, '\65');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_UNPIN,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+
+ pagecache_read(&pagecache, &file1, 0, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ 0);
+ ok((res= test(memcmp(buffr, buffw, TEST_PAGE_SIZE) == 0)),
+ "Simple read-change-write-read page ");
+ DBUG_ASSERT(pagecache.blocks_changed == 1);
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error during flushing pagecache\n");
+ exit(1);
+ }
+ DBUG_ASSERT(pagecache.blocks_changed == 0);
+ ok((res2= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_read_change_write_read_test_file))),
+ "Simple read-change-write-read page file");
+ if (res && res2)
+ reset_file(&file1, file1_name);
+ free(buffw);
+ free(buffr);
+ DBUG_RETURN(res && res2);
+}
+
+
+/*
+ Prepare page, read page 0 (and pin) then write page 1 and page 0.
+ Flush the file (shold flush only page 1 and return 1 (page 0 is
+ still pinned).
+ Check file on the disk.
+ Unpin and flush.
+ Check file on the disk.
+*/
+int simple_pin_test()
+{
+ unsigned char *buffw= malloc(TEST_PAGE_SIZE);
+ int res;
+ DBUG_ENTER("simple_pin_test");
+ /* prepare the file */
+ bfill(buffw, TEST_PAGE_SIZE, '\1');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ /* test */
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error during flushing pagecache\n");
+ exit(1);
+ }
+ pagecache_read(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ 0);
+ pagecache_write(&pagecache, &file1, 1, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ bfill(buffw + TEST_PAGE_SIZE/2, TEST_PAGE_SIZE/2, ((unsigned char) 129));
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE_TO_READ,
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ /*
+ We have to get error because one page of the file is pinned,
+ other page should be flushed
+ */
+ if (!flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Did not get error in flush_pagecache_blocks\n");
+ res= 0;
+ goto err;
+ }
+ ok((res= test(test_file(file1, file1_name, TEST_PAGE_SIZE*2, TEST_PAGE_SIZE*2,
+ simple_pin_test_file1))),
+ "Simple pin page file with pin");
+ pagecache_unlock(&pagecache,
+ &file1,
+ 0,
+ PAGECACHE_LOCK_READ_UNLOCK,
+ PAGECACHE_UNPIN,
+ 0, 0, 0);
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error in flush_pagecache_blocks\n");
+ res= 0;
+ goto err;
+ }
+ ok((res&= test(test_file(file1, file1_name, TEST_PAGE_SIZE*2, TEST_PAGE_SIZE,
+ simple_pin_test_file2))),
+ "Simple pin page result file");
+ if (res)
+ reset_file(&file1, file1_name);
+err:
+ free(buffw);
+ DBUG_RETURN(res);
+}
+
+/*
+ Checks pins without lock.
+*/
+int simple_pin_no_lock_test()
+{
+ unsigned char *buffw= malloc(TEST_PAGE_SIZE);
+ PAGECACHE_BLOCK_LINK *link;
+ int res;
+ DBUG_ENTER("simple_pin_no_lock_test");
+ /* prepare the file */
+ bfill(buffw, TEST_PAGE_SIZE, '\4');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ /* test */
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error during flushing pagecache 2\n");
+ exit(1);
+ }
+ bfill(buffw, TEST_PAGE_SIZE, '\5');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ /*
+ We have to get error because one page of the file is pinned,
+ other page should be flushed
+ */
+ if (!flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Did not get error in flush_pagecache_blocks 2\n");
+ res= 0;
+ goto err;
+ }
+ ok((res= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_pin_no_lock_test_file1))),
+ "Simple pin (no lock) page file with pin 2");
+ pagecache_unlock(&pagecache,
+ &file1,
+ 0,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_UNPIN,
+ 0, 0, 0);
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error in flush_pagecache_blocks 2\n");
+ res= 0;
+ goto err;
+ }
+ ok((res&= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_pin_no_lock_test_file2))),
+ "Simple pin (no lock) page result file 2");
+
+ bfill(buffw, TEST_PAGE_SIZE, '\6');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ PAGECACHE_PIN,
+ PAGECACHE_WRITE_DELAY,
+ &link, LSN_IMPOSSIBLE);
+ pagecache_unlock_by_link(&pagecache, link,
+ PAGECACHE_LOCK_WRITE_UNLOCK,
+ PAGECACHE_PIN_LEFT_PINNED, 0, 0, 1, FALSE);
+ if (!flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Did not get error in flush_pagecache_blocks 3\n");
+ res= 0;
+ goto err;
+ }
+ ok((res= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_pin_no_lock_test_file2))),
+ "Simple pin (no lock) page file with pin 3");
+ pagecache_unpin_by_link(&pagecache, link, 0);
+ if (flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE))
+ {
+ diag("Got error in flush_pagecache_blocks 3\n");
+ res= 0;
+ goto err;
+ }
+ ok((res&= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_pin_no_lock_test_file3))),
+ "Simple pin (no lock) page result file 3");
+ if (res)
+ reset_file(&file1, file1_name);
+err:
+ free(buffw);
+ DBUG_RETURN(res);
+}
+/*
+ Prepare page, write new value, then delete page from cache without flush,
+ on the disk should be page with old content written during preparation
+*/
+
+int simple_delete_forget_test()
+{
+ unsigned char *buffw= malloc(TEST_PAGE_SIZE);
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ int res;
+ DBUG_ENTER("simple_delete_forget_test");
+ /* prepare the file */
+ bfill(buffw, TEST_PAGE_SIZE, '\1');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+ /* test */
+ bfill(buffw, TEST_PAGE_SIZE, '\2');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ pagecache_delete(&pagecache, &file1, 0,
+ PAGECACHE_LOCK_WRITE, 0);
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+ ok((res= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_delete_forget_test_file))),
+ "Simple delete-forget page file");
+ if (res)
+ reset_file(&file1, file1_name);
+ free(buffw);
+ free(buffr);
+ DBUG_RETURN(res);
+}
+
+/*
+ Prepare page with locking, write new content to the page,
+ delete page with flush and on existing lock,
+ check that page on disk contain new value.
+*/
+
+int simple_delete_flush_test()
+{
+ unsigned char *buffw= malloc(TEST_PAGE_SIZE);
+ unsigned char *buffr= malloc(TEST_PAGE_SIZE);
+ PAGECACHE_BLOCK_LINK *link;
+ int res;
+ DBUG_ENTER("simple_delete_flush_test");
+ /* prepare the file */
+ bfill(buffw, TEST_PAGE_SIZE, '\1');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_WRITE,
+ PAGECACHE_PIN,
+ PAGECACHE_WRITE_DELAY,
+ &link, LSN_IMPOSSIBLE);
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+ /* test */
+ bfill(buffw, TEST_PAGE_SIZE, '\2');
+ pagecache_write(&pagecache, &file1, 0, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED,
+ PAGECACHE_PIN_LEFT_PINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ if (pagecache_delete_by_link(&pagecache, link,
+ PAGECACHE_LOCK_LEFT_WRITELOCKED, 1))
+ {
+ diag("simple_delete_flush_test: error during delete");
+ exit(1);
+ }
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+ ok((res= test(test_file(file1, file1_name, TEST_PAGE_SIZE, TEST_PAGE_SIZE,
+ simple_delete_flush_test_file))),
+ "Simple delete flush (link) page file");
+ if (res)
+ reset_file(&file1, file1_name);
+ free(buffw);
+ free(buffr);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ write then read file bigger then cache
+*/
+
+int simple_big_test()
+{
+ unsigned char *buffw= (unsigned char *) my_malloc(TEST_PAGE_SIZE, MYF(MY_WME));
+ unsigned char *buffr= (unsigned char *) my_malloc(TEST_PAGE_SIZE, MYF(MY_WME));
+ struct file_desc *desc= ((struct file_desc *)
+ my_malloc((PCACHE_SIZE/(TEST_PAGE_SIZE/2) + 1) *
+ sizeof(struct file_desc), MYF(MY_WME)));
+ int res, i;
+ DBUG_ENTER("simple_big_test");
+
+ /* prepare the file twice larger then cache */
+ for (i= 0; i < PCACHE_SIZE/(TEST_PAGE_SIZE/2); i++)
+ {
+ bfill(buffw, TEST_PAGE_SIZE, (unsigned char) (i & 0xff));
+ desc[i].length= TEST_PAGE_SIZE;
+ desc[i].content= (i & 0xff);
+ pagecache_write(&pagecache, &file1, i, 3, buffw,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ }
+ desc[i].length= 0;
+ desc[i].content= '\0';
+ ok(1, "Simple big file write");
+ /* check written pages sequentally read */
+ for (i= 0; i < PCACHE_SIZE/(TEST_PAGE_SIZE/2); i++)
+ {
+ int j;
+ pagecache_read(&pagecache, &file1, i, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ 0);
+ for(j= 0; j < TEST_PAGE_SIZE; j++)
+ {
+ if (buffr[j] != (i & 0xff))
+ {
+ diag("simple_big_test seq: page %u byte %u mismatch\n", i, j);
+ res= 0;
+ goto err;
+ }
+ }
+ }
+ ok(1, "Simple big file sequential read");
+ /* chack random reads */
+ for (i= 0; i < PCACHE_SIZE/(TEST_PAGE_SIZE); i++)
+ {
+ int j, page;
+ page= rand() % (PCACHE_SIZE/(TEST_PAGE_SIZE/2));
+ pagecache_read(&pagecache, &file1, page, 3, buffr,
+ PAGECACHE_PLAIN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ 0);
+ for(j= 0; j < TEST_PAGE_SIZE; j++)
+ {
+ if (buffr[j] != (page & 0xff))
+ {
+ diag("simple_big_test rnd: page %u byte %u mismatch\n", page, j);
+ res= 0;
+ goto err;
+ }
+ }
+ }
+ ok(1, "Simple big file random read");
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+
+ ok((res= test(test_file(file1, file1_name, PCACHE_SIZE*2, TEST_PAGE_SIZE,
+ desc))),
+ "Simple big file");
+ if (res)
+ reset_file(&file1, file1_name);
+
+err:
+ my_free(buffw, 0);
+ my_free(buffr, 0);
+ my_free(desc, 0);
+ DBUG_RETURN(res);
+}
+
+
+/*
+ Thread function
+*/
+
+static void *test_thread(void *arg)
+{
+#ifndef DBUG_OFF
+ int param= *((int*) arg);
+#endif
+
+ my_thread_init();
+ {
+ DBUG_ENTER("test_thread");
+ DBUG_PRINT("enter", ("param: %d", param));
+
+ if (!simple_read_write_test() ||
+ !simple_read_change_write_read_test() ||
+ !simple_pin_test() ||
+ !simple_pin_no_lock_test() ||
+ !simple_delete_forget_test() ||
+ !simple_delete_flush_test())
+ exit(1);
+
+ SKIP_BIG_TESTS(4)
+ {
+ if (!simple_big_test())
+ exit(1);
+ }
+
+ DBUG_PRINT("info", ("Thread %s ended\n", my_thread_name()));
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ DBUG_RETURN(0);
+ }
+}
+
+
+int main(int argc __attribute__((unused)),
+ char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int *param, error, pagen;
+ File tmp_file;
+ MY_INIT(argv[0]);
+
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\test_pagecache_single.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/test_pagecache_single.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+ {
+ DBUG_ENTER("main");
+ DBUG_PRINT("info", ("Main thread: %s\n", my_thread_name()));
+
+ plan(16);
+ SKIP_BIG_TESTS(16)
+ {
+
+ if ((tmp_file= my_open(file2_name, O_CREAT | O_TRUNC | O_RDWR,
+ MYF(MY_WME))) < 0)
+ exit(1);
+
+ if ((file1.file= my_open(file1_name,
+ O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
+ {
+ fprintf(stderr, "Got error during file1 creation from open() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ pagecache_file_init(file1, &dummy_callback, &dummy_callback,
+ &dummy_fail_callback, &dummy_callback, NULL);
+ my_close(tmp_file, MYF(0));
+ my_delete(file2_name, MYF(0));
+
+ DBUG_PRINT("info", ("file1: %d", file1.file));
+ if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
+ exit(1);
+ my_pwrite(file1.file, (const uchar*)"test file", 9, 0, MYF(MY_WME));
+
+ if ((error= pthread_cond_init(&COND_thread_count, NULL)))
+ {
+ fprintf(stderr, "Got error: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+ if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
+ {
+ fprintf(stderr, "Got error: %d from pthread_cond_init (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+
+ if ((error= pthread_attr_init(&thr_attr)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
+ {
+ fprintf(stderr,
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+
+#ifdef HAVE_THR_SETCONCURRENCY
+ VOID(thr_setconcurrency(2));
+#endif
+
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TEST_PAGE_SIZE, MYF(MY_WME))) == 0)
+ {
+ fprintf(stderr,"Got error: init_pagecache() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ DBUG_PRINT("info", ("Page cache %d pages", pagen));
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ param=(int*) malloc(sizeof(int));
+ *param= 1;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread, (void*) param)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ exit(1);
+ }
+ thread_count++;
+ DBUG_PRINT("info", ("Thread started"));
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ pthread_attr_destroy(&thr_attr);
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ if ((error= pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
+ fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_PRINT("info", ("thread ended"));
+
+ end_pagecache(&pagecache, 1);
+ DBUG_PRINT("info", ("Page cache ended"));
+
+ if (my_close(file1.file, MYF(MY_WME)))
+ exit(1);
+
+ my_delete(file1_name, MYF(0));
+
+ } /* SKIP_BIG_TESTS */
+ DBUG_PRINT("info", ("file1 (%d) closed", file1.file));
+ DBUG_PRINT("info", ("Program end"));
+
+ my_end(0);
+
+ }
+ return exit_status();
+}
diff --git a/storage/maria/unittest/ma_test_all-t b/storage/maria/unittest/ma_test_all-t
new file mode 100755
index 00000000000..8e52f42b483
--- /dev/null
+++ b/storage/maria/unittest/ma_test_all-t
@@ -0,0 +1,710 @@
+#!/usr/bin/env perl
+#
+# Run various unit tests.
+#
+
+use Getopt::Long;
+use File::Basename;
+
+$|= 1;
+$^W = 1; # warnings, because env cannot parse 'perl -w'
+$VER= "1.4";
+
+$opt_version= 0;
+$opt_help= 0;
+$opt_verbose= 0;
+$opt_abort_on_error= 0;
+$opt_valgrind= "valgrind --alignment=8 --leak-check=yes";
+$opt_silent= "-s";
+$opt_number_of_tests= 0;
+$opt_run_tests= undef();
+
+my $maria_path; # path to "storage/maria"
+my $maria_exe_path; # path to executables (ma_test1, maria_chk etc)
+my $my_progname= $0;
+$my_progname=~ s/.*[\/]//;
+my $runtime_error= 0; # Return 1 if error(s) occur during run
+my $NEW_TEST= 0; # Test group separator in an array of tests
+my $test_begin= 0;
+my $test_end= 0;
+my $test_counter= 0;
+
+run_tests();
+
+####
+#### Initialise variables, clean temporary files and run the tests
+####
+
+sub run_tests
+{
+ my $nr_tests= 0;
+ my $flag_exit= 0;
+
+ if (!GetOptions("help" => \$opt_help,
+ "version" => \$opt_version,
+ "verbose" => \$opt_verbose,
+ "abort-on-error" => \$opt_abort_on_error,
+ "valgrind=s" => \$opt_valgrind,
+ "silent=s" => \$opt_silent,
+ "number-of-tests" => \$opt_number_of_tests,
+ "run-tests=s" => \$opt_run_tests,
+ "start-from=s" => \$opt_run_tests))
+ {
+ $flag_exit= 1;
+ }
+ if ($opt_version)
+ {
+ print "$my_progname version $VER\n";
+ exit(0);
+ }
+ $maria_path= dirname($0) . "/..";
+
+ my $suffix= ( $^O =~ /win/i && $^O !~ /darwin/i ) ? ".exe" : "";
+ $maria_exe_path= "$maria_path/release";
+ # we use -f, sometimes -x is unexpectedly false in Cygwin
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ $maria_exe_path= "$maria_path/relwithdebinfo";
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ $maria_exe_path= "$maria_path/debug";
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ $maria_exe_path= $maria_path;
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ die("Cannot find ma_test1 executable\n");
+ }
+ }
+ }
+ }
+
+ usage() if ($opt_help || $flag_exit);
+
+ #
+ # IMPORTANT: If you modify this file, please read this:
+ #
+ # Count total number of tests. Make sure that the functions return
+ # number of unit tests correctly, e.g. calls to ok(). The last argument
+ # for each function is a flag counter and will return the number of
+ # unit tests in each. Please see comments on function ok() at the end.
+ #
+ # If you modify any functions or add any new ones, please make sure the
+ # unit tests are appropriately detected here. A wrong count will
+ # make the unit test fail during 'make test'. $nr_tests must be right.
+ #
+
+ $nr_tests+= run_check_tests(0, 0, 0, 0, 1) * 5; #
+ $nr_tests+= run_repair_tests(0, 0, 0, 0, 1) * 5; # called 4 times
+ $nr_tests+= run_pack_tests(0, 0, 0, 0, 1) * 5; #
+ $nr_tests+= run_tests_on_warnings_and_errors(0, 0, 0, 1);
+ $nr_tests+= run_ma_test_recovery(0, 1);
+ $nr_tests+= run_tests_on_clrs(0, 0, 1);
+
+ if ($opt_number_of_tests)
+ {
+ print "Total number of tests is $nr_tests\n";
+ exit(0);
+ }
+
+ if (defined($opt_run_tests))
+ {
+ if ($opt_run_tests =~ m/^(\d+)$/ ||
+ $opt_run_tests =~ m/^(\d+)\.+$/)
+ {
+ $test_begin= $1;
+ }
+ elsif ($opt_run_tests =~ m/^(\d+)\.+(\d+)$/)
+ {
+ $test_begin= $1;
+ $test_end= $2;
+ }
+ else
+ {
+ print "Wrong syntax for option --run-tests=$opt_run_tests\n";
+ print "Please use --run-tests=<begin>..<end>\nwhere 'begin' is the ";
+ print "first test to be run and 'end' is the last.\n";
+ exit(1);
+ }
+ if ($test_end > $nr_tests)
+ {
+ print "Test range ($test_begin..$test_end) out of range. ";
+ print "There are only $nr_tests in the test suite.\n";
+ exit(1);
+ }
+ $test_begin++ if (!$test_begin); # Handle zero, if user gave that
+ if ($test_end && $test_begin > $test_end)
+ {
+ print "Bad test range ($test_begin..$test_end)\n";
+ exit(1);
+ }
+ # Now adjust number of tests
+ $nr_tests= ($test_end ? $test_end : $nr_tests) - $test_begin + 1;
+ }
+
+ #
+ # clean-up
+ #
+
+ unlink <*.TMD maria_log*>; # Delete temporary files
+
+ #
+ # Run tests
+ #
+
+ if (!$opt_verbose)
+ {
+ print "1..$nr_tests\n";
+ }
+ else
+ {
+ print "Total tests: $nr_tests\n";
+ }
+
+ if ($opt_verbose)
+ {
+ print "Running tests with dynamic row format\n"
+ }
+ run_check_tests($suffix, $opt_silent, "", $opt_verbose, 0);
+ run_repair_tests($suffix, $opt_silent, "", $opt_verbose, 0);
+ run_pack_tests($suffix, $opt_silent, "", $opt_verbose, 0);
+
+ if ($opt_verbose)
+ {
+ print "\nRunning tests with static row format\n";
+ }
+ run_check_tests($suffix, $opt_silent, "-S", $opt_verbose, 0);
+ run_repair_tests($suffix, $opt_silent, "-S", $opt_verbose, 0);
+ run_pack_tests($suffix, $opt_silent, "-S", $opt_verbose, 0);
+
+ if ($opt_verbose)
+ {
+ print "\nRunning tests with block row format\n";
+ }
+ run_check_tests($suffix, $opt_silent, "-M", $opt_verbose, 0);
+ run_repair_tests($suffix, $opt_silent, "-M", $opt_verbose, 0);
+ run_pack_tests($suffix, $opt_silent, "-M", $opt_verbose, 0);
+
+ if ($opt_verbose)
+ {
+ print "\nRunning tests with block row format and transactions\n";
+ }
+ run_check_tests($suffix, $opt_silent, "-M -T", $opt_verbose, 0);
+ run_repair_tests($suffix, $opt_silent, "-M -T", $opt_verbose, 0);
+ run_pack_tests($suffix, $opt_silent, "-M -T", $opt_verbose, 0);
+
+ if ($opt_verbose)
+ {
+ print "\nRunning tests with block row format, transactions and versioning\n";
+ }
+ run_check_tests($suffix, $opt_silent, "-M -T -C", $opt_verbose, 0);
+ run_repair_tests($suffix, $opt_silent, "-M -T -C", $opt_verbose, 0);
+ run_pack_tests($suffix, $opt_silent, "-M -T -C", $opt_verbose, 0);
+
+
+ if ($opt_verbose)
+ {
+ print "\nRunning tests with warnings and recovery\n";
+ }
+ run_tests_on_warnings_and_errors($suffix, $opt_silent, $opt_verbose, 0);
+ run_ma_test_recovery($opt_verbose, 0);
+ run_tests_on_clrs($suffix, $opt_verbose, 0);
+
+ exit($runtime_error);
+}
+
+####
+#### regular tests
+####
+
+sub run_check_tests
+{
+ my ($suffix, $silent, $row_type, $verbose, $count)= @_;
+ my ($i, $nr_tests);
+ my @ma_test1_opt= ( ["","-se"],
+ ["-N","-se"],
+ ["-P --checksum","-se"],
+ ["-P -N","-se"],
+ ["-B -N -R2","-sm"],
+ ["-a -k 480 --unique","-sm"],
+ ["-a -N -R1 ","-sm"],
+ ["-p","-sm"],
+ ["-p -N --unique","-sm"],
+ ["-p -N --key_length=127 --checksum","-sm"],
+ ["-p -N --key_length=128","-sm"],
+ ["-p --key_length=480","-sm"],
+ ["-a -B","-sm"],
+ ["-a -B --key_length=64 --unique","-sm"],
+ ["-a -B -k 480 --checksum","-sm"],
+ ["-a -B -k 480 -N --unique --checksum","-sm"],
+ ["-a -m","-sm"],
+ ["-a -m -P --unique --checksum","-sm"],
+ ["-a -m -P --key_length=480 --key_cache","-sm"],
+ ["-m -p","-sm"],
+ ["-w --unique","-sm"],
+ ["-a -w --key_length=64 --checksum","-sm"],
+ ["-a -w -N --key_length=480","-sm"],
+ ["-a -w --key_length=480 --checksum","-sm"],
+ ["-a -b -N","-sm"],
+ ["-a -b --key_length=480","-sm"],
+ ["-p -B --key_length=480","-sm"],
+ ["--checksum --unique","-se"],
+ ["--unique","-se"],
+ ["--key_multiple -N -S","-sm"],
+ ["--key_multiple -a -p --key_length=480","-sm"],
+ ["--key_multiple -a -B --key_length=480","-sm"],
+ ["--key_multiple -P -S","-sm"] );
+ my @ma_test2_opt= ( ["-L -K -W -P","-sm"],
+ ["-L -K -W -P -A","-sm"],
+ ["-L -K -W -P -b32768", "-sm"],
+ ["-L -K -W -P -M -T -c -b32768 -t4 -m300", "-sm"],
+ ["-L -K -P -R3 -m50 -b1000000", "-sm"],
+ ["-L -B","-sm"],
+ ["-D -B -c","-sm"],
+ ["-m10000 -e4096 -K","-sm"],
+ ["-m10000 -e8192 -K","-sm"],
+ ["-m10000 -e16384 -E16384 -K -L","-sm"],
+ ["-L -K -W -P -b32768", "-se"],
+ ["-c -b65000","-se"] );
+ my @ma_rt_test_opt= ( ); # (["--checksum", "-se"] );
+
+
+ if ($count)
+ {
+ $nr_tests= 2; # Number of tests outside loops
+ for ($i= 0; defined($ma_test1_opt[$i]); $i++) { $nr_tests+=2; }
+ for ($i= 0; defined($ma_test2_opt[$i]); $i++) { $nr_tests+=2; }
+ for ($i= 0; defined($ma_rt_test_opt[$i]); $i++) { $nr_tests+=2; }
+ return $nr_tests;
+ }
+
+ for ($i= 0; defined($ma_test1_opt[$i]); $i++)
+ {
+ unlink <maria_log_control maria_log.*>;
+ ok("$maria_exe_path/ma_test1$suffix $silent $ma_test1_opt[$i][0] $row_type",
+ $verbose, $i + 1);
+ ok("$maria_exe_path/maria_chk$suffix $ma_test1_opt[$i][1] test1",
+ $verbose, $i + 1);
+ }
+ #
+ # These tests are outside the loops. Make sure to include them in
+ # nr_tests manually
+ #
+ ok("$maria_exe_path/maria_pack$suffix --force -s test1", $verbose, 0);
+ ok("$maria_exe_path/maria_chk$suffix -ess test1", $verbose, 0);
+
+ for ($i= 0; defined($ma_test2_opt[$i]); $i++)
+ {
+ unlink <maria_log_control maria_log.*>;
+ ok("$maria_exe_path/ma_test2$suffix $silent $ma_test2_opt[$i][0] $row_type",
+ $verbose, $i + 1);
+ ok("$maria_exe_path/maria_chk$suffix $ma_test2_opt[$i][1] test2",
+ $verbose, $i + 1);
+ }
+
+ for ($i= 0; defined($ma_rt_test_opt[$i]); $i++)
+ {
+ unlink <maria_log_control maria_log.*>;
+ ok("$maria_exe_path/ma_rt_test$suffix $silent $ma_rt_test_opt[$i][0] $row_type",
+ $verbose, $i + 1);
+ ok("$maria_exe_path/maria_chk$suffix $ma_rt_test_opt[$i][1] rt_test",
+ $verbose, $i + 1);
+ }
+
+ unlink <maria_log_control maria_log.*>;
+
+ return 0;
+}
+
+####
+#### repair tests
+####
+
+sub run_repair_tests()
+{
+ my ($suffix, $silent, $row_type, $verbose, $count)= @_;
+ my ($i);
+
+ my @t= ($NEW_TEST,
+ "$maria_exe_path/ma_test1$suffix $silent --checksum $row_type",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix --silent -re --transaction-log test1",
+ "$maria_exe_path/maria_chk$suffix -rs test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix -rqs test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix -rs --correct-checksum test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix -rqs --correct-checksum test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix -ros --correct-checksum test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix -rqos --correct-checksum test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix -sz test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/ma_test2$suffix $silent -c -d1 $row_type",
+ "$maria_exe_path/maria_chk$suffix -s --parallel-recover test2",
+ "$maria_exe_path/maria_chk$suffix -se test2",
+ "$maria_exe_path/maria_chk$suffix -s --parallel-recover --quick test2",
+ "$maria_exe_path/maria_chk$suffix -se test2",
+ "$maria_exe_path/ma_test2$suffix $silent -c $row_type",
+ "$maria_exe_path/maria_chk$suffix -se test2",
+ "$maria_exe_path/maria_chk$suffix -sr test2",
+ "$maria_exe_path/maria_chk$suffix -se test2",
+ "$maria_exe_path/ma_test2$suffix $silent -c -t4 -b32768 $row_type",
+ "$maria_exe_path/maria_chk$suffix -s --zerofill test1",
+ "$maria_exe_path/maria_chk$suffix -se test1"
+ );
+
+ return &count_tests(\@t) if ($count);
+ &run_test_bunch(\@t, $verbose, 0);
+ return 0;
+}
+
+####
+#### pack tests
+####
+
+sub run_pack_tests()
+{
+ my ($suffix, $silent, $row_type, $verbose, $count)= @_;
+ my ($i);
+
+ my @t= ($NEW_TEST,
+ "$maria_exe_path/ma_test1$suffix $silent --checksum $row_type",
+ "$maria_exe_path/maria_pack$suffix --force -s test1",
+ "$maria_exe_path/maria_chk$suffix -ess test1",
+ "$maria_exe_path/maria_chk$suffix -rqs test1",
+ "$maria_exe_path/maria_chk$suffix -es test1",
+ "$maria_exe_path/maria_chk$suffix -rs test1",
+ "$maria_exe_path/maria_chk$suffix -es test1",
+ "$maria_exe_path/maria_chk$suffix -rus test1",
+ "$maria_exe_path/maria_chk$suffix -es test1",
+ $NEW_TEST,
+ "$maria_exe_path/ma_test1$suffix $silent --checksum $row_type",
+ "$maria_exe_path/maria_pack$suffix --force -s test1",
+ "$maria_exe_path/maria_chk$suffix -rus --safe-recover test1",
+ "$maria_exe_path/maria_chk$suffix -es test1",
+ $NEW_TEST,
+ "$maria_exe_path/ma_test1$suffix $silent --checksum -S $row_type",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ "$maria_exe_path/maria_chk$suffix -ros test1",
+ "$maria_exe_path/maria_chk$suffix -rqs test1",
+ "$maria_exe_path/maria_chk$suffix -se test1",
+ $NEW_TEST,
+ "$maria_exe_path/maria_pack$suffix --force -s test1",
+ "$maria_exe_path/maria_chk$suffix -rqs test1",
+ "$maria_exe_path/maria_chk$suffix -es test1",
+ "$maria_exe_path/maria_chk$suffix -rus test1",
+ "$maria_exe_path/maria_chk$suffix -es test1",
+ $NEW_TEST,
+ "$maria_exe_path/ma_test2$suffix $silent -c -d1 $row_type",
+ "$maria_exe_path/maria_chk$suffix -s --parallel-recover test2",
+ "$maria_exe_path/maria_chk$suffix -se test2",
+ "$maria_exe_path/maria_chk$suffix -s --unpack --parallel-recover test2",
+ "$maria_exe_path/maria_chk$suffix -se test2",
+ "$maria_exe_path/maria_pack$suffix --force -s test1",
+ "$maria_exe_path/maria_chk$suffix -s --unpack --parallel-recover test2",
+ "$maria_exe_path/maria_chk$suffix -se test2",
+ $NEW_TEST,
+ "$maria_exe_path/ma_test1$suffix $silent -c $row_type",
+ "cp test1.MAD test2.MAD",
+ "cp test1.MAI test2.MAI",
+ "$maria_exe_path/maria_pack$suffix --force -s --join=test3 test1 test2",
+ "$maria_exe_path/maria_chk -s test3",
+ "$maria_exe_path/maria_chk -s --safe-recover test3",
+ "$maria_exe_path/maria_chk -s test3"
+ );
+
+ return &count_tests(\@t) if ($count);
+ &run_test_bunch(\@t, $verbose, 0);
+ return 0;
+}
+
+####
+#### Tests that gives warnings or errors
+####
+
+sub run_tests_on_warnings_and_errors
+{
+ my ($suffix, $silent, $verbose, $count)= @_;
+ my ($com);
+
+ return 9 if ($count); # Number of tests in this function, e.g. calls to ok()
+
+ ok("$maria_exe_path/ma_test2$suffix $silent -L -K -W -P -S -R1 -m500",
+ $verbose, 0);
+ ok("$maria_exe_path/maria_chk$suffix -sm test2", $verbose, 0);
+ # ma_test2$suffix $silent -L -K -R1 -m2000 ; Should give error 135\n
+ # In the following a failure is a success and success is a failure
+ $com= "$maria_exe_path/ma_test2$suffix $silent -L -K -R1 -m2000 ";
+ $com.= ">ma_test2_message.txt 2>&1";
+ ok($com, $verbose, 0, 1);
+ ok("cat ma_test2_message.txt", $verbose, 0);
+ ok("grep \"Error: 135\" ma_test2_message.txt > /dev/null", $verbose, 0);
+ # maria_exe_path/maria_chk$suffix -sm test2 will warn that
+ # Datafile is almost full
+ ok("$maria_exe_path/maria_chk$suffix -sm test2 >ma_test2_message.txt 2>&1",
+ $verbose, 0);
+ ok("cat ma_test2_message.txt", $verbose, 0);
+ ok("grep \"warning: Datafile is almost full\" ma_test2_message.txt>/dev/null",
+ $verbose, 0);
+ unlink <ma_test2_message.txt>;
+ ok("$maria_exe_path/maria_chk$suffix -ssm test2", $verbose, 0);
+
+ return 0;
+}
+
+####
+#### Test that removing tables and applying the log leads to identical tables
+####
+
+sub run_ma_test_recovery
+{
+ my ($verbose, $count)= @_;
+
+ return 1 if ($count); # Number of tests in this function
+ ok("$maria_path/unittest/ma_test_recovery.pl", $verbose, 0);
+ return 0;
+}
+
+####
+#### Tests on CLR's
+####
+
+sub run_tests_on_clrs
+{
+ my ($suffix, $verbose, $count)= @_;
+ my ($i);
+
+ my @t= ($NEW_TEST,
+ "$maria_exe_path/ma_test2$suffix -s -L -K -W -P -M -T -c -b -t2 -A1",
+ "cp maria_log_control tmp",
+ "$maria_exe_path/maria_read_log$suffix -a -s",
+ "$maria_exe_path/maria_chk$suffix -s -e test2",
+ "cp tmp/maria_log_control .",
+ "rm test2.MA?",
+ "$maria_exe_path/maria_read_log$suffix -a -s",
+ "$maria_exe_path/maria_chk$suffix -s -e test2",
+ "rm test2.MA?",
+ $NEW_TEST,
+ "$maria_exe_path/ma_test2$suffix -s -L -K -W -P -M -T -c -b -t2 -A1",
+ "$maria_exe_path/maria_read_log$suffix -a -s",
+ "$maria_exe_path/maria_chk$suffix -s -e test2",
+ "rm test2.MA?",
+ "$maria_exe_path/maria_read_log$suffix -a -s",
+ "$maria_exe_path/maria_chk$suffix -e -s test2",
+ "rm test2.MA?",
+ $NEW_TEST,
+ "$maria_exe_path/ma_test2$suffix -s -L -K -W -P -M -T -c -b32768 -t4 -A1",
+ "$maria_exe_path/maria_read_log$suffix -a -s",
+ "$maria_exe_path/maria_chk$suffix -es test2",
+ "$maria_exe_path/maria_read_log$suffix -a -s",
+ "$maria_exe_path/maria_chk$suffix -es test2",
+ "rm test2.MA?",
+ "$maria_exe_path/maria_read_log$suffix -a -s",
+ "$maria_exe_path/maria_chk$suffix -es test2",
+ "rm test2.MA?"
+ );
+
+ return &count_tests(\@t) if ($count);
+ &run_test_bunch(\@t, $verbose, 1);
+ return 0;
+}
+
+#
+# Print "ok" on success and "not ok" on error
+#
+# Note: Every time this function is called it will be counted
+# as a unit test.
+#
+# Args: $com: The actual command run. Will be printed on a failure
+# $verbose: Be more verbose.
+# $iteration: Number of iterations in a loop when the error
+# occurred. If not in loop, this should be blank
+# (e.g. send zero).
+# $expected_error: Optional; put here expected error code. Test
+# will pass with this result only.
+#
+# Return value: Will return 1 on success and 0 on an error
+#
+
+sub ok
+{
+ my ($com, $verbose, $iteration, $expected_error)= @_;
+ my ($msg, $output, $err, $len);
+
+ $test_counter++;
+ if ($test_begin > $test_counter)
+ {
+ return 0;
+ }
+ if ($test_end && $test_end < $test_counter)
+ {
+ exit(0);
+ }
+
+ $msg= "";
+ $expected_error= 0 if (!defined($expected_error));
+
+ if ($verbose)
+ {
+ print "$com ";
+ }
+ $output= `$com 2>&1`;
+ $len= length($com);
+ if ($verbose)
+ {
+ print " " x (62 - $len);
+ }
+ $err= $?;
+ if ((!$err && !$expected_error) ||
+ (($err >> 8) == $expected_error && $expected_error))
+ {
+ print "[ " if ($verbose);
+ print "ok";
+ if ($verbose)
+ {
+ print " ]";
+ print " " x (5 - length("$test_counter"));
+ print "$test_counter";
+ }
+ else
+ {
+ print " $test_counter - $com"
+ }
+ print "\n";
+ return 1;
+ }
+ print "[ " if ($verbose);
+ print "not ok";
+ print " ]" if ($verbose);
+ print " $test_counter - $com" unless $verbose;
+ print "\n";
+ if ($verbose && defined($output) && length($output))
+ {
+ print "$output\n";
+ }
+ if (!$verbose)
+ {
+ $msg= "\n"; # Get a nicer output in perl unit test mode
+ }
+ $msg.= "Failed test '$com' ";
+ if ($iteration)
+ {
+ $msg.= "(loop iteration $iteration.) ";
+ }
+ $msg.= "at line ";
+ $msg.= (caller)[2];
+ $msg.= "\n(errcode: $err, test: $test_counter)\n";
+ if ($expected_error)
+ {
+ $msg.= "Was expecting errcode: $expected_error\n";
+ }
+ warn $msg;
+ $runtime_error= 1;
+ if ($opt_abort_on_error)
+ {
+ exit 1;
+ }
+ return 0;
+}
+
+#
+# Print "skip" and the reason
+#
+# Note: Every time this function is called it will be counted
+# as a unit test.
+#
+# Args: $com: The actual command run. Will be printed on a failure
+# $reason: The reason to skip a test
+# $verbose: Be more verbose.
+#
+
+sub skip
+{
+ my ($com, $reason, $verbose)= @_;
+
+ $test_counter++;
+ return 0 if $test_begin > $test_counter;
+ exit 0 if $test_end && $test_end < $test_counter;
+ printf '%-64s[ skipped ]%5d', $com, $test_counter if $verbose;
+ print "ok $test_counter # skip $reason" unless $verbose;
+ print "\n";
+ return 1;
+}
+
+####
+#### Count tests
+#### Arguments: $t: an array of the tests
+####
+
+sub count_tests
+{
+ my ($t)= @_;
+ my ($i, $nr_tests);
+
+ $nr_tests= 0;
+ for ($i= 0; defined(@$t[$i]); $i++) { $nr_tests++ if (@$t[$i]); }
+ return $nr_tests;
+}
+
+####
+#### Run a bunch of tests
+#### Arguments: $t: an array of the tests
+#### $verbose: to be passed to ok()
+#### $clear: clear log files if set
+####
+
+sub run_test_bunch
+{
+ my ($t, $verbose, $clear)= @_;
+ my ($i);
+
+ for ($i= 0; defined(@$t[$i]); $i++)
+ {
+ if ($clear && @$t[$i] eq $NEW_TEST)
+ {
+ unlink <maria_log.* maria_log_control>;
+ }
+ if (@$t[$i] ne $NEW_TEST)
+ {
+ ok(@$t[$i], $verbose, $i + 1);
+ }
+ }
+}
+
+####
+#### usage
+####
+
+sub usage
+{
+ print <<EOF;
+$my_progname version $VER
+
+Description:
+
+Run various Maria related tests. Typically used via make test as a unittest.
+
+Options
+--help Show this help and exit.
+--abort-on-error Abort at once in case of error.
+--number-of-tests Print the total number of tests and exit.
+--run-tests=... Test number(s) that should be run. You can give just
+ one number or a range. For example 45..89. To run a specific
+ test alone, for example test 215, use --run-tests=215..215
+ Use this option with caution, because some of the tests
+ might depend on previous ones.
+--start-from=... Alias for --run-tests
+--silent=... Silent option passed to ma_test* tests ('$opt_silent')
+--valgrind=... Options for valgrind.
+ ('$opt_valgrind')
+--verbose Be more verbose. Will print each unittest on a line
+ and result after. This mode cannot be used with unit.pl
+ when running in normal unit test mode.
+--version Show version number and exit.
+EOF
+ exit(0);
+}
diff --git a/storage/maria/unittest/ma_test_loghandler-t.c b/storage/maria/unittest/ma_test_loghandler-t.c
new file mode 100644
index 00000000000..6027be1e5ea
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler-t.c
@@ -0,0 +1,663 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void example_loghandler_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+static TRN *trn= &dummy_transaction_object;
+
+#define PCACHE_SIZE (1024*1024*10)
+
+#define LONG_BUFFER_SIZE (100 * 1024)
+
+#ifdef LONG_LOG_TEST
+#define LOG_FLAGS 0
+#define LOG_FILE_SIZE (1024L*1024L*8)
+#define ITERATIONS (1600*4)
+
+#else
+#undef SKIP_BIG_TESTS
+#define SKIP_BIG_TESTS(X) /* no-op */
+#define LOG_FLAGS (TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC)
+#define LOG_FILE_SIZE (1024L*1024L*8L)
+#define ITERATIONS 1600
+#endif
+
+/*
+#define LOG_FLAGS 0
+#define LOG_FILE_SIZE 1024L*1024L*1024L
+#define ITERATIONS 181000
+*/
+
+/*
+#define LOG_FLAGS 0
+#define LOG_FILE_SIZE 1024L*1024L*3L
+#define ITERATIONS 1600
+*/
+
+/*
+#define LOG_FLAGS 0
+#define LOG_FILE_SIZE 1024L*1024L*100L
+#define ITERATIONS 65000
+*/
+
+/*
+ Generate random value in the range (0,LONG_BUFFER_SIZE)
+*/
+static uint32 rand_buffer_size()
+{
+ return (uint32)((ulonglong)rand()*(LONG_BUFFER_SIZE + 1)/RAND_MAX);
+}
+
+/*
+ Check that the buffer filled correctly
+
+ SYNOPSIS
+ check_content()
+ ptr Pointer to the buffer
+ length length of the buffer
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+
+static my_bool check_content(uchar *ptr, ulong length)
+{
+ ulong i;
+ uchar buff[2];
+ for (i= 0; i < length; i++)
+ {
+ if (i % 2 == 0)
+ int2store(buff, i >> 1);
+ if (ptr[i] != buff[i % 2])
+ {
+ fprintf(stderr, "Byte # %lu is %x instead of %x",
+ i, (uint) ptr[i], (uint) buff[i % 2]);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ Report OK for read operation
+
+ SYNOPSIS
+ read_ok()
+ rec the record header
+*/
+
+void read_ok(TRANSLOG_HEADER_BUFFER *rec)
+{
+ char buff[80];
+ my_snprintf(buff, sizeof(buff), "read record type: %u LSN: (%lu,0x%lx)",
+ rec->type, LSN_IN_PARTS(rec->lsn));
+ ok(1, buff);
+}
+
+/*
+ Read whole record content, and check content (put with offset)
+
+ SYNOPSIS
+ read_and_check_content()
+ rec The record header buffer
+ buffer The buffer to read the record in
+ skip Skip this number of bytes ot the record content
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
+ uchar *buffer, uint skip)
+{
+ DBUG_ASSERT(rec->record_length < LONG_BUFFER_SIZE * 2 + 7 * 2 + 2);
+ if (translog_read_record(rec->lsn, 0, rec->record_length, buffer, NULL) !=
+ rec->record_length)
+ return 1;
+ return check_content(buffer + skip, rec->record_length - skip);
+}
+
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ uint32 i;
+ uint32 rec_len;
+ uint pagen;
+ uchar long_tr_id[6];
+ uchar lsn_buff[23]=
+ {
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55
+ };
+ uchar long_buffer[LONG_BUFFER_SIZE * 2 + LSN_STORE_SIZE * 2 + 2];
+ PAGECACHE pagecache;
+ LSN lsn, lsn_base, first_lsn;
+ TRANSLOG_HEADER_BUFFER rec;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 3];
+ struct st_translog_scanner_data scanner;
+ int rc;
+
+ MY_INIT(argv[0]);
+
+ if (my_set_max_open_files(100) < 100)
+ {
+ fprintf(stderr, "can't allocate 100 file descriptors\n");
+ exit(1);
+ }
+ bzero(&pagecache, sizeof(pagecache));
+ maria_data_root= (char *)".";
+ if (maria_log_remove())
+ exit(1);
+
+ for (i= 0; i < (LONG_BUFFER_SIZE + LSN_STORE_SIZE * 2 + 2); i+= 2)
+ {
+ int2store(long_buffer + i, (i >> 1));
+ /* long_buffer[i]= (i & 0xFF); */
+ }
+
+ bzero(long_tr_id, 6);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ trn->first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ plan(((ITERATIONS - 1) * 4 + 1)*2 + ITERATIONS - 1 + 1);
+
+ SKIP_BIG_TESTS(((ITERATIONS - 1) * 4 + 1)*2 + ITERATIONS - 1 + 1)
+ {
+
+ srand(122334817L);
+
+ long_tr_id[5]= 0xff;
+
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ trn->short_id= 0;
+ trn->first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ trn, NULL, 6, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+ lsn_base= first_lsn= lsn;
+
+ for (i= 1; i < ITERATIONS; i++)
+ {
+ trn->short_id= i % 0xFFFF;
+ if (i % 2)
+ {
+ lsn_store(lsn_buff, lsn_base);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= LSN_STORE_SIZE;
+ /* check auto-count feature */
+ parts[TRANSLOG_INTERNAL_PARTS + 1].str= NULL;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].length= 0;
+ if (translog_write_record(&lsn, LOGREC_FIXED_RECORD_1LSN_EXAMPLE, trn,
+ NULL, LSN_STORE_SIZE, 0, parts, NULL, NULL))
+ {
+ fprintf(stderr, "1 Can't write reference defore record #%lu\n",
+ (ulong) i);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_1LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_1LSN_EXAMPLE");
+ lsn_store(lsn_buff, lsn_base);
+ if ((rec_len= rand_buffer_size()) < 12)
+ rec_len= 12;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= LSN_STORE_SIZE;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].length= rec_len;
+ /* check record length auto-counting */
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE,
+ trn, NULL, 0, TRANSLOG_INTERNAL_PARTS + 2,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "1 Can't write var reference defore record #%lu\n",
+ (ulong) i);
+ translog_destroy();
+ ok(0, "write LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE");
+ }
+ else
+ {
+ lsn_store(lsn_buff, lsn_base);
+ lsn_store(lsn_buff + LSN_STORE_SIZE, first_lsn);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 23;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_2LSN_EXAMPLE,
+ trn, NULL, 23, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "0 Can't write reference defore record #%lu\n",
+ (ulong) i);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_2LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_2LSN_EXAMPLE");
+ lsn_store(lsn_buff, lsn_base);
+ lsn_store(lsn_buff + LSN_STORE_SIZE, first_lsn);
+ if ((rec_len= rand_buffer_size()) < 19)
+ rec_len= 19;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 14;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].length= rec_len;
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE,
+ trn, NULL, 14 + rec_len,
+ TRANSLOG_INTERNAL_PARTS + 2, parts, NULL,
+ NULL))
+ {
+ fprintf(stderr, "0 Can't write var reference defore record #%lu\n",
+ (ulong) i);
+ translog_destroy();
+ ok(0, "write LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE");
+ }
+ int4store(long_tr_id, i);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ trn, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) i);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+
+ lsn_base= lsn;
+
+ if ((rec_len= rand_buffer_size()) < 9)
+ rec_len= 9;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= rec_len;
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
+ trn, NULL, rec_len,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
+ translog_destroy();
+ ok(0, "write LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE");
+ if (translog_flush(lsn))
+ {
+ fprintf(stderr, "Can't flush #%lu\n", (ulong) i);
+ translog_destroy();
+ ok(0, "flush");
+ exit(1);
+ }
+ ok(1, "flush");
+ }
+
+ if (translog_flush(translog_get_horizon()))
+ {
+ fprintf(stderr, "Can't flush up to horizon\n");
+ translog_destroy();
+ ok(0, "flush");
+ exit(1);
+ }
+ ok(1, "flush");
+
+ srand(122334817L);
+
+ rc= 1;
+
+ {
+ int len= translog_read_record_header(first_lsn, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "translog_read_record_header failed (%d)\n", errno);
+ goto err;
+ }
+ if (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE || rec.short_trid != 0 ||
+ rec.record_length != 6 || uint4korr(rec.header) != 0 ||
+ ((uchar)rec.header[4]) != 0 || ((uchar)rec.header[5]) != 0xFF ||
+ first_lsn != rec.lsn)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
+ "data read(0)\n"
+ "type %u, strid %u, len %u, i: %u, 4: %u 5: %u, "
+ "lsn(%lu,0x%lx)\n",
+ (uint) rec.type, (uint) rec.short_trid, (uint) rec.record_length,
+ (uint) uint4korr(rec.header), (uint) rec.header[4],
+ (uint) rec.header[5],
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ read_ok(&rec);
+ translog_free_record_header(&rec);
+ lsn= first_lsn;
+ if (translog_scanner_init(first_lsn, 1, &scanner, 0))
+ {
+ fprintf(stderr, "scanner init failed\n");
+ goto err;
+ }
+ for (i= 1;; i++)
+ {
+ len= translog_read_next_record_header(&scanner, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
+ i, errno);
+ goto err;
+ }
+ if (len == RECHEADER_READ_EOF)
+ {
+ if (i != ITERATIONS)
+ {
+ fprintf(stderr, "EOL met at iteration %u instead of %u\n",
+ i, ITERATIONS);
+ goto err;
+ }
+ break;
+ }
+ if (i % 2)
+ {
+ LSN ref;
+ ref= lsn_korr(rec.header);
+ if (rec.type != LOGREC_FIXED_RECORD_1LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != 7 || ref != lsn)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_1LSN_EXAMPLE "
+ "data read(%d) "
+ "type: %u strid: %u len: %u"
+ "ref: (%lu,0x%lx) (%lu,0x%lx) "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (uint) rec.record_length,
+ LSN_IN_PARTS(ref), LSN_IN_PARTS(lsn),
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ }
+ else
+ {
+ LSN ref1, ref2;
+ ref1= lsn_korr(rec.header);
+ ref2= lsn_korr(rec.header + LSN_STORE_SIZE);
+ if (rec.type != LOGREC_FIXED_RECORD_2LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != 23 ||
+ ref1 != lsn ||
+ ref2 != first_lsn ||
+ ((uchar)rec.header[22]) != 0x55 ||
+ ((uchar)rec.header[21]) != 0xAA ||
+ ((uchar)rec.header[20]) != 0x55 ||
+ ((uchar)rec.header[19]) != 0xAA ||
+ ((uchar)rec.header[18]) != 0x55 ||
+ ((uchar)rec.header[17]) != 0xAA ||
+ ((uchar)rec.header[16]) != 0x55 ||
+ ((uchar)rec.header[15]) != 0xAA ||
+ ((uchar)rec.header[14]) != 0x55)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_2LSN_EXAMPLE "
+ "data read(%d) "
+ "type %u, strid %u, len %u, ref1(%lu,0x%lx), "
+ "ref2(%lu,0x%lx) %x%x%x%x%x%x%x%x%x "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (uint) rec.record_length,
+ LSN_IN_PARTS(ref1), LSN_IN_PARTS(ref2),
+ (uint) rec.header[14], (uint) rec.header[15],
+ (uint) rec.header[16], (uint) rec.header[17],
+ (uint) rec.header[18], (uint) rec.header[19],
+ (uint) rec.header[20], (uint) rec.header[21],
+ (uint) rec.header[22],
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ }
+ read_ok(&rec);
+ translog_free_record_header(&rec);
+
+ len= translog_read_next_record_header(&scanner, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "1-%d translog_read_next_record_header (var) "
+ "failed (%d)\n", i, errno);
+ goto err;
+ }
+ if (len == RECHEADER_READ_EOF)
+ {
+ fprintf(stderr, "EOL met at the middle of iteration (first var) %u "
+ "instead of beginning of %u\n", i, ITERATIONS);
+ goto err;
+ }
+ if (i % 2)
+ {
+ LSN ref;
+ ref= lsn_korr(rec.header);
+ if ((rec_len= rand_buffer_size()) < 12)
+ rec_len= 12;
+ if (rec.type != LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != rec_len + LSN_STORE_SIZE ||
+ len != 12 || ref != lsn ||
+ check_content(rec.header + LSN_STORE_SIZE, len - LSN_STORE_SIZE))
+ {
+ fprintf(stderr, "Incorrect LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE "
+ "data read(%d)"
+ "type %u (%d), strid %u (%d), len %lu, %lu + 7 (%d), "
+ "hdr len: %u (%d), "
+ "ref(%lu,0x%lx), lsn(%lu,0x%lx) (%d), content: %d\n",
+ i, (uint) rec.type,
+ rec.type != LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE,
+ (uint) rec.short_trid,
+ rec.short_trid != (i % 0xFFFF),
+ (ulong) rec.record_length, (ulong) rec_len,
+ rec.record_length != rec_len + LSN_STORE_SIZE,
+ (uint) len,
+ len != 12,
+ LSN_IN_PARTS(ref), LSN_IN_PARTS(rec.lsn),
+ (len != 12 || ref != lsn),
+ check_content(rec.header + LSN_STORE_SIZE,
+ len - LSN_STORE_SIZE));
+ goto err;
+ }
+ if (read_and_check_content(&rec, long_buffer, LSN_STORE_SIZE))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE "
+ "in whole rec read lsn(%lu,0x%lx)\n",
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ }
+ else
+ {
+ LSN ref1, ref2;
+ ref1= lsn_korr(rec.header);
+ ref2= lsn_korr(rec.header + LSN_STORE_SIZE);
+ if ((rec_len= rand_buffer_size()) < 19)
+ rec_len= 19;
+ if (rec.type != LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != rec_len + LSN_STORE_SIZE * 2 ||
+ len != 19 ||
+ ref1 != lsn ||
+ ref2 != first_lsn ||
+ check_content(rec.header + LSN_STORE_SIZE * 2,
+ len - LSN_STORE_SIZE * 2))
+ {
+ fprintf(stderr, "Incorrect LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE "
+ "data read(%d) "
+ "type %u, strid %u, len %lu != %lu + 14, hdr len: %d, "
+ "ref1(%lu,0x%lx), ref2(%lu,0x%lx), "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (ulong) rec.record_length, (ulong) rec_len,
+ len, LSN_IN_PARTS(ref1), LSN_IN_PARTS(ref2),
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ if (read_and_check_content(&rec, long_buffer, LSN_STORE_SIZE * 2))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE "
+ "in whole rec read lsn(%lu,0x%lx)\n",
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ }
+ read_ok(&rec);
+ translog_free_record_header(&rec);
+
+ len= translog_read_next_record_header(&scanner, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
+ i, errno);
+ goto err;
+ }
+ if (len == RECHEADER_READ_EOF)
+ {
+ fprintf(stderr, "EOL met at the middle of iteration %u "
+ "instead of beginning of %u\n", i, ITERATIONS);
+ goto err;
+ }
+ if (rec.type != LOGREC_FIXED_RECORD_0LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != 6 || uint4korr(rec.header) != i ||
+ ((uchar)rec.header[4]) != 0 || ((uchar)rec.header[5]) != 0xFF)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
+ "data read(%d)\n"
+ "type %u, strid %u, len %u, i: %u, 4: %u 5: %u "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (uint) rec.record_length,
+ (uint) uint4korr(rec.header), (uint) rec.header[4],
+ (uint) rec.header[5],
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ lsn= rec.lsn;
+ read_ok(&rec);
+ translog_free_record_header(&rec);
+
+ len= translog_read_next_record_header(&scanner, &rec);
+ if ((rec_len= rand_buffer_size()) < 9)
+ rec_len= 9;
+ if (rec.type != LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != rec_len ||
+ len != 9 || check_content(rec.header, (uint)len))
+ {
+ fprintf(stderr, "Incorrect LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE "
+ "data read(%d) "
+ "type %u, strid %u, len %lu != %lu, hdr len: %d, "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (ulong) rec.record_length, (ulong) rec_len,
+ len, LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ if (read_and_check_content(&rec, long_buffer, 0))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE "
+ "in whole rec read lsn(%lu,0x%lx)\n",
+ LSN_IN_PARTS(rec.lsn));
+ goto err;
+ }
+ read_ok(&rec);
+ translog_free_record_header(&rec);
+ }
+ }
+
+ rc= 0;
+err:
+ if (rc)
+ ok(0, "read record");
+ } /* SKIP_BIG_TESTS */
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+
+ if (maria_log_remove())
+ exit(1);
+
+ return(test(exit_status()));
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
new file mode 100644
index 00000000000..06d9a00c04c
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_first_lsn-t.c
@@ -0,0 +1,160 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void translog_example_table_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+
+#define PCACHE_SIZE (1024*1024*10)
+#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
+#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
+#define LOG_FLAGS 0
+
+static char *first_translog_file= (char*)"maria_log.00000001";
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ uint pagen;
+ uchar long_tr_id[6];
+ PAGECACHE pagecache;
+ LSN lsn, first_lsn, theor_lsn;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+
+ MY_INIT(argv[0]);
+
+ plan(2);
+
+ bzero(&pagecache, sizeof(pagecache));
+ maria_data_root= (char *)".";
+ if (maria_log_remove())
+ exit(1);
+ /* be sure that we have no logs in the directory*/
+ my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
+ my_delete(first_translog_file, MYF(0));
+
+ bzero(long_tr_id, 6);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ PCACHE_PAGE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ theor_lsn= translog_first_theoretical_lsn();
+ if (theor_lsn == 1)
+ {
+ fprintf(stderr, "Error reading the first log file.");
+ translog_destroy();
+ exit(1);
+ }
+ if (theor_lsn == LSN_IMPOSSIBLE)
+ {
+ fprintf(stderr, "There is no first log file.");
+ translog_destroy();
+ exit(1);
+ }
+ first_lsn= translog_first_lsn_in_log();
+ if (first_lsn != LSN_IMPOSSIBLE)
+ {
+ fprintf(stderr, "Incorrect first lsn response (%lu,0x%lx).",
+ LSN_IN_PARTS(first_lsn));
+ translog_destroy();
+ exit(1);
+ }
+ ok(1, "Empty log response");
+
+
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
+ translog_destroy();
+ exit(1);
+ }
+
+ theor_lsn= translog_first_theoretical_lsn();
+ if (theor_lsn == 1)
+ {
+ fprintf(stderr, "Error reading the first log file\n");
+ translog_destroy();
+ exit(1);
+ }
+ if (theor_lsn == LSN_IMPOSSIBLE)
+ {
+ fprintf(stderr, "There is no first log file\n");
+ translog_destroy();
+ exit(1);
+ }
+ first_lsn= translog_first_lsn_in_log();
+ if (first_lsn != theor_lsn)
+ {
+ fprintf(stderr, "Incorrect first lsn: (%lu,0x%lx) "
+ " theoretical first: (%lu,0x%lx)\n",
+ LSN_IN_PARTS(first_lsn), LSN_IN_PARTS(theor_lsn));
+ translog_destroy();
+ exit(1);
+ }
+
+ ok(1, "Full log response");
+
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+ if (maria_log_remove())
+ exit(1);
+ exit(0);
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c b/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
new file mode 100644
index 00000000000..64f486b8cf1
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_max_lsn-t.c
@@ -0,0 +1,156 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void translog_example_table_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+
+#define PCACHE_SIZE (1024*1024*10)
+#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
+#define LOG_FILE_SIZE (8*1024L*1024L)
+#define LOG_FLAGS 0
+
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ ulong i;
+ uint pagen;
+ uchar long_tr_id[6];
+ PAGECACHE pagecache;
+ LSN lsn, max_lsn, last_lsn= LSN_IMPOSSIBLE;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+
+ MY_INIT(argv[0]);
+
+ plan(2);
+
+ bzero(&pagecache, sizeof(pagecache));
+ maria_data_root= (char *)".";
+ if (maria_log_remove())
+ exit(1);
+
+ bzero(long_tr_id, 6);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ PCACHE_PAGE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ max_lsn= translog_get_file_max_lsn_stored(1);
+ if (max_lsn == 1)
+ {
+ fprintf(stderr, "Error reading the first log file.");
+ translog_destroy();
+ exit(1);
+ }
+ if (max_lsn != LSN_IMPOSSIBLE)
+ {
+ fprintf(stderr, "Incorrect first lsn response (%lu,0x%lx).",
+ LSN_IN_PARTS(max_lsn));
+ translog_destroy();
+ exit(1);
+ }
+ ok(1, "Empty log response");
+
+
+ /* write more then 1 file */
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ for(i= 0; i < LOG_FILE_SIZE/6; i++)
+ {
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
+ translog_destroy();
+ exit(1);
+ }
+ if (LSN_FILE_NO(lsn) == 1)
+ last_lsn= lsn;
+ }
+
+
+ max_lsn= translog_get_file_max_lsn_stored(1);
+ if (max_lsn == 1)
+ {
+ fprintf(stderr, "Error reading the first log file\n");
+ translog_destroy();
+ exit(1);
+ }
+ if (max_lsn == LSN_IMPOSSIBLE)
+ {
+ fprintf(stderr, "Isn't first file still finished?!!\n");
+ translog_destroy();
+ exit(1);
+ }
+ if (max_lsn != last_lsn)
+ {
+ fprintf(stderr, "Incorrect max lsn: (%lu,0x%lx) "
+ " last lsn on first file: (%lu,0x%lx)\n",
+ LSN_IN_PARTS(max_lsn), LSN_IN_PARTS(last_lsn));
+ translog_destroy();
+ exit(1);
+ }
+
+ ok(1, "First file max LSN");
+
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+ if (maria_log_remove())
+ exit(1);
+ exit(0);
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_multigroup-t.c b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
new file mode 100644
index 00000000000..7ba7ce3176d
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_multigroup-t.c
@@ -0,0 +1,746 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+#include "sequence_storage.h"
+#include <my_getopt.h>
+
+extern my_bool maria_log_remove();
+extern void translog_example_table_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+static TRN *trn= &dummy_transaction_object;
+
+
+#ifndef READONLY_TEST
+
+#define PCACHE_SIZE (1024*1024*10)
+#define LONG_BUFFER_SIZE ((1024L*1024L*1024L) + (1024L*1024L*512))
+#define MIN_REC_LENGTH (1024L*1024L + 1024L*512L + 1)
+#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
+#define ITERATIONS 2
+#define READONLY 0
+
+#else
+
+#define PCACHE_SIZE (1024*1024*10)
+#define LONG_BUFFER_SIZE (1024L*1024L)
+#define MIN_REC_LENGTH (1024L)
+#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
+#define ITERATIONS 2
+#define READONLY 1
+
+#endif /*READONLY_TEST*/
+
+
+/*
+#define LOG_FILE_SIZE 1024L*1024L*3L
+#define ITERATIONS 1600
+*/
+/*
+#define LOG_FILE_SIZE 1024L*1024L*100L
+#define ITERATIONS 65000
+*/
+
+
+/*
+ Check that the buffer filled correctly
+
+ SYNOPSIS
+ check_content()
+ ptr Pointer to the buffer
+ length length of the buffer
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+static my_bool check_content(uchar *ptr, ulong length)
+{
+ ulong i;
+ uchar buff[4];
+ DBUG_ENTER("check_content");
+ for (i= 0; i < length; i++)
+ {
+ if (i % 4 == 0)
+ int4store(buff, (i >> 2));
+ if (ptr[i] != buff[i % 4])
+ {
+ fprintf(stderr, "Byte # %lu is %x instead of %x",
+ i, (uint) ptr[i], (uint) buff[i % 4]);
+ DBUG_DUMP("mem", ptr +(ulong) (i > 16 ? i - 16 : 0),
+ (i > 16 ? 16 : i) + (i + 16 < length ? 16 : length - i));
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Read whole record content, and check content (put with offset)
+
+ SYNOPSIS
+ read_and_check_content()
+ rec The record header buffer
+ buffer The buffer to read the record in
+ skip Skip this number of bytes ot the record content
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
+ uchar *buffer, uint skip)
+{
+ int res= 0;
+ translog_size_t len;
+ DBUG_ENTER("read_and_check_content");
+ DBUG_ASSERT(rec->record_length < LONG_BUFFER_SIZE + LSN_STORE_SIZE * 2 + 2);
+ if ((len= translog_read_record(rec->lsn, 0, rec->record_length,
+ buffer, NULL)) != rec->record_length)
+ {
+ fprintf(stderr, "Requested %lu byte, read %lu\n",
+ (ulong) rec->record_length, (ulong) len);
+ res= 1;
+ }
+ res|= check_content(buffer + skip, rec->record_length - skip);
+ DBUG_RETURN(res);
+}
+
+static const char *load_default_groups[]= {"ma_unit_loghandler", 0};
+#ifndef DBUG_OFF
+static const char *default_dbug_option=
+ IF_WIN("d:t:i:O,\\ma_test_loghandler.trace",
+ "d:t:i:o,/tmp/ma_test_loghandler.trace");
+#endif
+static const char *opt_wfile= NULL;
+static const char *opt_rfile= NULL;
+static struct my_option my_long_options[] =
+{
+#ifndef DBUG_OFF
+ {"debug", '#', "Output debug log. Often the argument is 'd:t:o,filename'.",
+ 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+ {"write-seq", 'w', "Path to file in which \"random\" sequence used in the test will be written",
+ (uchar**) &opt_wfile, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"read-seq", 'r', "Path to file from which \"random\" sequence used in the test will be read",
+ (uchar**) &opt_rfile, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"help", '?', "Display this help and exit.",
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+static SEQ_STORAGE seq;
+
+static uint32 get_len()
+{
+ uint32 res;
+ DBUG_ENTER("get_len");
+ if (opt_rfile)
+ res= seq_storage_next(&seq);
+ else
+ {
+ res= (uint32)
+ ((ulonglong) rand() *
+ (LONG_BUFFER_SIZE - MIN_REC_LENGTH - 1) / RAND_MAX) + MIN_REC_LENGTH;
+ if (opt_wfile &&
+ seq_storage_write(opt_wfile, res))
+ exit(1);
+ }
+ DBUG_PRINT("info", ("length value : %lu", (ulong) res));
+ DBUG_RETURN(res);
+}
+
+static void usage(void)
+{
+ puts("Copyright (C) 2008 MySQL AB");
+ puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
+ puts("and you are welcome to modify and redistribute it under the GPL license\n");
+
+ puts("Unit test of maria engine");
+ VOID(printf("\nUsage: %s [OPTIONS]\n", my_progname_short));
+ my_print_help(my_long_options);
+ print_defaults("my", load_default_groups);
+ my_print_variables(my_long_options);
+}
+
+
+static my_bool
+get_one_option(int optid __attribute__((unused)),
+ const struct my_option *opt __attribute__((unused)),
+ char *argument __attribute__((unused)))
+{
+ switch (optid) {
+ case '?':
+ usage();
+ exit(0);
+#ifndef DBUG_OFF
+ case '#':
+ DBUG_SET_INITIAL(argument ? argument : default_dbug_option);
+ break;
+#endif
+ }
+ return 0;
+}
+
+
+static void get_options(int *argc,char ***argv)
+{
+ int ho_error;
+
+ if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
+ exit(ho_error);
+
+ if (opt_rfile && opt_wfile)
+ {
+ usage();
+ exit(1);
+ }
+}
+
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ uint32 i;
+ uint32 rec_len;
+ uint pagen;
+ uchar long_tr_id[6];
+ uchar lsn_buff[23]=
+ {
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55
+ };
+ uchar *long_buffer= malloc(LONG_BUFFER_SIZE + LSN_STORE_SIZE * 2 + 2);
+ char **default_argv;
+ PAGECACHE pagecache;
+ LSN lsn, lsn_base, first_lsn;
+ TRANSLOG_HEADER_BUFFER rec;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 2];
+ struct st_translog_scanner_data scanner;
+ int rc;
+
+ MY_INIT(argv[0]);
+
+ bzero(&pagecache, sizeof(pagecache));
+ maria_data_root= (char *)".";
+ load_defaults("my", load_default_groups, &argc, &argv);
+ default_argv= argv;
+ get_options(&argc, &argv);
+
+ if (maria_log_remove())
+ exit(1);
+
+ {
+ uchar buff[4];
+ for (i= 0; i < (LONG_BUFFER_SIZE + LSN_STORE_SIZE * 2 + 2); i++)
+ {
+ if (i % 4 == 0)
+ int4store(buff, (i >> 2));
+ long_buffer[i]= buff[i % 4];
+ }
+ }
+
+ bzero(long_tr_id, 6);
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ 0, 0, &translog_example_table_init, 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ trn->first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ plan(((ITERATIONS - 1) * 4 + 1) * 2);
+
+ if (opt_rfile &&
+ seq_storage_reader_init(&seq, opt_rfile))
+ exit(1);
+ srand(122334817L);
+
+ long_tr_id[5]= 0xff;
+
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ trn->short_id= 0;
+ trn->first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
+ if (translog_write_record(&lsn, LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ trn, NULL, 6, TRANSLOG_INTERNAL_PARTS + 1, parts,
+ NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%u\n", 0);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+ lsn_base= first_lsn= lsn;
+
+ for (i= 1; i < ITERATIONS; i++)
+ {
+ if (i % 2)
+ {
+ lsn_store(lsn_buff, lsn_base);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= LSN_STORE_SIZE;
+ trn->short_id= i % 0xFFFF;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_1LSN_EXAMPLE, trn, NULL,
+ LSN_STORE_SIZE, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "1 Can't write reference before record #%u\n", i);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_1LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_1LSN_EXAMPLE");
+ lsn_store(lsn_buff, lsn_base);
+ rec_len= get_len();
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= LSN_STORE_SIZE;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].length= rec_len;
+ trn->short_id= i % 0xFFFF;
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE,
+ trn, NULL, LSN_STORE_SIZE + rec_len,
+ TRANSLOG_INTERNAL_PARTS + 2,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "1 Can't write var reference before record #%u\n", i);
+ translog_destroy();
+ ok(0, "write LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE");
+ }
+ else
+ {
+ lsn_store(lsn_buff, lsn_base);
+ lsn_store(lsn_buff + LSN_STORE_SIZE, first_lsn);
+ parts[TRANSLOG_INTERNAL_PARTS + 1].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].length= 23;
+ trn->short_id= i % 0xFFFF;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_2LSN_EXAMPLE,
+ trn, NULL, 23, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "0 Can't write reference before record #%u\n", i);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_2LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_2LSN_EXAMPLE");
+ lsn_store(lsn_buff, lsn_base);
+ lsn_store(lsn_buff + LSN_STORE_SIZE, first_lsn);
+ rec_len= get_len();
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= lsn_buff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= LSN_STORE_SIZE * 2;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 1].length= rec_len;
+ trn->short_id= i % 0xFFFF;
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE,
+ trn, NULL, LSN_STORE_SIZE * 2 + rec_len,
+ TRANSLOG_INTERNAL_PARTS + 2,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "0 Can't write var reference before record #%u\n", i);
+ translog_destroy();
+ ok(0, "write LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE");
+ }
+ int4store(long_tr_id, i);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ trn->short_id= i % 0xFFFF;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ trn, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1, parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%u\n", i);
+ translog_destroy();
+ ok(0, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_FIXED_RECORD_0LSN_EXAMPLE");
+
+ lsn_base= lsn;
+
+ rec_len= get_len();
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= rec_len;
+ trn->short_id= i % 0xFFFF;
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
+ trn, NULL, rec_len,
+ TRANSLOG_INTERNAL_PARTS + 1, parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write variable record #%u\n", i);
+ translog_destroy();
+ ok(0, "write LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE");
+ exit(1);
+ }
+ ok(1, "write LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE");
+ }
+
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+
+ if (ma_control_file_open(TRUE,TRUE))
+ {
+ fprintf(stderr, "pass2: Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, 0)) == 0)
+ {
+ fprintf(stderr, "pass2: Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ 0, READONLY, &translog_example_table_init, 0))
+ {
+ fprintf(stderr, "pass2: Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+
+
+ /* If we were writing sequence we need it only once */
+ opt_wfile= NULL;
+ if (opt_rfile)
+ seq_storage_rewind(&seq);
+ srand(122334817L);
+
+ rc= 1;
+
+ {
+ int len= translog_read_record_header(first_lsn, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "translog_read_record_header failed (%d)\n", errno);
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE || rec.short_trid != 0 ||
+ rec.record_length != 6 || uint4korr(rec.header) != 0 ||
+ ((uchar)rec.header[4]) != 0 || ((uchar)rec.header[5]) != 0xFF ||
+ first_lsn != rec.lsn)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
+ "data read(0)\n"
+ "type %u, strid %u, len %u, i: %u, 4: %u 5: %u, "
+ "lsn(0x%lu,0x%lx)\n",
+ (uint) rec.type, (uint) rec.short_trid, (uint) rec.record_length,
+ (uint)uint4korr(rec.header), (uint) rec.header[4],
+ (uint) rec.header[5],
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ ok(1, "read record");
+ translog_free_record_header(&rec);
+ lsn= first_lsn;
+ if (translog_scanner_init(first_lsn, 1, &scanner, 0))
+ {
+ fprintf(stderr, "scanner init failed\n");
+ goto err;
+ }
+ for (i= 1;; i++)
+ {
+ len= translog_read_next_record_header(&scanner, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
+ i, errno);
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (len == RECHEADER_READ_EOF)
+ {
+ if (i != ITERATIONS)
+ {
+ fprintf(stderr, "EOL met at iteration %u instead of %u\n",
+ i, ITERATIONS);
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ break;
+ }
+
+ if (i % 2)
+ {
+ LSN ref;
+ ref= lsn_korr(rec.header);
+ if (rec.type != LOGREC_FIXED_RECORD_1LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != LSN_STORE_SIZE || ref != lsn)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_1LSN_EXAMPLE "
+ "data read(%d)"
+ "type %u, strid %u, len %u, ref(%lu,0x%lx), lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (uint) rec.record_length,
+ LSN_IN_PARTS(ref), LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ }
+ else
+ {
+ LSN ref1, ref2;
+ ref1= lsn_korr(rec.header);
+ ref2= lsn_korr(rec.header + LSN_STORE_SIZE);
+ if (rec.type != LOGREC_FIXED_RECORD_2LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != 23 ||
+ ref1 != lsn ||
+ ref2 != first_lsn ||
+ ((uchar)rec.header[22]) != 0x55 ||
+ ((uchar)rec.header[21]) != 0xAA ||
+ ((uchar)rec.header[20]) != 0x55 ||
+ ((uchar)rec.header[19]) != 0xAA ||
+ ((uchar)rec.header[18]) != 0x55 ||
+ ((uchar)rec.header[17]) != 0xAA ||
+ ((uchar)rec.header[16]) != 0x55 ||
+ ((uchar)rec.header[15]) != 0xAA ||
+ ((uchar)rec.header[14]) != 0x55)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_2LSN_EXAMPLE "
+ "data read(%d) "
+ "type %u, strid %u, len %u, ref1(%lu,0x%lx), "
+ "ref2(%lu,0x%lx) %x%x%x%x%x%x%x%x%x "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (uint) rec.record_length,
+ LSN_IN_PARTS(ref1), LSN_IN_PARTS(ref2),
+ (uint) rec.header[14], (uint) rec.header[15],
+ (uint) rec.header[16], (uint) rec.header[17],
+ (uint) rec.header[18], (uint) rec.header[19],
+ (uint) rec.header[20], (uint) rec.header[21],
+ (uint) rec.header[22],
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ DBUG_ASSERT(0);
+ goto err;
+ }
+ }
+ ok(1, "read record");
+ translog_free_record_header(&rec);
+
+ len= translog_read_next_record_header(&scanner, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "1-%d translog_read_next_record_header (var) "
+ "failed (%d)\n", i, errno);
+ goto err;
+ }
+ if (len == RECHEADER_READ_EOF)
+ {
+ fprintf(stderr, "EOL met at the middle of iteration (first var) %u "
+ "instead of beginning of %u\n", i, ITERATIONS);
+ goto err;
+ }
+ if (i % 2)
+ {
+ LSN ref;
+ ref= lsn_korr(rec.header);
+ rec_len= get_len();
+ if (rec.type !=LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != rec_len + LSN_STORE_SIZE ||
+ len != 12 || ref != lsn ||
+ check_content(rec.header + LSN_STORE_SIZE, len - LSN_STORE_SIZE))
+ {
+ fprintf(stderr, "Incorrect LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE "
+ "data read(%d)"
+ "type %u (%d), strid %u (%d), len %lu, %lu + 7 (%d), "
+ "hdr len: %d (%d), "
+ "ref(%lu,0x%lx), lsn(%lu,0x%lx) (%d), content: %d\n",
+ i, (uint) rec.type,
+ rec.type !=LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE,
+ (uint) rec.short_trid,
+ rec.short_trid != (i % 0xFFFF),
+ (ulong) rec.record_length, (ulong) rec_len,
+ rec.record_length != rec_len + LSN_STORE_SIZE,
+ len,
+ len != 12,
+ LSN_IN_PARTS(ref), LSN_IN_PARTS(rec.lsn),
+ (ref != lsn),
+ check_content(rec.header + LSN_STORE_SIZE,
+ len - LSN_STORE_SIZE));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (read_and_check_content(&rec, long_buffer, LSN_STORE_SIZE))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_1LSN_EXAMPLE "
+ "in whole rec read lsn(%lu,0x%lx)\n",
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ }
+ else
+ {
+ LSN ref1, ref2;
+ ref1= lsn_korr(rec.header);
+ ref2= lsn_korr(rec.header + LSN_STORE_SIZE);
+ rec_len= get_len();
+ if (rec.type != LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != rec_len + LSN_STORE_SIZE * 2 ||
+ len != 19 ||
+ ref1 != lsn ||
+ ref2 != first_lsn ||
+ check_content(rec.header + LSN_STORE_SIZE * 2,
+ len - LSN_STORE_SIZE * 2))
+ {
+ fprintf(stderr, "Incorrect LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE "
+ " data read(%d) "
+ "type %u, strid %u, len %lu != %lu + 14, hdr len: %d, "
+ "ref1(%lu,0x%lx), ref2(%lu,0x%lx), "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (ulong) rec.record_length, (ulong) rec_len,
+ len,
+ LSN_IN_PARTS(ref1), LSN_IN_PARTS(ref2),
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (read_and_check_content(&rec, long_buffer, LSN_STORE_SIZE * 2))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE "
+ "in whole rec read lsn(%lu,0x%lx)\n",
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ }
+ ok(1, "read record");
+ translog_free_record_header(&rec);
+
+ len= translog_read_next_record_header(&scanner, &rec);
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
+ i, errno);
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (len == RECHEADER_READ_EOF)
+ {
+ fprintf(stderr, "EOL met at the middle of iteration %u "
+ "instead of beginning of %u\n", i, ITERATIONS);
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (rec.type != LOGREC_FIXED_RECORD_0LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != 6 || uint4korr(rec.header) != i ||
+ ((uchar)rec.header[4]) != 0 || ((uchar)rec.header[5]) != 0xFF)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
+ "data read(%d)\n"
+ "type %u, strid %u, len %u, i: %u, 4: %u 5: %u "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (uint) rec.record_length,
+ (uint)uint4korr(rec.header), (uint) rec.header[4],
+ (uint) rec.header[5],
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ ok(1, "read record");
+ translog_free_record_header(&rec);
+
+ lsn= rec.lsn;
+
+ len= translog_read_next_record_header(&scanner, &rec);
+ rec_len= get_len();
+ if (rec.type != LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE ||
+ rec.short_trid != (i % 0xFFFF) ||
+ rec.record_length != rec_len ||
+ len != 9 || check_content(rec.header, len))
+ {
+ fprintf(stderr, "Incorrect LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE "
+ "data read(%d) "
+ "type %u, strid %u, len %lu != %lu, hdr len: %d, "
+ "lsn(%lu,0x%lx)\n",
+ i, (uint) rec.type, (uint) rec.short_trid,
+ (ulong) rec.record_length, (ulong) rec_len,
+ len, LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (read_and_check_content(&rec, long_buffer, 0))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_2LSN_EXAMPLE "
+ "in whole rec read lsn(%lu,0x%lx)\n",
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ ok(1, "read record");
+ translog_free_record_header(&rec);
+ }
+ }
+
+ rc= 0;
+err:
+ if (rc)
+ ok(0, "read record");
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+ free_defaults(default_argv);
+ seq_storage_destroy(&seq);
+ if (maria_log_remove())
+ exit(1);
+
+ return (test(exit_status()));
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_multithread-t.c b/storage/maria/unittest/ma_test_loghandler_multithread-t.c
new file mode 100644
index 00000000000..354f5d12e08
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_multithread-t.c
@@ -0,0 +1,556 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void translog_example_table_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+
+#define PCACHE_SIZE (1024*1024*10)
+
+#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
+/*#define LOG_FLAGS TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC */
+#define LOG_FLAGS 0
+/*#define LONG_BUFFER_SIZE (1024L*1024L*1024L + 1024L*1024L*512)*/
+
+#ifdef MULTIFLUSH_TEST
+
+#define LONG_BUFFER_SIZE (16384L)
+#define MIN_REC_LENGTH 10
+#define SHOW_DIVIDER 20
+#define ITERATIONS 10000
+#define FLUSH_ITERATIONS 1000
+#define WRITERS 2
+#define FLUSHERS 10
+
+#else
+
+#define LONG_BUFFER_SIZE (512L*1024L*1024L)
+#define MIN_REC_LENGTH 30
+#define SHOW_DIVIDER 10
+#define ITERATIONS 3
+#define FLUSH_ITERATIONS 0
+#define WRITERS 3
+#define FLUSHERS 0
+
+#endif
+
+static uint number_of_writers= WRITERS;
+static uint number_of_flushers= FLUSHERS;
+
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+
+static ulong lens[WRITERS][ITERATIONS];
+static LSN lsns1[WRITERS][ITERATIONS];
+static LSN lsns2[WRITERS][ITERATIONS];
+static uchar *long_buffer;
+
+
+static LSN last_lsn; /* For test purposes the variable allow dirty read/write */
+
+/*
+ Get pseudo-random length of the field in
+ limits [MIN_REC_LENGTH..LONG_BUFFER_SIZE]
+
+ SYNOPSIS
+ get_len()
+
+ RETURN
+ length - length >= 0 length <= LONG_BUFFER_SIZE
+*/
+
+static uint32 get_len()
+{
+ return MIN_REC_LENGTH +
+ (uint32)(((ulonglong)rand())*
+ (LONG_BUFFER_SIZE - MIN_REC_LENGTH - 1)/RAND_MAX);
+}
+
+
+/*
+ Check that the buffer filled correctly
+
+ SYNOPSIS
+ check_content()
+ ptr Pointer to the buffer
+ length length of the buffer
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+static my_bool check_content(uchar *ptr, ulong length)
+{
+ ulong i;
+ for (i= 0; i < length; i++)
+ {
+ if (((uchar)ptr[i]) != (i & 0xFF))
+ {
+ fprintf(stderr, "Byte # %lu is %x instead of %x",
+ i, (uint) ptr[i], (uint) (i & 0xFF));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ Read whole record content, and check content (put with offset)
+
+ SYNOPSIS
+ read_and_check_content()
+ rec The record header buffer
+ buffer The buffer to read the record in
+ skip Skip this number of bytes ot the record content
+
+ RETURN
+ 0 - OK
+ 1 - Error
+*/
+
+
+static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
+ uchar *buffer, uint skip)
+{
+ int res= 0;
+ translog_size_t len;
+
+ if ((len= translog_read_record(rec->lsn, 0, rec->record_length,
+ buffer, NULL)) != rec->record_length)
+ {
+ fprintf(stderr, "Requested %lu byte, read %lu\n",
+ (ulong) rec->record_length, (ulong) len);
+ res= 1;
+ }
+ res|= check_content(buffer + skip, rec->record_length - skip);
+ return(res);
+}
+
+void writer(int num)
+{
+ LSN lsn;
+ TRN trn;
+ uchar long_tr_id[6];
+ uint i;
+
+ trn.short_id= num;
+ trn.first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
+ for (i= 0; i < ITERATIONS; i++)
+ {
+ uint len= get_len();
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+ lens[num][i]= len;
+
+ int2store(long_tr_id, num);
+ int4store(long_tr_id + 2, i);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &trn, NULL, 6, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write LOGREC_FIXED_RECORD_0LSN_EXAMPLE record #%lu "
+ "thread %i\n", (ulong) i, num);
+ translog_destroy();
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(0, "write records");
+ pthread_mutex_unlock(&LOCK_thread_count);
+ return;
+ }
+ lsns1[num][i]= lsn;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= len;
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
+ &trn, NULL,
+ len, TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write variable record #%lu\n", (ulong) i);
+ translog_destroy();
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(0, "write records");
+ pthread_mutex_unlock(&LOCK_thread_count);
+ return;
+ }
+ lsns2[num][i]= lsn;
+ last_lsn= lsn;
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "write records");
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+ return;
+}
+
+
+static void *test_thread_writer(void *arg)
+{
+ int param= *((int*) arg);
+
+ my_thread_init();
+
+ writer(param);
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ ok(1, "writer finished"); /* just to show progress */
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are
+ ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ return(0);
+}
+
+
+static void *test_thread_flusher(void *arg)
+{
+ int param= *((int*) arg);
+ int i;
+
+ my_thread_init();
+
+ for(i= 0; i < FLUSH_ITERATIONS; i++)
+ {
+ translog_flush(last_lsn);
+ pthread_mutex_lock(&LOCK_thread_count);
+ ok(1, "-- flush %d", param);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ ok(1, "flusher finished"); /* just to show progress */
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are
+ ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((uchar*) arg);
+ my_thread_end();
+ return(0);
+}
+
+
+int main(int argc __attribute__((unused)),
+ char **argv __attribute__ ((unused)))
+{
+ uint32 i;
+ uint pagen;
+ PAGECACHE pagecache;
+ LSN first_lsn;
+ TRANSLOG_HEADER_BUFFER rec;
+ struct st_translog_scanner_data scanner;
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int *param, error;
+ int rc;
+
+ /* Disabled until Sanja tests */
+ plan(1);
+ ok(1, "disabled");
+ exit(0);
+
+ plan(WRITERS + FLUSHERS +
+ ITERATIONS * WRITERS * 3 + FLUSH_ITERATIONS * FLUSHERS );
+
+ bzero(&pagecache, sizeof(pagecache));
+ maria_data_root= (char *)".";
+ long_buffer= malloc(LONG_BUFFER_SIZE + 7 * 2 + 2);
+ if (long_buffer == 0)
+ {
+ fprintf(stderr, "End of memory\n");
+ exit(1);
+ }
+ for (i= 0; i < (LONG_BUFFER_SIZE + 7 * 2 + 2); i++)
+ long_buffer[i]= (i & 0xFF);
+
+ MY_INIT(argv[0]);
+ if (maria_log_remove())
+ exit(1);
+
+
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+
+ if ((error= pthread_cond_init(&COND_thread_count, NULL)))
+ {
+ fprintf(stderr, "COND_thread_count: %d from pthread_cond_init "
+ "(errno: %d)\n", error, errno);
+ exit(1);
+ }
+ if ((error= pthread_mutex_init(&LOCK_thread_count, MY_MUTEX_INIT_FAST)))
+ {
+ fprintf(stderr, "LOCK_thread_count: %d from pthread_cond_init "
+ "(errno: %d)\n", error, errno);
+ exit(1);
+ }
+ if ((error= pthread_attr_init(&thr_attr)))
+ {
+ fprintf(stderr, "Got error: %d from pthread_attr_init "
+ "(errno: %d)\n", error, errno);
+ exit(1);
+ }
+ if ((error= pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED)))
+ {
+ fprintf(stderr,
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+
+#ifdef HAVE_THR_SETCONCURRENCY
+ VOID(thr_setconcurrency(2));
+#endif
+
+ my_thread_global_init();
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ TRANSLOG_PAGE_SIZE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ srand(122334817L);
+ {
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+ uchar long_tr_id[6]=
+ {
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66
+ };
+
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ dummy_transaction_object.first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
+ if (translog_write_record(&first_lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write the first record\n");
+ translog_destroy();
+ exit(1);
+ }
+ }
+
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (number_of_writers != 0 || number_of_flushers != 0)
+ {
+ if (number_of_writers)
+ {
+ param= (int*) malloc(sizeof(int));
+ *param= number_of_writers - 1;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_writer,
+ (void*) param)))
+ {
+ fprintf(stderr, "Got error: %d from pthread_create (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_writers--;
+ }
+ if (number_of_flushers)
+ {
+ param= (int*) malloc(sizeof(int));
+ *param= number_of_flushers - 1;
+ if ((error= pthread_create(&tid, &thr_attr, test_thread_flusher,
+ (void*) param)))
+ {
+ fprintf(stderr, "Got error: %d from pthread_create (errno: %d)\n",
+ error, errno);
+ exit(1);
+ }
+ thread_count++;
+ number_of_flushers--;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ pthread_attr_destroy(&thr_attr);
+
+ /* wait finishing */
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ if ((error= pthread_cond_wait(&COND_thread_count, &LOCK_thread_count)))
+ fprintf(stderr, "COND_thread_count: %d from pthread_cond_wait\n", error);
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ /* Find last LSN and flush up to it (all our log) */
+ {
+ LSN max= 0;
+ for (i= 0; i < WRITERS; i++)
+ {
+ if (cmp_translog_addr(lsns2[i][ITERATIONS - 1], max) > 0)
+ max= lsns2[i][ITERATIONS - 1];
+ }
+ translog_flush(max);
+ }
+
+ rc= 1;
+
+ {
+ uint indeces[WRITERS];
+ uint index, stage;
+ int len;
+ bzero(indeces, sizeof(uint) * WRITERS);
+
+ bzero(indeces, sizeof(indeces));
+
+ if (translog_scanner_init(first_lsn, 1, &scanner, 0))
+ {
+ fprintf(stderr, "scanner init failed\n");
+ goto err;
+ }
+ for (i= 0;; i++)
+ {
+ len= translog_read_next_record_header(&scanner, &rec);
+
+ if (len == RECHEADER_READ_ERROR)
+ {
+ fprintf(stderr, "1-%d translog_read_next_record_header failed (%d)\n",
+ i, errno);
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (len == RECHEADER_READ_EOF)
+ {
+ if (i != WRITERS * ITERATIONS * 2)
+ {
+ fprintf(stderr, "EOL met at iteration %u instead of %u\n",
+ i, ITERATIONS * WRITERS * 2);
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ break;
+ }
+ index= indeces[rec.short_trid] / 2;
+ stage= indeces[rec.short_trid] % 2;
+ if (stage == 0)
+ {
+ if (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE ||
+ rec.record_length != 6 ||
+ uint2korr(rec.header) != rec.short_trid ||
+ index != uint4korr(rec.header + 2) ||
+ cmp_translog_addr(lsns1[rec.short_trid][index], rec.lsn) != 0)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
+ "data read(%d)\n"
+ "type %u, strid %u %u, len %u, i: %u %u, "
+ "lsn(%lu,0x%lx) (%lu,0x%lx)\n",
+ i, (uint) rec.type,
+ (uint) rec.short_trid, (uint) uint2korr(rec.header),
+ (uint) rec.record_length,
+ (uint) index, (uint) uint4korr(rec.header + 2),
+ LSN_IN_PARTS(rec.lsn),
+ LSN_IN_PARTS(lsns1[rec.short_trid][index]));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ }
+ else
+ {
+ if (rec.type != LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE ||
+ len != 9 ||
+ rec.record_length != lens[rec.short_trid][index] ||
+ cmp_translog_addr(lsns2[rec.short_trid][index], rec.lsn) != 0 ||
+ check_content(rec.header, (uint)len))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE "
+ "data read(%d) "
+ "thread: %d, iteration %d, stage %d\n"
+ "type %u (%d), len %d, length %lu %lu (%d) "
+ "lsn(%lu,0x%lx) (%lu,0x%lx)\n",
+ i, (uint) rec.short_trid, index, stage,
+ (uint) rec.type, (rec.type !=
+ LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE),
+ len,
+ (ulong) rec.record_length, lens[rec.short_trid][index],
+ (rec.record_length != lens[rec.short_trid][index]),
+ LSN_IN_PARTS(rec.lsn),
+ LSN_IN_PARTS(lsns2[rec.short_trid][index]));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ if (read_and_check_content(&rec, long_buffer, 0))
+ {
+ fprintf(stderr,
+ "Incorrect LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE "
+ "in whole rec read lsn(%lu,0x%lx)\n",
+ LSN_IN_PARTS(rec.lsn));
+ translog_free_record_header(&rec);
+ goto err;
+ }
+ }
+ ok(1, "record read");
+ translog_free_record_header(&rec);
+ indeces[rec.short_trid]++;
+ }
+ }
+
+ rc= 0;
+err:
+ if (rc)
+ ok(0, "record read");
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+ if (maria_log_remove())
+ exit(1);
+
+ return(exit_status());
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_noflush-t.c b/storage/maria/unittest/ma_test_loghandler_noflush-t.c
new file mode 100644
index 00000000000..973dfd03bcf
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_noflush-t.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void translog_example_table_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+
+#define PCACHE_SIZE (1024*1024*10)
+#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
+#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
+#define LOG_FLAGS 0
+
+static char *first_translog_file= (char*)"maria_log.00000001";
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ uint pagen;
+ int rc= 1;
+ uchar long_tr_id[6];
+ PAGECACHE pagecache;
+ LSN first_lsn;
+ TRANSLOG_HEADER_BUFFER rec;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+ translog_size_t len;
+
+ MY_INIT(argv[0]);
+
+ plan(1);
+
+ bzero(&pagecache, sizeof(pagecache));
+ maria_data_root= (char *)".";
+ if (maria_log_remove())
+ exit(1);
+ /* be sure that we have no logs in the directory*/
+ my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
+ my_delete(first_translog_file, MYF(0));
+
+ bzero(long_tr_id, 6);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ PCACHE_PAGE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ int4store(long_tr_id, 0);
+ long_tr_id[5]= 0xff;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&first_lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
+ translog_destroy();
+ exit(1);
+ }
+
+ len= translog_read_record_header(first_lsn, &rec);
+ if (len == 0)
+ {
+ fprintf(stderr, "translog_read_record_header failed (%d)\n", errno);
+ goto err;
+ }
+ if (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE || rec.short_trid != 0 ||
+ rec.record_length != 6 || uint4korr(rec.header) != 0 ||
+ ((uchar)rec.header[4]) != 0 || ((uchar)rec.header[5]) != 0xFF ||
+ first_lsn != rec.lsn)
+ {
+ fprintf(stderr, "Incorrect LOGREC_FIXED_RECORD_0LSN_EXAMPLE "
+ "data read(0)\n"
+ "type: %u (%d) strid: %u (%d) len: %u (%d) i: %u (%d), "
+ "4: %u (%d) 5: %u (%d) "
+ "lsn(%lu,0x%lx) (%d)\n",
+ (uint) rec.type, (rec.type !=LOGREC_FIXED_RECORD_0LSN_EXAMPLE),
+ (uint) rec.short_trid, (rec.short_trid != 0),
+ (uint) rec.record_length, (rec.record_length != 6),
+ (uint) uint4korr(rec.header), (uint4korr(rec.header) != 0),
+ (uint) rec.header[4], (((uchar)rec.header[4]) != 0),
+ (uint) rec.header[5], (((uchar)rec.header[5]) != 0xFF),
+ LSN_IN_PARTS(rec.lsn), (first_lsn != rec.lsn));
+ goto err;
+ }
+
+ ok(1, "read OK");
+ rc= 0;
+
+err:
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+ if (maria_log_remove())
+ exit(1);
+
+ exit(rc);
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_nologs-t.c b/storage/maria/unittest/ma_test_loghandler_nologs-t.c
new file mode 100644
index 00000000000..34508d1d751
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_nologs-t.c
@@ -0,0 +1,195 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void example_loghandler_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+
+#define PCACHE_SIZE (1024*1024*10)
+#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
+#define LOG_FILE_SIZE (8*1024L*1024L)
+#define LOG_FLAGS 0
+#define LONG_BUFFER_SIZE (LOG_FILE_SIZE + LOG_FILE_SIZE / 2)
+
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ ulong i;
+ uint pagen;
+ uchar long_tr_id[6];
+ PAGECACHE pagecache;
+ LSN lsn;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+ uchar *long_buffer= malloc(LONG_BUFFER_SIZE);
+
+ MY_INIT(argv[0]);
+
+ plan(2);
+
+ bzero(&pagecache, sizeof(pagecache));
+ bzero(long_buffer, LONG_BUFFER_SIZE);
+ maria_data_root= (char *)".";
+ if (maria_log_remove())
+ exit(1);
+
+ bzero(long_tr_id, 6);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ PCACHE_PAGE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ /* write more then 1 file */
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #0\n");
+ translog_destroy();
+ exit(1);
+ }
+
+ for(i= 0; i < LOG_FILE_SIZE/6 && LSN_FILE_NO(lsn) == 1; i++)
+ {
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #0\n");
+ translog_destroy();
+ exit(1);
+ }
+ }
+
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+
+ {
+ char file_name[FN_REFLEN];
+ for (i= 1; i <= 2; i++)
+ {
+ translog_filename_by_fileno(i, file_name);
+ if (my_access(file_name, W_OK))
+ {
+ fprintf(stderr, "No file '%s'\n", file_name);
+ exit(1);
+ }
+ if (my_delete(file_name, MYF(MY_WME)) != 0)
+ {
+ fprintf(stderr, "Error %d during removing file'%s'\n",
+ errno, file_name);
+ exit(1);
+ }
+ }
+ }
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ PCACHE_PAGE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 1))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ ok(1, "Log init OK");
+
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #0\n");
+ translog_destroy();
+ exit(1);
+ }
+
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+
+ if (!translog_is_file(3))
+ {
+ fprintf(stderr, "No file #3\n");
+ exit(1);
+ }
+
+ ok(1, "New log is OK");
+
+ if (maria_log_remove())
+ exit(1);
+ exit(0);
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_pagecache-t.c b/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
new file mode 100644
index 00000000000..bfbba5407c1
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_pagecache-t.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void translog_example_table_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+
+#define PCACHE_SIZE (1024*1024*10)
+#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
+#define LOG_FILE_SIZE (1024L*1024L*1024L + 1024L*1024L*512)
+#define LOG_FLAGS 0
+
+static char *first_translog_file= (char*)"maria_log.00000001";
+static char *file1_name= (char*)"page_cache_test_file_1";
+static PAGECACHE_FILE file1;
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static my_bool
+dummy_callback(uchar *page __attribute__((unused)),
+ pgcache_page_no_t page_no __attribute__((unused)),
+ uchar* data_ptr __attribute__((unused)))
+{
+ return 0;
+}
+
+
+/**
+ @brief Dummy pagecache callback.
+*/
+
+static void
+dummy_fail_callback(uchar* data_ptr __attribute__((unused)))
+{
+ return;
+}
+
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ uint pagen;
+ uchar long_tr_id[6];
+ PAGECACHE pagecache;
+ LSN lsn;
+ my_off_t file_size;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+
+ MY_INIT(argv[0]);
+
+ plan(1);
+
+ bzero(&pagecache, sizeof(pagecache));
+ maria_data_root= (char *)".";
+ if (maria_log_remove())
+ exit(1);
+ /* be sure that we have no logs in the directory*/
+ my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
+ my_delete(first_translog_file, MYF(0));
+
+ bzero(long_tr_id, 6);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler_pagecache.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler_pagecache.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ PCACHE_PAGE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ if ((file1.file= my_open(first_translog_file, O_RDONLY, MYF(MY_WME))) < 0)
+ {
+ fprintf(stderr, "There is no %s (%d)\n", first_translog_file, errno);
+ exit(1);
+ }
+ file_size= my_seek(file1.file, 0, SEEK_END, MYF(MY_WME));
+ if (file_size != TRANSLOG_PAGE_SIZE)
+ {
+ fprintf(stderr,
+ "incorrect initial size of %s: %ld instead of %ld\n",
+ first_translog_file, (long)file_size, (long)TRANSLOG_PAGE_SIZE);
+ exit(1);
+ }
+ my_close(file1.file, MYF(MY_WME));
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ dummy_transaction_object.first_undo_lsn= TRANSACTION_LOGGED_LONG_ID;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
+ translog_destroy();
+ exit(1);
+ }
+
+ if ((file1.file= my_open(file1_name,
+ O_CREAT | O_TRUNC | O_RDWR, MYF(0))) == -1)
+ {
+ fprintf(stderr, "Got error during file1 creation from open() (errno: %d)\n",
+ errno);
+ exit(1);
+ }
+ pagecache_file_init(file1, &dummy_callback, &dummy_callback,
+ &dummy_fail_callback, maria_flush_log_for_page, NULL);
+ if (my_chmod(file1_name, S_IRWXU | S_IRWXG | S_IRWXO, MYF(MY_WME)))
+ exit(1);
+
+ {
+ uchar page[PCACHE_PAGE];
+
+ bzero(page, PCACHE_PAGE);
+ lsn_store(page, lsn);
+ pagecache_write(&pagecache, &file1, 0, 3, page,
+ PAGECACHE_LSN_PAGE,
+ PAGECACHE_LOCK_LEFT_UNLOCKED,
+ PAGECACHE_PIN_LEFT_UNPINNED,
+ PAGECACHE_WRITE_DELAY,
+ 0, LSN_IMPOSSIBLE);
+ flush_pagecache_blocks(&pagecache, &file1, FLUSH_FORCE_WRITE);
+ }
+ my_close(file1.file, MYF(MY_WME));
+ if ((file1.file= my_open(first_translog_file, O_RDONLY, MYF(MY_WME))) < 0)
+ {
+ fprintf(stderr, "can't open %s (%d)\n", first_translog_file, errno);
+ exit(1);
+ }
+ file_size= my_seek(file1.file, 0, SEEK_END, MYF(MY_WME));
+ if (file_size != TRANSLOG_PAGE_SIZE * 2)
+ {
+ fprintf(stderr,
+ "incorrect initial size of %s: %ld instead of %ld\n",
+ first_translog_file,
+ (long)file_size, (long)(TRANSLOG_PAGE_SIZE * 2));
+ ok(0, "log triggered");
+ exit(1);
+ }
+ my_close(file1.file, MYF(MY_WME));
+ ok(1, "log triggered");
+
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+ my_delete(CONTROL_FILE_BASE_NAME, MYF(0));
+ my_delete(first_translog_file, MYF(0));
+ my_delete(file1_name, MYF(0));
+
+ exit(0);
+}
diff --git a/storage/maria/unittest/ma_test_loghandler_purge-t.c b/storage/maria/unittest/ma_test_loghandler_purge-t.c
new file mode 100644
index 00000000000..d37b45bc3ca
--- /dev/null
+++ b/storage/maria/unittest/ma_test_loghandler_purge-t.c
@@ -0,0 +1,192 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include <stdio.h>
+#include <errno.h>
+#include <tap.h>
+#include "../trnman.h"
+
+extern my_bool maria_log_remove();
+extern void translog_example_table_init();
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option;
+#endif
+
+#define PCACHE_SIZE (1024*1024*10)
+#define PCACHE_PAGE TRANSLOG_PAGE_SIZE
+#define LOG_FILE_SIZE (8*1024L*1024L)
+#define LOG_FLAGS 0
+#define LONG_BUFFER_SIZE (LOG_FILE_SIZE + LOG_FILE_SIZE / 2)
+
+
+int main(int argc __attribute__((unused)), char *argv[])
+{
+ ulong i;
+ uint pagen;
+ uchar long_tr_id[6];
+ PAGECACHE pagecache;
+ LSN lsn;
+ LEX_CUSTRING parts[TRANSLOG_INTERNAL_PARTS + 1];
+ uchar *long_buffer= malloc(LONG_BUFFER_SIZE);
+
+ MY_INIT(argv[0]);
+
+ plan(4);
+
+ bzero(&pagecache, sizeof(pagecache));
+ bzero(long_buffer, LONG_BUFFER_SIZE);
+ maria_data_root= (char *)".";
+ if (maria_log_remove())
+ exit(1);
+
+ bzero(long_tr_id, 6);
+#ifndef DBUG_OFF
+#if defined(__WIN__)
+ default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
+#else
+ default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
+#endif
+ if (argc > 1)
+ {
+ DBUG_SET(default_dbug_option);
+ DBUG_SET_INITIAL(default_dbug_option);
+ }
+#endif
+
+ if (ma_control_file_open(TRUE, TRUE))
+ {
+ fprintf(stderr, "Can't init control file (%d)\n", errno);
+ exit(1);
+ }
+ if ((pagen= init_pagecache(&pagecache, PCACHE_SIZE, 0, 0,
+ PCACHE_PAGE, 0)) == 0)
+ {
+ fprintf(stderr, "Got error: init_pagecache() (errno: %d)\n", errno);
+ exit(1);
+ }
+ if (translog_init_with_table(".", LOG_FILE_SIZE, 50112, 0, &pagecache,
+ LOG_FLAGS, 0, &translog_example_table_init,
+ 0))
+ {
+ fprintf(stderr, "Can't init loghandler (%d)\n", errno);
+ exit(1);
+ }
+ /* Suppressing of automatic record writing */
+ dummy_transaction_object.first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID;
+
+ /* write more then 1 file */
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
+ translog_destroy();
+ exit(1);
+ }
+
+ translog_purge(lsn);
+ if (!translog_is_file(1))
+ {
+ fprintf(stderr, "First file was removed after first record\n");
+ translog_destroy();
+ exit(1);
+ }
+ ok(1, "First is not removed");
+
+ for(i= 0; i < LOG_FILE_SIZE/6 && LSN_FILE_NO(lsn) == 1; i++)
+ {
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write record #%lu\n", (ulong) 0);
+ translog_destroy();
+ exit(1);
+ }
+ }
+
+ translog_purge(lsn);
+ if (translog_is_file(1))
+ {
+ fprintf(stderr, "First file was not removed.\n");
+ translog_destroy();
+ exit(1);
+ }
+
+ ok(1, "First file is removed");
+
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_buffer;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= LONG_BUFFER_SIZE;
+ if (translog_write_record(&lsn,
+ LOGREC_VARIABLE_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, LONG_BUFFER_SIZE,
+ TRANSLOG_INTERNAL_PARTS + 1, parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write variable record\n");
+ translog_destroy();
+ exit(1);
+ }
+
+ translog_purge(lsn);
+ if (!translog_is_file(2) || !translog_is_file(3))
+ {
+ fprintf(stderr, "Second file (%d) or third file (%d) is not present.\n",
+ translog_is_file(2), translog_is_file(3));
+ translog_destroy();
+ exit(1);
+ }
+
+ ok(1, "Second and third files are not removed");
+
+ int4store(long_tr_id, 0);
+ parts[TRANSLOG_INTERNAL_PARTS + 0].str= long_tr_id;
+ parts[TRANSLOG_INTERNAL_PARTS + 0].length= 6;
+ if (translog_write_record(&lsn,
+ LOGREC_FIXED_RECORD_0LSN_EXAMPLE,
+ &dummy_transaction_object, NULL, 6,
+ TRANSLOG_INTERNAL_PARTS + 1,
+ parts, NULL, NULL))
+ {
+ fprintf(stderr, "Can't write last record\n");
+ translog_destroy();
+ exit(1);
+ }
+
+ translog_purge(lsn);
+ if (translog_is_file(2))
+ {
+ fprintf(stderr, "Second file is not removed\n");
+ translog_destroy();
+ exit(1);
+ }
+
+ ok(1, "Second file is removed");
+
+ translog_destroy();
+ end_pagecache(&pagecache, 1);
+ ma_control_file_end();
+ if (maria_log_remove())
+ exit(1);
+ exit(0);
+}
diff --git a/storage/maria/unittest/ma_test_recovery.expected b/storage/maria/unittest/ma_test_recovery.expected
new file mode 100644
index 00000000000..b95575173ee
--- /dev/null
+++ b/storage/maria/unittest/ma_test_recovery.expected
@@ -0,0 +1,1578 @@
+Testing the REDO PHASE ALONE
+TEST WITH ma_test1 -s -M -T -c
+applying log
+testing idempotency
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -d500
+applying log
+testing idempotency
+applying log
+TEST WITH ma_test2 -s -M -T -c -b65000
+applying log
+testing idempotency
+applying log
+TEST WITH ma_test2 -s -M -T -c -b65000 -d800
+applying log
+testing idempotency
+applying log
+TEST WITH ma_test1 -s -M -T -c -C
+applying log
+testing idempotency
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -d500 -C
+applying log
+testing idempotency
+applying log
+Testing the REDO AND UNDO PHASE
+TEST WITH ma_test1 -s -M -T -c -N --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 --test-undo=1 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=1 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t2 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t6 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 --test-undo=2 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=2 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t2 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t6 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 --test-undo=3 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=3 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t2 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t6 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 --test-undo=4 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N --testflag=3 --test-undo=4 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t2 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -t6 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 --test-undo=1 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=1 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t2 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t6 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 --test-undo=2 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=2 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t2 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t6 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 --test-undo=3 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=3 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t2 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t6 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 --test-undo=4 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 --testflag=3 --test-undo=4 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t2 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -t6 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=2 --test-undo=1 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=1 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t2 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t6 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=2 --test-undo=2 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=2 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t2 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t6 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=2 --test-undo=3 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=3 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t2 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t6 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -H1 --testflag=2 --test-undo=4 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -H2 --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -H2 --testflag=3 --test-undo=4 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t2 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -H1 -t6 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=2 --test-undo=1 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=1 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=1 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t2 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t6 -A1 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=2 --test-undo=2 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=2 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=2 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t2 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t6 -A2 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=2 --test-undo=3 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=3 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=3 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t2 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t6 -A3 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=1 (commit at end)
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H1 --testflag=2 --test-undo=4 (additional aborted work)
+Terminating after inserts
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=3 (commit at end)
+Terminating after updates
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --versioning --testflag=4 --test-undo=4 (additional aborted work)
+Terminating after deletes
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=2 (commit at end)
+Terminating after inserts
+TEST WITH ma_test1 -s -M -T -c -N -b32768 -H2 --testflag=3 --test-undo=4 (additional aborted work)
+Terminating after updates
+Dying on request without maria_commit()/maria_close()
+applying log
+testing idempotency
+applying log
+testing applying of CLRs to recreate table
+applying log
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t2 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t1 (commit at end)
+TEST WITH ma_test2 -s -L -K -W -P -M -T -c -b32768 -H1 -t6 -A4 (additional aborted work)
+Dying on request without maria_commit()/maria_close()
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing idempotency
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
+testing applying of CLRs to recreate table
+applying log
+Differences in maria_chk -dvv, recovery not yet perfect !
+========DIFF START=======
+6c6
+< Status: checked,analyzed,optimized keys,sorted index pages,zerofilled,movable
+---
+> Status: changed
+========DIFF END=======
diff --git a/storage/maria/unittest/ma_test_recovery.pl b/storage/maria/unittest/ma_test_recovery.pl
new file mode 100755
index 00000000000..58b9cc3b56b
--- /dev/null
+++ b/storage/maria/unittest/ma_test_recovery.pl
@@ -0,0 +1,481 @@
+#!/usr/bin/env perl
+
+use Getopt::Long;
+use File::Copy;
+use File::Compare;
+use File::Basename;
+use Digest::MD5;
+
+$|= 1;
+$^W = 1; # warnings, because env cannot parse 'perl -w'
+$VER= "1.2";
+
+$opt_version= 0;
+$opt_help= 0;
+$opt_verbose= 0;
+$opt_abort_on_error=0;
+
+my $silent= "-s";
+my $maria_path; # path to "storage/maria"
+my $maria_exe_path; # path to executables (ma_test1, maria_chk etc)
+my $tmp= "./tmp";
+my $my_progname= $0;
+my $suffix;
+my $zerofilled_tables= 0;
+
+$my_progname=~ s/.*[\/]//;
+$maria_path= dirname($0) . "/..";
+
+main();
+
+####
+#### main function
+####
+
+sub main
+{
+ my ($res, $table);
+
+ if (!GetOptions("abort-on-error", "help", "version", "verbose"))
+ {
+ $flag_exit= 1;
+ }
+ if ($opt_version)
+ {
+ print "$my_progname version $VER\n";
+ exit(0);
+ }
+ usage() if ($opt_help || $flag_exit);
+
+ $suffix= ( $^O =~ /win/i && $^O !~ /darwin/i ) ? ".exe" : "";
+ $maria_exe_path= "$maria_path/release";
+ # we use -f, sometimes -x is unexpectedly false in Cygwin
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ $maria_exe_path= "$maria_path/relwithdebinfo";
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ $maria_exe_path= "$maria_path/debug";
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ $maria_exe_path= $maria_path;
+ if ( ! -f "$maria_exe_path/ma_test1$suffix" )
+ {
+ die("Cannot find ma_test1 executable\n");
+ }
+ }
+ }
+ }
+
+ # test data is always put in the current directory or a tmp subdirectory
+ # of it
+
+ if (! -d "$tmp")
+ {
+ mkdir $tmp;
+ }
+ print "MARIA RECOVERY TESTS\n";
+
+ # To not flood the screen, we redirect all the commands below to a text file
+ # and just give a final error if their output is not as expected
+
+ open (MY_LOG, ">$tmp/ma_test_recovery.output") or die "Can't open log file\n";
+ print MY_LOG "Testing the REDO PHASE ALONE\n";
+
+ # runs a program inserting/deleting rows, then moves the resulting table
+ # elsewhere; applies the log and checks that the data file is
+ # identical to the saved original.
+
+ my @t= ("ma_test1$suffix $silent -M -T -c",
+ "ma_test2$suffix $silent -L -K -W -P -M -T -c -d500",
+ "ma_test2$suffix $silent -M -T -c -b65000",
+ "ma_test2$suffix $silent -M -T -c -b65000 -d800",
+ "ma_test1$suffix $silent -M -T -c -C",
+ "ma_test2$suffix $silent -L -K -W -P -M -T -c -d500 -C",
+ #"ma_rt_test$suffix $silent -M -T -c -C",
+ # @todo: also add to @t2
+ );
+
+ foreach my $prog (@t)
+ {
+ unlink <maria_log.* maria_log_control>;
+ my $prog_no_suffix= $prog;
+ $prog_no_suffix=~ s/$suffix// if ($suffix);
+ print MY_LOG "TEST WITH $prog_no_suffix\n";
+ $res= my_exec("$maria_exe_path/$prog");
+ print MY_LOG $res;
+ # derive table's name from program's name
+ if ($prog =~ m/^ma_(\S+)\s.*/)
+ {
+ $table= $1;
+ }
+ else
+ {
+ die("can't guess table name");
+ }
+ $com= "$maria_exe_path/maria_chk$suffix -dvv $table ";
+ $com.= "| grep -v \"Creation time:\" | grep -v \"file length\" | grep -v \"LSNs:\" | grep -v \"UUID:\"";
+ $com.= "> $tmp/maria_chk_message.good.txt 2>&1";
+ my_exec($com);
+ my $checksum= my_exec("$maria_exe_path/maria_chk$suffix -dss $table");
+ move("$table.MAD", "$tmp/$table-good.MAD") ||
+ die "Can't move $table.MAD to $tmp/$table-good.MAD\n";
+ move("$table.MAI", "$tmp/$table-good.MAI") ||
+ die "Can't move $table.MAI to $tmp/$table-good.MAI\n";
+ apply_log($table, "shouldnotchangelog");
+ check_table_is_same($table, $checksum);
+ $res= physical_cmp($table, "$tmp/$table-good");
+ print MY_LOG $res;
+ print MY_LOG "testing idempotency\n";
+ apply_log($table, "shouldnotchangelog");
+ check_table_is_same($table, $checksum);
+ $res= physical_cmp($table, "$tmp/$table-good");
+ print MY_LOG $res;
+ }
+
+ print MY_LOG "Testing the REDO AND UNDO PHASE\n";
+ # The test programs look like:
+ # work; commit (time T1); work; exit-without-commit (time T2)
+ # We first run the test program and let it exit after T1's commit.
+ # Then we run it again and let it exit at T2. Then we compare
+ # and expect identity.
+
+ my @take_checkpoints= ("no", "yes");
+ my @blobs= ("", "-b32768");
+ my @test_undo= (1, 2, 3, 4);
+ my @t2= ("ma_test1$suffix $silent -M -T -c -N blob -H1",
+ "--testflag=1",
+ "--testflag=2 --test-undo=",
+ "ma_test1$suffix $silent -M -T -c -N blob -H2",
+ "--testflag=3",
+ "--testflag=4 --test-undo=",
+ "ma_test1$suffix $silent -M -T -c -N blob -H2 --versioning",
+ "--testflag=3",
+ "--testflag=4 --test-undo=",
+ "ma_test1$suffix $silent -M -T -c -N blob -H2",
+ "--testflag=2",
+ "--testflag=3 --test-undo=",
+ "ma_test2$suffix $silent -L -K -W -P -M -T -c blob -H1",
+ "-t1",
+ "-t2 -A",
+ "ma_test2$suffix $silent -L -K -W -P -M -T -c blob -H1",
+ "-t1",
+ "-t6 -A");
+
+ foreach my $take_checkpoint (@take_checkpoints)
+ {
+ my ($i, $j, $k, $commit_run_args, $abort_run_args);
+ # we test table without blobs and then table with blobs
+ for ($i= 0; defined($blobs[$i]); $i++)
+ {
+ for ($j= 0; defined($test_undo[$j]); $j++)
+ {
+ # first iteration tests rollback of insert, second tests rollback of delete
+ # -N (create NULL fields) is needed because --test-undo adds it anyway
+ for ($k= 0; defined($t2[$k]); $k+= 3)
+ {
+ $prog= $t2[$k];
+ $prog=~ s/blob/$blobs[$i]/;
+ if ("$take_checkpoint" eq "no") {
+ $prog=~ s/\s+\-H[0-9]+//;
+ }
+ $commit_run_args= $t2[$k + 1];
+ $abort_run_args= $t2[$k + 2];
+ unlink <maria_log.* maria_log_control>;
+ my $prog_no_suffix= $prog;
+ $prog_no_suffix=~ s/$suffix// if ($suffix);
+ print MY_LOG "TEST WITH $prog_no_suffix $commit_run_args (commit at end)\n";
+ $res= my_exec("$maria_exe_path/$prog $commit_run_args");
+ print MY_LOG $res;
+ # derive table's name from program's name
+ if ($prog =~ m/^ma_(\S+)\s.*/)
+ {
+ $table= $1;
+ }
+ else
+ {
+ die("can't guess table name");
+ }
+ $com= "$maria_exe_path/maria_chk$suffix -dvv $table ";
+ $com.= "| grep -v \"Creation time:\" | grep -v \"file length\" | grep -v \"LSNs:\" | grep -v \"UUID:\" ";
+ $com.= "> $tmp/maria_chk_message.good.txt 2>&1";
+ $res= my_exec($com);
+ print MY_LOG $res;
+ $checksum= my_exec("$maria_exe_path/maria_chk$suffix -dss $table");
+ move("$table.MAD", "$tmp/$table-good.MAD") ||
+ die "Can't move $table.MAD to $tmp/$table-good.MAD\n";
+ move("$table.MAI", "$tmp/$table-good.MAI") ||
+ die "Can't move $table.MAI to $tmp/$table-good.MAI\n";
+ unlink <maria_log.* maria_log_control>;
+ print MY_LOG "TEST WITH $prog_no_suffix $abort_run_args$test_undo[$j] (additional aborted work)\n";
+ $res= my_exec("$maria_exe_path/$prog $abort_run_args$test_undo[$j]");
+ print MY_LOG $res;
+ copy("$table.MAD", "$tmp/$table-before_undo.MAD") ||
+ die "Can't copy $table.MAD to $tmp/$table-before_undo.MAD\n";
+ copy("$table.MAI", "$tmp/$table-before_undo.MAI") ||
+ die "Can't copy $table.MAI to $tmp/$table-before_undo.MAI\n";
+
+ # The lines below seem unneeded, will be removed soon
+ # We have to copy and restore logs, as running maria_read_log will
+ # change the maria_control_file
+ # rm -f $tmp/maria_log.* $tmp/maria_log_control
+ # cp $maria_path/maria_log* $tmp
+
+ if ($test_undo[$j] != 3) {
+ apply_log($table, "shouldchangelog"); # should undo aborted work
+ } else {
+ # probably nothing to undo went to log or data file
+ apply_log($table, "dontknow");
+ }
+ copy("$table.MAD", "$tmp/$table-after_undo.MAD") ||
+ die "Can't copy $table.MAD to $tmp/$table-after_undo.MAD\n";
+ copy("$table.MAI", "$tmp/$table-after_undo.MAI") ||
+ die "Can't copy $table.MAI to $tmp/$table-after_undo.MAI\n";
+
+ # It is impossible to do a "cmp" between .good and .after_undo,
+ # because the UNDO phase generated log
+ # records whose LSN tagged pages. Another reason is that rolling back
+ # INSERT only marks the rows free, does not empty them (optimization), so
+ # traces of the INSERT+rollback remain.
+
+ check_table_is_same($table, $checksum);
+ print MY_LOG "testing idempotency\n";
+ apply_log($table, "shouldnotchangelog");
+ check_table_is_same($table, $checksum);
+ $res= physical_cmp($table, "$tmp/$table-after_undo");
+ print MY_LOG $res;
+ print MY_LOG "testing applying of CLRs to recreate table\n";
+ unlink <$table.MA?>;
+ # cp $tmp/maria_log* $maria_path #unneeded
+ apply_log($table, "shouldnotchangelog");
+ check_table_is_same($table, $checksum);
+ $res= physical_cmp($table, "$tmp/$table-after_undo");
+ print MY_LOG $res;
+ }
+ unlink <$table.* $tmp/$table* $tmp/maria_chk_*.txt $tmp/maria_read_log_$table.txt>;
+ }
+ }
+ }
+
+ if ($? >> 8) {
+ print "Some test failed\n";
+ exit(1);
+ }
+
+ close(MY_LOG);
+ # also note that maria_chk -dvv shows differences for ma_test2 in UNDO phase,
+ # this is normal: removing records does not shrink the data/key file,
+ # does not put back the "analyzed,optimized keys"(etc) index state.
+ `diff -b $maria_path/unittest/ma_test_recovery.expected $tmp/ma_test_recovery.output`;
+ if ($? >> 8) {
+ print "UNEXPECTED OUTPUT OF TESTS, FAILED";
+ print " (zerofilled $zerofilled_tables tables)\n";
+ print "For more info, do diff -b $maria_path/unittest/ma_test_recovery.expected ";
+ print "$tmp/ma_test_recovery.output\n";
+ exit(1);
+ }
+ print "ALL RECOVERY TESTS OK (zerofilled $zerofilled_tables tables)\n";
+}
+
+####
+#### check_table_is_same
+####
+
+sub check_table_is_same
+{
+ my ($table, $checksum)= @_;
+ my ($com, $checksum2, $res);
+
+ # Computes checksum of new table and compares to checksum of old table
+ # Shows any difference in table's state (info from the index's header)
+ # Data/key file length is random in ma_test2 (as it uses srand() which
+ # may differ between machines).
+
+ if ($opt_verbose)
+ {
+ print "checking if table $table has changed\n";
+ }
+
+ $com= "$maria_exe_path/maria_chk$suffix -dvv $table | grep -v \"Creation time:\" ";
+ $com.= "| grep -v \"file length\" | grep -v \"LSNs:\" | grep -v \"UUID:\" > $tmp/maria_chk_message.txt 2>&1";
+ $res= `$com`;
+ print MY_LOG $res;
+ $res= `$maria_exe_path/maria_chk$suffix -s -e --read-only $table`;
+ print MY_LOG $res;
+ $checksum2= `$maria_exe_path/maria_chk$suffix -dss $table`;
+ if ("$checksum" ne "$checksum2")
+ {
+ print MY_LOG "checksum differs for $table before and after recovery\n";
+ return 1;
+ }
+
+ $com= "diff $tmp/maria_chk_message.good.txt $tmp/maria_chk_message.txt ";
+ $com.= "> $tmp/maria_chk_diff.txt || true";
+ $res= `$com`;
+ print MY_LOG $res;
+
+ if (-s "$tmp/maria_chk_diff.txt")
+ {
+ print MY_LOG "Differences in maria_chk -dvv, recovery not yet perfect !\n";
+ print MY_LOG "========DIFF START=======\n";
+ open(MY_FILE, "<$tmp/maria_chk_diff.txt") || die "Can't open file maria_chk_diff.txt\n";
+ while (<MY_FILE>)
+ {
+ print MY_LOG $_;
+ }
+ close(MY_FILE);
+ print MY_LOG "========DIFF END=======\n";
+ }
+}
+
+####
+#### apply_log
+####
+
+sub apply_log
+{
+ my ($table, $shouldchangelog)= @_;
+ my ($log_md5, $log_md5_2);
+
+ # applies log, can verify if applying did write to log or not
+
+ if ("$shouldchangelog" ne "shouldnotchangelog" &&
+ "$shouldchangelog" ne "shouldchangelog" &&
+ "$shouldchangelog" ne "dontknow" )
+ {
+ print MY_LOG "bad argument '$shouldchangelog'\n";
+ return 1;
+ }
+ foreach (<maria_log.*>)
+ {
+ $log_md5.= md5_conv($_);
+ }
+ print MY_LOG "applying log\n";
+ my_exec("$maria_exe_path/maria_read_log$suffix -a > $tmp/maria_read_log_$table.txt");
+ foreach (<maria_log.*>)
+ {
+ $log_md5_2.= md5_conv($_);
+ }
+ if ("$log_md5" ne "$log_md5_2" )
+ {
+ if ("$shouldchangelog" eq "shouldnotchangelog")
+ {
+ print MY_LOG "maria_read_log should not have modified the log\n";
+ return 1;
+ }
+ }
+ elsif ("$shouldchangelog" eq "shouldchangelog")
+ {
+ print MY_LOG "maria_read_log should have modified the log\n";
+ return 1;
+ }
+}
+
+####
+#### md5_conv
+####
+
+sub md5_conv
+{
+ my ($file)= @_;
+
+ open(FILE, $file) or die "Can't open '$file': $!\n";
+ binmode(FILE);
+ my $md5= Digest::MD5->new;
+ $md5->addfile(FILE);
+ close (FILE);
+ return $md5->hexdigest . "\n";
+}
+
+####
+#### physical_cmp: compares two tables (MAI and MAD) physically;
+#### uses zerofill-keep-lsn to reduce irrelevant differences.
+####
+
+sub physical_cmp
+{
+ my ($table1, $table2)= @_;
+ my ($zerofilled, $ret_text)= (0, "");
+ #return `cmp $table1.MAD $table2.MAD`.`cmp $table1.MAI $table2.MAI`;
+ foreach my $file_suffix ("MAD", "MAI")
+ {
+ my $file1= "$table1.$file_suffix";
+ my $file2= "$table2.$file_suffix";
+ my $res= File::Compare::compare($file1, $file2);
+ die() if ($res == -1);
+ if ($res == 1 # they differ
+ and !$zerofilled)
+ {
+ # let's try with --zerofill-keep-lsn
+ $zerofilled= 1; # but no need to do it twice
+ $zerofilled_tables= $zerofilled_tables + 1;
+ my $table_no= 1;
+ foreach my $table ($table1, $table2)
+ {
+ # save original tables to restore them later
+ copy("$table.MAD", "$tmp/before_zerofill$table_no.MAD") || die();
+ copy("$table.MAI", "$tmp/before_zerofill$table_no.MAI") || die();
+ $com= "$maria_exe_path/maria_chk$suffix -s --zerofill-keep-lsn $table";
+ $res= `$com`;
+ print MY_LOG $res;
+ $table_no= $table_no + 1;
+ }
+ $res= File::Compare::compare($file1, $file2);
+ die() if ($res == -1);
+ }
+ $ret_text.= "$file1 and $file2 differ\n" if ($res != 0);
+ }
+ if ($zerofilled)
+ {
+ my $table_no= 1;
+ foreach my $table ($table1, $table2)
+ {
+ move("$tmp/before_zerofill$table_no.MAD", "$table.MAD") || die();
+ move("$tmp/before_zerofill$table_no.MAI", "$table.MAI") || die();
+ $table_no= $table_no + 1;
+ }
+ }
+ return $ret_text;
+}
+
+
+sub my_exec
+{
+ my($command)= @_;
+ my $res;
+ if ($opt_verbose)
+ {
+ print "$command\n";
+ }
+ $res= `$command`;
+ if ($? != 0 && $opt_abort_on_error)
+ {
+ exit(1);
+ }
+ return $res;
+}
+
+
+####
+#### usage
+####
+
+sub usage
+{
+ print <<EOF;
+$my_progname version $VER
+
+Description:
+
+Run various maria recovery tests and print the results
+
+Options
+--help Show this help and exit.
+
+--abort-on-error Abort at once in case of error.
+--verbose Show commands while there are executing.
+--version Show version number and exit.
+
+EOF
+ exit(0);
+}
diff --git a/storage/maria/unittest/sequence_storage.c b/storage/maria/unittest/sequence_storage.c
new file mode 100644
index 00000000000..d5db20d31ca
--- /dev/null
+++ b/storage/maria/unittest/sequence_storage.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "../maria_def.h"
+#include "sequence_storage.h"
+
+
+/**
+ @brief Initializes the sequence from the sequence file.
+
+ @param seq Reference on the sequence storage.
+ @param file Path to the file where to write the sequence
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool seq_storage_reader_init(SEQ_STORAGE *seq, const char *file)
+{
+ FILE *fd;
+ seq->pos= 0;
+ if ((fd= my_fopen(file, O_RDONLY, MYF(MY_WME))) == NULL)
+ return 1;
+ if (my_init_dynamic_array(&seq->seq, sizeof(ulong), 10, 10))
+ return 1;
+
+ for(;;)
+ {
+ ulong num;
+ char line[22];
+ if (fgets(line, sizeof(line), fd) == NULL)
+ break;
+ num= atol(line);
+ if (insert_dynamic(&seq->seq, (uchar*) &num))
+ return 1;
+ }
+ fclose(fd);
+ return 0;
+}
+
+
+/**
+ @brief Gets next number from the sequence storage
+
+ @param seq Reference on the sequence storage.
+
+ @return Next number from the sequence.
+*/
+
+ulong seq_storage_next(SEQ_STORAGE *seq)
+{
+ DBUG_ASSERT(seq->seq.elements > 0);
+ DBUG_ASSERT(seq->pos < seq->seq.elements);
+ return (*(dynamic_element(&seq->seq, seq->pos++, ulong *)));
+}
+
+
+/**
+ @brief Frees resources allocated for the storage
+
+ @param seq Reference on the sequence storage.
+*/
+
+void seq_storage_destroy(SEQ_STORAGE *seq)
+{
+ delete_dynamic(&seq->seq);
+}
+
+
+/**
+ @brief Starts the sequence from begining
+
+ @param seq Reference on the sequence storage.
+*/
+
+void seq_storage_rewind(SEQ_STORAGE *seq)
+{
+ seq->pos= 0;
+}
+
+/**
+ @brief Writes a number to the sequence file.
+
+ @param file Path to the file where to write the sequence
+ @pagem num Number to be written
+
+ @retval 0 OK
+ @retval 1 Error
+*/
+
+my_bool seq_storage_write(const char *file, ulong num)
+{
+ FILE *fd;
+ return ((fd= my_fopen(file, O_CREAT | O_APPEND | O_WRONLY, MYF(MY_WME))) ==
+ NULL ||
+ fprintf(fd, "%lu\n", num) < 0 ||
+ fclose(fd) != 0);
+}
diff --git a/storage/maria/unittest/sequence_storage.h b/storage/maria/unittest/sequence_storage.h
new file mode 100644
index 00000000000..78ce15a6253
--- /dev/null
+++ b/storage/maria/unittest/sequence_storage.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+typedef struct st_seq_storage
+{
+ uint pos;
+ DYNAMIC_ARRAY seq;
+} SEQ_STORAGE;
+
+extern my_bool seq_storage_reader_init(SEQ_STORAGE *seq, const char *file);
+extern ulong seq_storage_next(SEQ_STORAGE *seq);
+extern void seq_storage_destroy(SEQ_STORAGE *seq);
+extern void seq_storage_rewind(SEQ_STORAGE *seq);
+extern my_bool seq_storage_write(const char *file, ulong num);
+
diff --git a/storage/maria/unittest/test_file.c b/storage/maria/unittest/test_file.c
new file mode 100644
index 00000000000..5f7e3939592
--- /dev/null
+++ b/storage/maria/unittest/test_file.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <tap.h>
+#include <my_sys.h>
+#include <my_dir.h>
+#include "test_file.h"
+
+
+/*
+ Check that file contance correspond to descriptor
+
+ SYNOPSIS
+ test_file()
+ file File to test
+ file_name Path (and name) of file which is tested
+ size size of file
+ buff_size size of buffer which is enought to check the file
+ desc file descriptor to check with
+
+ RETURN
+ 1 file if OK
+ 0 error
+*/
+
+int test_file(PAGECACHE_FILE file, char *file_name,
+ off_t size, size_t buff_size, struct file_desc *desc)
+{
+ unsigned char *buffr= my_malloc(buff_size, MYF(0));
+ off_t pos= 0;
+ size_t byte;
+ int step= 0;
+ int res= 1; /* ok */
+
+#ifdef __WIN__
+ /*
+ On Windows, the info returned by stat(), specifically file length
+ is not necessarily current, because this is the behavior of
+ underlying FindFirstFile() function.
+ */
+ WIN32_FILE_ATTRIBUTE_DATA file_attr;
+ LARGE_INTEGER li;
+ if(GetFileAttributesEx(file_name, GetFileExInfoStandard, &file_attr) == 0)
+ {
+ diag("Can't GetFileAttributesEx %s (errno: %d)\n", file_name,
+ GetLastError());
+ res= 0;
+ goto err;
+ }
+ li.HighPart= file_attr.nFileSizeHigh;
+ li.LowPart= file_attr.nFileSizeLow;
+ if(li.QuadPart != size)
+ {
+ diag("file %s size is %llu (should be %llu)\n",
+ file_name, (ulonglong)size, (ulonglong)li.QuadPart);
+ res= 0; /* failed */
+ /* continue to get more information */
+ }
+#else
+ MY_STAT stat_buff, *stat;
+ if ((stat= my_stat(file_name, &stat_buff, MYF(0))) == NULL)
+ {
+ diag("Can't stat() %s (errno: %d)\n", file_name, errno);
+ res= 0;
+ goto err;
+ }
+ if (stat->st_size != size)
+ {
+ diag("file %s size is %lu (should be %lu)\n",
+ file_name, (ulong) stat->st_size, (ulong) size);
+ res= 0; /* failed */
+ /* continue to get more information */
+ }
+#endif
+
+ /* check content */
+ my_seek(file.file, 0, SEEK_SET, MYF(MY_WME));
+ while (desc[step].length != 0)
+ {
+ if (my_read(file.file, buffr, desc[step].length, MYF(0)) !=
+ desc[step].length)
+ {
+ diag("Can't read %u bytes from %s (file: %d errno: %d)\n",
+ (uint)desc[step].length, file_name, file.file, errno);
+ res= 0;
+ goto err;
+ }
+ for (byte= 0; byte < desc[step].length; byte++)
+ {
+ if (buffr[byte] != desc[step].content)
+ {
+ diag("content of %s mismatch 0x%x in position %lu instead of 0x%x\n",
+ file_name, (uint) buffr[byte], (ulong) (pos + byte),
+ desc[step].content);
+ res= 0;
+ goto err;
+ }
+ }
+ pos+= desc[step].length;
+ step++;
+ }
+
+err:
+ my_free(buffr, 0);
+ return res;
+}
diff --git a/storage/maria/unittest/test_file.h b/storage/maria/unittest/test_file.h
new file mode 100644
index 00000000000..0a1ccf4ab54
--- /dev/null
+++ b/storage/maria/unittest/test_file.h
@@ -0,0 +1,29 @@
+/* Copyright (C) 2006-2008 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <m_string.h>
+#include "../ma_pagecache.h"
+
+/*
+ File content descriptor
+*/
+struct file_desc
+{
+ unsigned int length;
+ unsigned char content;
+};
+
+int test_file(PAGECACHE_FILE file, char *file_name,
+ off_t size, size_t buff_size, struct file_desc *desc);
diff --git a/storage/maria/unittest/trnman-t.c b/storage/maria/unittest/trnman-t.c
new file mode 100644
index 00000000000..43cf982a7f2
--- /dev/null
+++ b/storage/maria/unittest/trnman-t.c
@@ -0,0 +1,175 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <tap.h>
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_atomic.h>
+#include <lf.h>
+#include <m_string.h>
+#include "../trnman.h"
+
+pthread_mutex_t rt_mutex;
+pthread_attr_t attr;
+size_t stacksize= 0;
+#define STACK_SIZE (((int)stacksize-2048)*STACK_DIRECTION)
+
+int rt_num_threads;
+int litmus;
+
+/*
+ create and end (commit or rollback) transactions randomly
+*/
+#define MAX_ITER 100
+pthread_handler_t test_trnman(void *arg)
+{
+ uint x, y, i, n;
+ TRN *trn[MAX_ITER];
+ int m= (*(int *)arg);
+
+ if (my_thread_init())
+ BAIL_OUT("my_thread_init failed!");
+
+ for (x= ((int)(intptr)(&m)); m > 0; )
+ {
+ y= x= (x*LL(3628273133) + LL(1500450271)) % LL(9576890767); /* three prime numbers */
+ m-= n= x % MAX_ITER;
+ for (i= 0; i < n; i++)
+ {
+ trn[i]= trnman_new_trn(0);
+ if (!trn[i])
+ {
+ diag("trnman_new_trn() failed");
+ litmus++;
+ }
+ }
+ for (i= 0; i < n; i++)
+ {
+ y= (y*19 + 7) % 31;
+ trnman_end_trn(trn[i], y & 1);
+ }
+ }
+ pthread_mutex_lock(&rt_mutex);
+ rt_num_threads--;
+ pthread_mutex_unlock(&rt_mutex);
+
+ my_thread_end();
+
+ return 0;
+}
+#undef MAX_ITER
+
+void run_test(const char *test, pthread_handler handler, int n, int m)
+{
+ pthread_t *threads;
+ ulonglong now= my_getsystime();
+ int i;
+
+ litmus= 0;
+
+ threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
+ if (!threads)
+ {
+ diag("Out of memory");
+ abort();
+ }
+
+ diag("Testing %s with %d threads, %d iterations... ", test, n, m);
+ rt_num_threads= n;
+ for (i= 0; i < n ; i++)
+ if (pthread_create(threads+i, &attr, handler, &m))
+ {
+ diag("Could not create thread");
+ abort();
+ }
+ for (i= 0 ; i < n ; i++)
+ pthread_join(threads[i], 0);
+ now= my_getsystime()-now;
+ ok(litmus == 0, "Tested %s in %g secs (%d)", test, ((double)now)/1e7, litmus);
+ my_free((void*)threads, MYF(0));
+}
+
+#define ok_read_from(T1, T2, RES) \
+ i= trnman_can_read_from(trn[T1], trid[T2]); \
+ ok(i == RES, "trn" #T1 " %s read from trn" #T2, i ? "can" : "cannot")
+#define start_transaction(T) \
+ trn[T]= trnman_new_trn(0); \
+ trid[T]= trn[T]->trid
+#define commit(T) trnman_commit_trn(trn[T])
+#define abort(T) trnman_abort_trn(trn[T])
+
+#define Ntrns 4
+void test_trnman_read_from()
+{
+ TRN *trn[Ntrns];
+ TrID trid[Ntrns];
+ int i;
+
+ start_transaction(0); /* start trn1 */
+ start_transaction(1); /* start trn2 */
+ ok_read_from(1, 0, 0);
+ commit(0); /* commit trn1 */
+ start_transaction(2); /* start trn4 */
+ abort(2); /* abort trn4 */
+ start_transaction(3); /* start trn5 */
+ ok_read_from(3, 0, 1);
+ ok_read_from(3, 1, 0);
+ ok_read_from(3, 2, 0);
+ ok_read_from(3, 3, 1);
+ commit(1); /* commit trn2 */
+ ok_read_from(3, 1, 0);
+ commit(3); /* commit trn5 */
+
+}
+
+int main(int argc __attribute__((unused)), char **argv)
+{
+ MY_INIT(argv[0]);
+
+ plan(7);
+
+ if (my_atomic_initialize())
+ return exit_status();
+
+ pthread_mutex_init(&rt_mutex, 0);
+ pthread_attr_init(&attr);
+#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
+ pthread_attr_getstacksize(&attr, &stacksize);
+ if (stacksize == 0)
+#endif
+ stacksize= PTHREAD_STACK_MIN;
+
+#define CYCLES 10000
+#define THREADS 10
+
+ trnman_init(0);
+
+ test_trnman_read_from();
+ run_test("trnman", test_trnman, THREADS, CYCLES);
+
+ diag("mallocs: %d", trnman_allocated_transactions);
+ {
+ ulonglong now= my_getsystime();
+ trnman_destroy();
+ now= my_getsystime()-now;
+ diag("trnman_destroy: %g", ((double)now)/1e7);
+ }
+
+ pthread_mutex_destroy(&rt_mutex);
+ my_end(0);
+ return exit_status();
+}
+
diff --git a/storage/myisam/CMakeLists.txt b/storage/myisam/CMakeLists.txt
index 4436c8fa7c4..f4449f445b2 100755
--- a/storage/myisam/CMakeLists.txt
+++ b/storage/myisam/CMakeLists.txt
@@ -24,6 +24,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
SET(MYISAM_SOURCES ft_boolean_search.c ft_nlq_search.c ft_parser.c ft_static.c ft_stem.c
ha_myisam.cc
+ ft_myisam.c
ft_stopwords.c ft_update.c mi_cache.c mi_changed.c mi_check.c
mi_checksum.c mi_close.c mi_create.c mi_dbug.c mi_delete.c
mi_delete_all.c mi_delete_table.c mi_dynrec.c mi_extra.c mi_info.c
@@ -51,6 +52,21 @@ IF(NOT SOURCE_SUBLIBS)
ADD_EXECUTABLE(myisampack myisampack.c)
TARGET_LINK_LIBRARIES(myisampack myisam mysys debug dbug strings zlib wsock32)
+ ADD_EXECUTABLE(mi_test1 mi_test1.c)
+ TARGET_LINK_LIBRARIES(mi_test1 myisam mysys debug dbug strings zlib wsock32)
+
+ ADD_EXECUTABLE(mi_test2 mi_test2.c)
+ TARGET_LINK_LIBRARIES(mi_test2 myisam mysys debug dbug strings zlib wsock32)
+
+ ADD_EXECUTABLE(mi_test3 mi_test3.c)
+ TARGET_LINK_LIBRARIES(mi_test3 myisam mysys debug dbug strings zlib wsock32)
+
+ ADD_EXECUTABLE(sp_test sp_test.c)
+ TARGET_LINK_LIBRARIES(sp_test myisam mysys debug dbug strings zlib wsock32)
+
+ ADD_EXECUTABLE(rt_test rt_test.c)
+ TARGET_LINK_LIBRARIES(rt_test myisam mysys debug dbug strings zlib wsock32)
+
IF(EMBED_MANIFESTS)
MYSQL_EMBED_MANIFEST("myisam_ftdump" "asInvoker")
MYSQL_EMBED_MANIFEST("myisamchk" "asInvoker")
diff --git a/storage/myisam/Makefile.am b/storage/myisam/Makefile.am
index f50c312b8e4..4bd0b177daa 100644
--- a/storage/myisam/Makefile.am
+++ b/storage/myisam/Makefile.am
@@ -97,8 +97,8 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \
mi_delete_table.c mi_rename.c mi_check.c \
mi_keycache.c mi_preload.c \
ft_parser.c ft_stopwords.c ft_static.c \
- ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c \
- ha_myisam.cc \
+ ft_update.c ft_boolean_search.c ft_nlq_search.c \
+ sort.c ha_myisam.cc ft_myisam.c \
rt_index.c rt_key.c rt_mbr.c rt_split.c sp_key.c
CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all rt_test.MY? sp_test.MY?
diff --git a/storage/myisam/ft_boolean_search.c b/storage/myisam/ft_boolean_search.c
index 66097864622..274f91e2691 100644
--- a/storage/myisam/ft_boolean_search.c
+++ b/storage/myisam/ft_boolean_search.c
@@ -196,7 +196,7 @@ static int ftb_query_add_word(MYSQL_FTPARSER_PARAM *param,
case FT_TOKEN_WORD:
ftbw= (FTB_WORD *)alloc_root(&ftb_param->ftb->mem_root,
sizeof(FTB_WORD) +
- (info->trunc ? MI_MAX_KEY_BUFF :
+ (info->trunc ? HA_MAX_KEY_BUFF :
word_len * ftb_param->ftb->charset->mbmaxlen +
HA_FT_WLEN +
ftb_param->ftb->info->s->rec_reflength));
@@ -344,8 +344,8 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search)
MI_INFO *info=ftb->info;
uint off, extra=HA_FT_WLEN+info->s->base.rec_reflength;
uchar *lastkey_buf=ftbw->word+ftbw->off;
-
LINT_INIT(off);
+
if (ftbw->flags & FTB_FLAG_TRUNC)
lastkey_buf+=ftbw->len;
diff --git a/storage/myisam/ft_myisam.c b/storage/myisam/ft_myisam.c
new file mode 100644
index 00000000000..bef3fbfd5f5
--- /dev/null
+++ b/storage/myisam/ft_myisam.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Written by Sergei A. Golubchik, who has a shared copyright to this code */
+
+/*
+ This function is for interface functions between fulltext and myisam
+*/
+
+#include "ftdefs.h"
+
+FT_INFO *ft_init_search(uint flags, void *info, uint keynr,
+ uchar *query, uint query_len, CHARSET_INFO *cs,
+ uchar *record)
+{
+ FT_INFO *res;
+ if (flags & FT_BOOL)
+ res= ft_init_boolean_search((MI_INFO *)info, keynr, query, query_len,cs);
+ else
+ res= ft_init_nlq_search((MI_INFO *)info, keynr, query, query_len, flags,
+ record);
+ return res;
+}
diff --git a/storage/myisam/ft_static.c b/storage/myisam/ft_static.c
index 1b6c7458fd7..4a5ee18920f 100644
--- a/storage/myisam/ft_static.c
+++ b/storage/myisam/ft_static.c
@@ -54,20 +54,6 @@ const struct _ft_vft _ft_vft_boolean = {
ft_boolean_get_relevance, ft_boolean_reinit_search
};
-
-FT_INFO *ft_init_search(uint flags, void *info, uint keynr,
- uchar *query, uint query_len, CHARSET_INFO *cs,
- uchar *record)
-{
- FT_INFO *res;
- if (flags & FT_BOOL)
- res= ft_init_boolean_search((MI_INFO *)info, keynr, query, query_len,cs);
- else
- res= ft_init_nlq_search((MI_INFO *)info, keynr, query, query_len, flags,
- record);
- return res;
-}
-
const char *ft_stopword_file = 0;
const char *ft_precompiled_stopwords[] = {
diff --git a/storage/myisam/ft_stopwords.c b/storage/myisam/ft_stopwords.c
index 9838b15af34..8aefffbee1d 100644
--- a/storage/myisam/ft_stopwords.c
+++ b/storage/myisam/ft_stopwords.c
@@ -51,10 +51,11 @@ static int ft_add_stopword(const char *w)
int ft_init_stopwords()
{
+ DBUG_ENTER("ft_init_stopwords");
if (!stopwords3)
{
if (!(stopwords3=(TREE *)my_malloc(sizeof(TREE),MYF(0))))
- return -1;
+ DBUG_RETURN(-1);
init_tree(stopwords3,0,0,sizeof(FT_STOPWORD),(qsort_cmp2)&FT_STOPWORD_cmp,
0,
(ft_stopword_file ? (tree_element_free)&FT_STOPWORD_free : 0),
@@ -70,10 +71,10 @@ int ft_init_stopwords()
int error=-1;
if (!*ft_stopword_file)
- return 0;
+ DBUG_RETURN(0);
if ((fd=my_open(ft_stopword_file, O_RDONLY, MYF(MY_WME))) == -1)
- return -1;
+ DBUG_RETURN(-1);
len=(uint)my_seek(fd, 0L, MY_SEEK_END, MYF(0));
my_seek(fd, 0L, MY_SEEK_SET, MYF(0));
if (!(start=buffer=my_malloc(len+1, MYF(MY_WME))))
@@ -90,7 +91,7 @@ err1:
my_free(buffer, MYF(0));
err0:
my_close(fd, MYF(MY_WME));
- return error;
+ DBUG_RETURN(error);
}
else
{
@@ -100,13 +101,14 @@ err0:
for (;*sws;sws++)
{
if (ft_add_stopword(*sws))
- return -1;
+ DBUG_RETURN(-1);
}
ft_stopword_file="(built-in)"; /* for SHOW VARIABLES */
}
- return 0;
+ DBUG_RETURN(0);
}
+
int is_stopword(char *word, uint len)
{
FT_STOPWORD sw;
@@ -118,6 +120,8 @@ int is_stopword(char *word, uint len)
void ft_free_stopwords()
{
+ DBUG_ENTER("ft_free_stopwords");
+
if (stopwords3)
{
delete_tree(stopwords3); /* purecov: inspected */
@@ -125,4 +129,5 @@ void ft_free_stopwords()
stopwords3=0;
}
ft_stopword_file= 0;
+ DBUG_VOID_RETURN;
}
diff --git a/storage/myisam/fulltext.h b/storage/myisam/fulltext.h
index 856e93e034d..9aef2d0d002 100644
--- a/storage/myisam/fulltext.h
+++ b/storage/myisam/fulltext.h
@@ -20,18 +20,8 @@
#include "myisamdef.h"
#include "ft_global.h"
-#define HA_FT_WTYPE HA_KEYTYPE_FLOAT
-#define HA_FT_WLEN 4
-#define FT_SEGS 2
-
-#define ft_sintXkorr(A) mi_sint4korr(A)
-#define ft_intXstore(T,A) mi_int4store(T,A)
-
-extern const HA_KEYSEG ft_keysegs[FT_SEGS];
-
int _mi_ft_cmp(MI_INFO *, uint, const uchar *, const uchar *);
int _mi_ft_add(MI_INFO *, uint, uchar *, const uchar *, my_off_t);
int _mi_ft_del(MI_INFO *, uint, uchar *, const uchar *, my_off_t);
uint _mi_ft_convert_to_ft2(MI_INFO *, uint, uchar *);
-
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index b8d5a9af8d2..a6e6d4ea9cb 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -57,13 +57,13 @@ static handler *myisam_create_handler(handlerton *hton,
// collect errors printed by mi_check routines
-static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
+static void mi_check_print_msg(HA_CHECK *param, const char* msg_type,
const char *fmt, va_list args)
{
THD* thd = (THD*)param->thd;
Protocol *protocol= thd->protocol;
uint length, msg_length;
- char msgbuf[MI_MAX_MSG_BUF];
+ char msgbuf[HA_MAX_MSG_BUF];
char name[NAME_LEN*2+2];
msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
@@ -256,30 +256,31 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d",
(long) found, recpos, minpos, length));
if (recpos != minpos)
- { // Reserved space (Null bits?)
+ {
+ /* reserve space for null bits */
bzero((char*) recinfo_pos, sizeof(*recinfo_pos));
- recinfo_pos->type= (int) FIELD_NORMAL;
+ recinfo_pos->type= FIELD_NORMAL;
recinfo_pos++->length= (uint16) (minpos - recpos);
}
if (!found)
break;
if (found->flags & BLOB_FLAG)
- recinfo_pos->type= (int) FIELD_BLOB;
+ recinfo_pos->type= FIELD_BLOB;
else if (found->type() == MYSQL_TYPE_VARCHAR)
recinfo_pos->type= FIELD_VARCHAR;
else if (!(options & HA_OPTION_PACK_RECORD))
- recinfo_pos->type= (int) FIELD_NORMAL;
+ recinfo_pos->type= FIELD_NORMAL;
else if (found->zero_pack())
- recinfo_pos->type= (int) FIELD_SKIP_ZERO;
+ recinfo_pos->type= FIELD_SKIP_ZERO;
else
- recinfo_pos->type= (int) ((length <= 3 ||
- (found->flags & ZEROFILL_FLAG)) ?
- FIELD_NORMAL :
- found->type() == MYSQL_TYPE_STRING ||
- found->type() == MYSQL_TYPE_VAR_STRING ?
- FIELD_SKIP_ENDSPACE :
- FIELD_SKIP_PRESPACE);
+ recinfo_pos->type= ((length <= 3 ||
+ (found->flags & ZEROFILL_FLAG)) ?
+ FIELD_NORMAL :
+ found->type() == MYSQL_TYPE_STRING ||
+ found->type() == MYSQL_TYPE_VAR_STRING ?
+ FIELD_SKIP_ENDSPACE :
+ FIELD_SKIP_PRESPACE);
if (found->null_ptr)
{
recinfo_pos->null_bit= found->null_bit;
@@ -305,7 +306,7 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
Check for underlying table conformance
SYNOPSIS
- check_definition()
+ myisam_check_definition()
t1_keyinfo in First table key definition
t1_recinfo in First table record definition
t1_keys in Number of keys in first table
@@ -466,13 +467,13 @@ int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
extern "C" {
-volatile int *killed_ptr(MI_CHECK *param)
+volatile int *killed_ptr(HA_CHECK *param)
{
/* In theory Unsafe conversion, but should be ok for now */
return (int*) &(((THD *)(param->thd))->killed);
}
-void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
+void mi_check_print_error(HA_CHECK *param, const char *fmt,...)
{
param->error_printed|=1;
param->out_flag|= O_DATA_LOST;
@@ -482,7 +483,7 @@ void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
va_end(args);
}
-void mi_check_print_info(MI_CHECK *param, const char *fmt,...)
+void mi_check_print_info(HA_CHECK *param, const char *fmt,...)
{
va_list args;
va_start(args, fmt);
@@ -490,7 +491,7 @@ void mi_check_print_info(MI_CHECK *param, const char *fmt,...)
va_end(args);
}
-void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
+void mi_check_print_warning(HA_CHECK *param, const char *fmt,...)
{
param->warning_printed=1;
param->out_flag|= O_DATA_LOST;
@@ -689,7 +690,19 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
if (!table->s->db_record_offset)
int_table_flags|=HA_REC_NOT_IN_SEQ;
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
- int_table_flags|=HA_HAS_CHECKSUM;
+ {
+ /*
+ Set which type of automatic checksum we have
+ The old checksum and new checksum are identical if there is no
+ null fields.
+ Files with new checksum has the HA_OPTION_NULL_FIELDS bit set.
+ */
+ if ((file->s->options & HA_OPTION_NULL_FIELDS) ||
+ !file->s->has_null_fields)
+ int_table_flags|= HA_HAS_NEW_CHECKSUM;
+ if (!(file->s->options & HA_OPTION_NULL_FIELDS))
+ int_table_flags|= HA_HAS_OLD_CHECKSUM;
+ }
for (i= 0; i < table->s->keys; i++)
{
@@ -745,7 +758,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
{
if (!file) return HA_ADMIN_INTERNAL_ERROR;
int error;
- MI_CHECK param;
+ HA_CHECK param;
MYISAM_SHARE* share = file->s;
const char *old_proc_info=thd->proc_info;
@@ -756,7 +769,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
param.db_name= table->s->db.str;
param.table_name= table->alias;
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
- param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
+ param.stats_method= (enum_handler_stats_method)thd->variables.myisam_stats_method;
if (!(table->db_stat & HA_READ_ONLY))
param.testflag|= T_STATISTICS;
@@ -785,13 +798,13 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
mi_is_crashed(file))
{
- uint old_testflag=param.testflag;
+ ulonglong old_testflag= param.testflag;
param.testflag|=T_MEDIUM;
if (!(error= init_io_cache(&param.read_cache, file->dfile,
my_default_record_cache_size, READ_CACHE,
share->pack.header_length, 1, MYF(MY_WME))))
{
- error= chk_data_link(&param, file, param.testflag & T_EXTEND);
+ error= chk_data_link(&param, file, test(param.testflag & T_EXTEND));
end_io_cache(&(param.read_cache));
}
param.testflag= old_testflag;
@@ -837,7 +850,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
{
int error=0;
- MI_CHECK param;
+ HA_CHECK param;
MYISAM_SHARE* share = file->s;
myisamchk_init(&param);
@@ -848,7 +861,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
T_DONT_CHECK_CHECKSUM);
param.using_global_keycache = 1;
- param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
+ param.stats_method= (enum_handler_stats_method)thd->variables.myisam_stats_method;
if (!(share->state.changed & STATE_NOT_ANALYZED))
return HA_ADMIN_ALREADY_DONE;
@@ -897,7 +910,7 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
err:
{
- MI_CHECK param;
+ HA_CHECK param;
myisamchk_init(&param);
param.thd= thd;
param.op_name= "restore";
@@ -960,7 +973,7 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
err:
{
- MI_CHECK param;
+ HA_CHECK param;
myisamchk_init(&param);
param.thd= thd;
param.op_name= "backup";
@@ -976,7 +989,7 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
{
int error;
- MI_CHECK param;
+ HA_CHECK param;
ha_rows start_records;
if (!file) return HA_ADMIN_INTERNAL_ERROR;
@@ -987,7 +1000,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
- param.sort_buffer_length= check_opt->sort_buffer_size;
+ param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
start_records=file->state->records;
while ((error=repair(thd,param,0)) && param.retry_repair)
{
@@ -995,7 +1008,9 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
if (test_all_bits(param.testflag,
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
{
- param.testflag&= ~T_RETRY_WITHOUT_QUICK;
+ param.testflag&= ~(T_RETRY_WITHOUT_QUICK | T_QUICK);
+ /* Ensure we don't loose any rows when retrying without quick */
+ param.testflag|= T_SAFE_REPAIR;
sql_print_information("Retrying repair of: '%s' without quick",
table->s->path.str);
continue;
@@ -1026,14 +1041,14 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
{
int error;
if (!file) return HA_ADMIN_INTERNAL_ERROR;
- MI_CHECK param;
+ HA_CHECK param;
myisamchk_init(&param);
param.thd = thd;
param.op_name= "optimize";
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
- param.sort_buffer_length= check_opt->sort_buffer_size;
+ param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
if ((error= repair(thd,param,1)) && param.retry_repair)
{
sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
@@ -1045,10 +1060,10 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
}
-int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
+int ha_myisam::repair(THD *thd, HA_CHECK &param, bool do_optimize)
{
int error=0;
- uint local_testflag=param.testflag;
+ ulonglong local_testflag= param.testflag;
bool optimize_done= !do_optimize, statistics_done=0;
const char *old_proc_info=thd->proc_info;
char fixed_name[FN_REFLEN];
@@ -1097,7 +1112,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
mi_get_mask_all_keys_active(share->base.keys) :
share->state.key_map);
- uint testflag=param.testflag;
+ ulonglong testflag= param.testflag;
if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
(local_testflag & T_REP_BY_SORT))
{
@@ -1111,7 +1126,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
thd_proc_info(thd, buf);
error = mi_repair_parallel(&param, file, fixed_name,
- param.testflag & T_QUICK);
+ test(param.testflag & T_QUICK));
thd_proc_info(thd, "Repair done"); // to reset proc_info, as
// it was pointing to local buffer
}
@@ -1119,7 +1134,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
{
thd_proc_info(thd, "Repair by sorting");
error = mi_repair_by_sort(&param, file, fixed_name,
- param.testflag & T_QUICK);
+ test(param.testflag & T_QUICK));
}
}
else
@@ -1127,9 +1142,9 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
thd_proc_info(thd, "Repair with keycache");
param.testflag &= ~T_REP_BY_SORT;
error= mi_repair(&param, file, fixed_name,
- param.testflag & T_QUICK);
+ test(param.testflag & T_QUICK));
}
- param.testflag=testflag;
+ param.testflag= testflag | (param.testflag & T_RETRY_WITHOUT_QUICK);
optimize_done=1;
}
if (!error)
@@ -1233,7 +1248,7 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
if (error != HA_ADMIN_OK)
{
/* Send error to user */
- MI_CHECK param;
+ HA_CHECK param;
myisamchk_init(&param);
param.thd= thd;
param.op_name= "assign_to_keycache";
@@ -1297,7 +1312,7 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
err:
{
- MI_CHECK param;
+ HA_CHECK param;
myisamchk_init(&param);
param.thd= thd;
param.op_name= "preload_keys";
@@ -1404,7 +1419,7 @@ int ha_myisam::enable_indexes(uint mode)
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
{
THD *thd=current_thd;
- MI_CHECK param;
+ HA_CHECK param;
const char *save_proc_info=thd->proc_info;
thd_proc_info(thd, "Creating index");
myisamchk_init(&param);
@@ -1413,7 +1428,8 @@ int ha_myisam::enable_indexes(uint mode)
T_CREATE_MISSING_KEYS);
param.myf_rw&= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
- param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
+ param.stats_method=
+ (enum_handler_stats_method)thd->variables.myisam_stats_method;
param.tmpdir=&mysql_tmpdir_list;
if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
{
@@ -1528,12 +1544,12 @@ void ha_myisam::start_bulk_insert(ha_rows rows)
!= 0 Error
*/
-int ha_myisam::end_bulk_insert()
+int ha_myisam::end_bulk_insert(bool abort)
{
mi_end_bulk_insert(file);
int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0);
- return err ? err : can_enable_indexes ?
- enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0;
+ return (err || abort ? err : can_enable_indexes ?
+ enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0);
}
@@ -1698,9 +1714,15 @@ int ha_myisam::rnd_next(uchar *buf)
return error;
}
-int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos)
+int ha_myisam::remember_rnd_pos()
+{
+ position((uchar*) 0);
+ return 0;
+}
+
+int ha_myisam::restart_rnd_next(uchar *buf)
{
- return rnd_pos(buf,pos);
+ return rnd_pos(buf, ref);
}
int ha_myisam::rnd_pos(uchar *buf, uchar *pos)
@@ -1917,7 +1939,7 @@ void ha_myisam::get_auto_increment(ulonglong offset, ulonglong increment,
{
ulonglong nr;
int error;
- uchar key[MI_MAX_KEY_LENGTH];
+ uchar key[HA_MAX_KEY_LENGTH];
if (!table->s->next_number_key_offset)
{ // Autoincrement at key-start
@@ -2032,6 +2054,27 @@ bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
return COMPATIBLE_DATA_YES;
}
+
+/**
+ Check if a table is incompatible with the current version.
+
+ The cases are:
+ - Table has checksum, varchars and are not of dynamic record type
+*/
+
+int ha_myisam::check_for_upgrade(HA_CHECK_OPT *check_opt)
+{
+ if (!(file->s->options & HA_OPTION_NULL_FIELDS) &&
+ !(file->s->options & HA_OPTION_PACK_RECORD) &&
+ file->s->has_varchar_fields)
+ {
+ /* We need alter there to get the HA_OPTION_NULL_FIELDS flag to be set */
+ return HA_ADMIN_NEEDS_ALTER;
+ }
+ return HA_ADMIN_OK;
+}
+
+
extern int mi_panic(enum ha_panic_function flag);
int myisam_panic(handlerton *hton, ha_panic_function flag)
{
diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h
index ca44ae9ad87..62792a10a20 100644
--- a/storage/myisam/ha_myisam.h
+++ b/storage/myisam/ha_myisam.h
@@ -21,6 +21,7 @@
/* class for the the myisam handler */
#include <myisam.h>
+#include <myisamchk.h>
#include <ft_global.h>
#define HA_RECOVER_NONE 0 /* No automatic recover */
@@ -39,7 +40,7 @@ class ha_myisam: public handler
ulonglong int_table_flags;
char *data_file_name, *index_file_name;
bool can_enable_indexes;
- int repair(THD *thd, MI_CHECK &param, bool optimize);
+ int repair(THD *thd, HA_CHECK &param, bool optimize);
public:
ha_myisam(handlerton *hton, TABLE_SHARE *table_arg);
@@ -56,8 +57,8 @@ class ha_myisam: public handler
HA_READ_ORDER | HA_KEYREAD_ONLY);
}
uint max_supported_keys() const { return MI_MAX_KEY; }
- uint max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
- uint max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
+ uint max_supported_key_length() const { return HA_MAX_KEY_LENGTH; }
+ uint max_supported_key_part_length() const { return HA_MAX_KEY_LENGTH; }
uint checksum() const;
int open(const char *name, int mode, uint test_if_locked);
@@ -93,7 +94,8 @@ class ha_myisam: public handler
int rnd_init(bool scan);
int rnd_next(uchar *buf);
int rnd_pos(uchar * buf, uchar *pos);
- int restart_rnd_next(uchar *buf, uchar *pos);
+ int remember_rnd_pos();
+ int restart_rnd_next(uchar *buf);
void position(const uchar *record);
int info(uint);
int extra(enum ha_extra_function operation);
@@ -105,7 +107,7 @@ class ha_myisam: public handler
int enable_indexes(uint mode);
int indexes_are_disabled(void);
void start_bulk_insert(ha_rows rows);
- int end_bulk_insert();
+ int end_bulk_insert(bool abort);
ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
void update_create_info(HA_CREATE_INFO *create_info);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
@@ -117,6 +119,7 @@ class ha_myisam: public handler
ulonglong *nb_reserved_values);
int rename_table(const char * from, const char * to);
int delete_table(const char *name);
+ int check_for_upgrade(HA_CHECK_OPT *check_opt);
int check(THD* thd, HA_CHECK_OPT* check_opt);
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int repair(THD* thd, HA_CHECK_OPT* check_opt);
diff --git a/storage/myisam/mi_cache.c b/storage/myisam/mi_cache.c
index d6dcc431a8d..1ccf038a570 100644
--- a/storage/myisam/mi_cache.c
+++ b/storage/myisam/mi_cache.c
@@ -97,8 +97,8 @@ int _mi_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos, uint length,
DBUG_PRINT("error",
("Error %d reading next-multi-part block (Got %d bytes)",
my_errno, (int) read_length));
- if (!my_errno || my_errno == -1)
- my_errno=HA_ERR_WRONG_IN_RECORD;
+ if (!my_errno || my_errno == -1 || my_errno == HA_ERR_FILE_TOO_SHORT)
+ my_errno= HA_ERR_WRONG_IN_RECORD;
DBUG_RETURN(1);
}
bzero(buff+read_length,MI_BLOCK_INFO_HEADER_LENGTH - in_buff_length -
diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c
index bdca1a1f0b8..a61b71150ac 100644
--- a/storage/myisam/mi_check.c
+++ b/storage/myisam/mi_check.c
@@ -59,14 +59,14 @@
/* Functions defined in this file */
-static int check_k_link(MI_CHECK *param, MI_INFO *info,uint nr);
-static int chk_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
+static int check_k_link(HA_CHECK *param, MI_INFO *info,uint nr);
+static int chk_index(HA_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
my_off_t page, uchar *buff, ha_rows *keys,
ha_checksum *key_checksum, uint level);
static uint isam_key_length(MI_INFO *info,MI_KEYDEF *keyinfo);
static ha_checksum calc_checksum(ha_rows count);
static int writekeys(MI_SORT_PARAM *sort_param);
-static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
+static int sort_one_index(HA_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo,
my_off_t pagepos, File new_file);
static int sort_key_read(MI_SORT_PARAM *sort_param,void *key);
static int sort_ft_key_read(MI_SORT_PARAM *sort_param,void *key);
@@ -80,13 +80,13 @@ static int sort_insert_key(MI_SORT_PARAM *sort_param,
reg1 SORT_KEY_BLOCKS *key_block,
uchar *key, my_off_t prev_block);
static int sort_delete_record(MI_SORT_PARAM *sort_param);
-/*static int flush_pending_blocks(MI_CHECK *param);*/
-static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
+/*static int flush_pending_blocks(HA_CHECK *param);*/
+static SORT_KEY_BLOCKS *alloc_key_blocks(HA_CHECK *param, uint blocks,
uint buffer_length);
static ha_checksum mi_byte_checksum(const uchar *buf, uint length);
-static void set_data_file_type(SORT_INFO *sort_info, MYISAM_SHARE *share);
+static void set_data_file_type(MI_SORT_INFO *sort_info, MYISAM_SHARE *share);
-void myisamchk_init(MI_CHECK *param)
+void myisamchk_init(HA_CHECK *param)
{
bzero((uchar*) param,sizeof(*param));
param->opt_follow_links=1;
@@ -108,7 +108,7 @@ void myisamchk_init(MI_CHECK *param)
/* Check the status flags for the table */
-int chk_status(MI_CHECK *param, register MI_INFO *info)
+int chk_status(HA_CHECK *param, register MI_INFO *info)
{
MYISAM_SHARE *share=info->s;
@@ -136,7 +136,7 @@ int chk_status(MI_CHECK *param, register MI_INFO *info)
/* Check delete links */
-int chk_del(MI_CHECK *param, register MI_INFO *info, uint test_flag)
+int chk_del(HA_CHECK *param, register MI_INFO *info, ulonglong test_flag)
{
reg2 ha_rows i;
uint delete_link_length;
@@ -245,7 +245,7 @@ wrong:
/* Check delete links in index file */
-static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint nr)
+static int check_k_link(HA_CHECK *param, register MI_INFO *info, uint nr)
{
my_off_t next_link;
uint block_size=(nr+1)*MI_MIN_KEY_BLOCK_LENGTH;
@@ -323,7 +323,7 @@ static int check_k_link(MI_CHECK *param, register MI_INFO *info, uint nr)
/* Check sizes of files */
-int chk_size(MI_CHECK *param, register MI_INFO *info)
+int chk_size(HA_CHECK *param, register MI_INFO *info)
{
int error=0;
register my_off_t skr,size;
@@ -399,7 +399,7 @@ int chk_size(MI_CHECK *param, register MI_INFO *info)
/* Check keys */
-int chk_key(MI_CHECK *param, register MI_INFO *info)
+int chk_key(HA_CHECK *param, register MI_INFO *info)
{
uint key,found_keys=0,full_text_keys=0,result=0;
ha_rows keys;
@@ -584,7 +584,7 @@ do_stat:
} /* chk_key */
-static int chk_index_down(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
+static int chk_index_down(HA_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
my_off_t page, uchar *buff, ha_rows *keys,
ha_checksum *key_checksum, uint level)
{
@@ -731,7 +731,7 @@ int mi_collect_stats_nonulls_next(HA_KEYSEG *keyseg, ulonglong *notnull,
/* Check if index is ok */
-static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
+static int chk_index(HA_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
my_off_t page, uchar *buff, ha_rows *keys,
ha_checksum *key_checksum, uint level)
{
@@ -755,7 +755,10 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
}
if (keyinfo->flag & HA_NOSAME)
- comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* Not real duplicates */
+ {
+ /* Not real duplicates */
+ comp_flag= SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT;
+ }
else
comp_flag=SEARCH_SAME; /* Keys in positionorder */
nod_flag=mi_test_if_nod(buff);
@@ -800,9 +803,9 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
(flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length,
comp_flag, diff_pos)) >=0)
{
- DBUG_DUMP("old",(uchar*) info->lastkey, info->lastkey_length);
- DBUG_DUMP("new",(uchar*) key, key_length);
- DBUG_DUMP("new_in_page",(char*) old_keypos,(uint) (keypos-old_keypos));
+ DBUG_DUMP("old",info->lastkey, info->lastkey_length);
+ DBUG_DUMP("new",key, key_length);
+ DBUG_DUMP("new_in_page",old_keypos,(uint) (keypos-old_keypos));
if (comp_flag & SEARCH_FIND && flag == 0)
mi_check_print_error(param,"Found duplicated key at page %s",llstr(page,llbuff));
@@ -871,8 +874,8 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
DBUG_PRINT("test",("page: %s record: %s filelength: %s",
llstr(page,llbuff),llstr(record,llbuff2),
llstr(info->state->data_file_length,llbuff3)));
- DBUG_DUMP("key",(uchar*) key,key_length);
- DBUG_DUMP("new_in_page",(char*) old_keypos,(uint) (keypos-old_keypos));
+ DBUG_DUMP("key",key,key_length);
+ DBUG_DUMP("new_in_page",old_keypos,(uint) (keypos-old_keypos));
goto err;
}
param->record_checksum+=(ha_checksum) record;
@@ -934,7 +937,7 @@ static uint isam_key_length(MI_INFO *info, register MI_KEYDEF *keyinfo)
/* Check that record-link is ok */
-int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
+int chk_data_link(HA_CHECK *param, MI_INFO *info, my_bool extend)
{
int error,got_error,flag;
uint key,left_length,b_type,field;
@@ -992,6 +995,9 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
if (*killed_ptr(param))
goto err2;
switch (info->s->data_file_type) {
+ case BLOCK_RECORD:
+ DBUG_ASSERT(0); /* Impossible */
+ break;
case STATIC_RECORD:
if (my_b_read(&param->read_cache,(uchar*) record,
info->s->base.pack_reclength))
@@ -1005,7 +1011,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
del_length+=info->s->base.pack_reclength;
continue; /* Record removed */
}
- param->glob_crc+= mi_static_checksum(info,record);
+ param->glob_crc+= (*info->s->calc_check_checksum)(info,record);
used+=info->s->base.pack_reclength;
break;
case DYNAMIC_RECORD:
@@ -1159,7 +1165,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
}
else
{
- info->checksum=mi_checksum(info,record);
+ info->checksum= (*info->s->calc_check_checksum)(info,record);
if (param->testflag & (T_EXTEND | T_MEDIUM | T_VERBOSE))
{
if (_mi_rec_check(info,record, info->rec_buff,block_info.rec_len,
@@ -1205,15 +1211,10 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
llstr(start_recpos,llbuff));
got_error=1;
}
- if (static_row_size)
- param->glob_crc+= mi_static_checksum(info,record);
- else
- param->glob_crc+= mi_checksum(info,record);
+ param->glob_crc+= (*info->s->calc_check_checksum)(info,record);
link_used+= (block_info.filepos - start_recpos);
used+= (pos-start_recpos);
break;
- case BLOCK_RECORD:
- assert(0); /* Impossible */
} /* switch */
if (! got_error)
{
@@ -1432,7 +1433,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
then recrate all indexes.
*/
-static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force)
+static int mi_drop_all_indexes(HA_CHECK *param, MI_INFO *info, my_bool force)
{
MYISAM_SHARE *share= info->s;
MI_STATE_INFO *state= &share->state;
@@ -1515,7 +1516,7 @@ static int mi_drop_all_indexes(MI_CHECK *param, MI_INFO *info, my_bool force)
/* Recover old table by reading each record and writing all keys */
/* Save new datafile-name in temp_filename */
-int mi_repair(MI_CHECK *param, register MI_INFO *info,
+int mi_repair(HA_CHECK *param, register MI_INFO *info,
char * name, int rep_quick)
{
int error,got_error;
@@ -1524,7 +1525,7 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info,
File new_file;
MYISAM_SHARE *share=info->s;
char llbuff[22],llbuff2[22];
- SORT_INFO sort_info;
+ MI_SORT_INFO sort_info;
MI_SORT_PARAM sort_param;
DBUG_ENTER("mi_repair");
@@ -1892,7 +1893,7 @@ int movepoint(register MI_INFO *info, uchar *record, my_off_t oldpos,
/* Tell system that we want all memory for our cache */
-void lock_memory(MI_CHECK *param __attribute__((unused)))
+void lock_memory(HA_CHECK *param __attribute__((unused)))
{
#ifdef SUN_OS /* Key-cacheing thrases on sun 4.1 */
if (param->opt_lock_memory)
@@ -1908,7 +1909,7 @@ void lock_memory(MI_CHECK *param __attribute__((unused)))
/* Flush all changed blocks to disk */
-int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file)
+int flush_blocks(HA_CHECK *param, KEY_CACHE *key_cache, File file)
{
if (flush_key_blocks(key_cache, file, FLUSH_RELEASE))
{
@@ -1923,7 +1924,7 @@ int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file)
/* Sort index for more efficent reads */
-int mi_sort_index(MI_CHECK *param, register MI_INFO *info, char * name)
+int mi_sort_index(HA_CHECK *param, register MI_INFO *info, char * name)
{
reg2 uint key;
reg1 MI_KEYDEF *keyinfo;
@@ -2023,7 +2024,7 @@ err2:
/* Sort records recursive using one index */
-static int sort_one_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
+static int sort_one_index(HA_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
my_off_t pagepos, File new_file)
{
uint length,nod_flag,used_length, key_length;
@@ -2143,12 +2144,12 @@ int change_to_newfile(const char * filename, const char * old_ext,
/* Locks a whole file */
/* Gives an error-message if file can't be locked */
-int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type,
+int lock_file(HA_CHECK *param, File file, my_off_t start, int lock_type,
const char *filetype, const char *filename)
{
if (my_lock(file,lock_type,start,F_TO_EOF,
param->testflag & T_WAIT_FOREVER ? MYF(MY_SEEK_NOT_DONE) :
- MYF(MY_SEEK_NOT_DONE | MY_DONT_WAIT)))
+ MYF(MY_SEEK_NOT_DONE | MY_SHORT_WAIT)))
{
mi_check_print_error(param," %d when locking %s '%s'",my_errno,filetype,filename);
param->error_printed=2; /* Don't give that data is crashed */
@@ -2160,7 +2161,7 @@ int lock_file(MI_CHECK *param, File file, my_off_t start, int lock_type,
/* Copy a block between two files */
-int filecopy(MI_CHECK *param, File to,File from,my_off_t start,
+int filecopy(HA_CHECK *param, File to,File from,my_off_t start,
my_off_t length, const char *type)
{
char tmp_buff[IO_SIZE],*buff;
@@ -2211,7 +2212,7 @@ err:
<>0 Error
*/
-int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
+int mi_repair_by_sort(HA_CHECK *param, register MI_INFO *info,
const char * name, int rep_quick)
{
int got_error;
@@ -2225,7 +2226,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
HA_KEYSEG *keyseg;
ulong *rec_per_key_part;
char llbuff[22];
- SORT_INFO sort_info;
+ MI_SORT_INFO sort_info;
ulonglong key_map;
DBUG_ENTER("mi_repair_by_sort");
LINT_INIT(key_map);
@@ -2497,7 +2498,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
goto err;
}
- if (rep_quick & T_FORCE_UNIQUENESS)
+ if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
{
my_off_t skr=info->state->data_file_length+
(share->options & HA_OPTION_COMPRESS_RECORD ?
@@ -2630,7 +2631,7 @@ err:
<>0 Error
*/
-int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
+int mi_repair_parallel(HA_CHECK *param, register MI_INFO *info,
const char * name, int rep_quick)
{
#ifndef THREAD
@@ -2649,7 +2650,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
char llbuff[22];
IO_CACHE new_data_cache; /* For non-quick repair. */
IO_CACHE_SHARE io_share;
- SORT_INFO sort_info;
+ MI_SORT_INFO sort_info;
ulonglong key_map;
pthread_attr_t thr_attr;
ulong max_pack_reclength;
@@ -2674,14 +2675,14 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
/*
Quick repair (not touching data file, rebuilding indexes):
{
- Read cache is (MI_CHECK *param)->read_cache using info->dfile.
+ Read cache is (HA_CHECK *param)->read_cache using info->dfile.
}
Non-quick repair (rebuilding data file and indexes):
{
Master thread:
- Read cache is (MI_CHECK *param)->read_cache using info->dfile.
+ Read cache is (HA_CHECK *param)->read_cache using info->dfile.
Write cache is (MI_INFO *info)->rec_cache using new_file.
Slave threads:
@@ -3020,7 +3021,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
goto err;
}
- if (rep_quick & T_FORCE_UNIQUENESS)
+ if (rep_quick && (param->testflag & T_FORCE_UNIQUENESS))
{
my_off_t skr=info->state->data_file_length+
(share->options & HA_OPTION_COMPRESS_RECORD ?
@@ -3129,7 +3130,7 @@ err:
static int sort_key_read(MI_SORT_PARAM *sort_param, void *key)
{
int error;
- SORT_INFO *sort_info=sort_param->sort_info;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
MI_INFO *info=sort_info->info;
DBUG_ENTER("sort_key_read");
@@ -3156,7 +3157,7 @@ static int sort_key_read(MI_SORT_PARAM *sort_param, void *key)
static int sort_ft_key_read(MI_SORT_PARAM *sort_param, void *key)
{
int error;
- SORT_INFO *sort_info=sort_param->sort_info;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
MI_INFO *info=sort_info->info;
FT_WORD *wptr=0;
DBUG_ENTER("sort_ft_key_read");
@@ -3243,8 +3244,8 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
my_off_t pos;
uchar *to;
MI_BLOCK_INFO block_info;
- SORT_INFO *sort_info=sort_param->sort_info;
- MI_CHECK *param=sort_info->param;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
MI_INFO *info=sort_info->info;
MYISAM_SHARE *share=info->s;
char llbuff[22],llbuff2[22];
@@ -3254,6 +3255,9 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
DBUG_RETURN(1);
switch (share->data_file_type) {
+ case BLOCK_RECORD:
+ DBUG_ASSERT(0); /* Impossible */
+ break;
case STATIC_RECORD:
for (;;)
{
@@ -3278,7 +3282,9 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
{
if (sort_param->calc_checksum)
param->glob_crc+= (info->checksum=
- mi_static_checksum(info,sort_param->record));
+ (*info->s->calc_check_checksum)(info,
+ sort_param->
+ record));
DBUG_RETURN(0);
}
if (!sort_param->fix_datafile && sort_param->master)
@@ -3554,7 +3560,8 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
if (sort_param->read_cache.error < 0)
DBUG_RETURN(1);
if (sort_param->calc_checksum)
- info->checksum= mi_checksum(info, sort_param->record);
+ info->checksum= (*info->s->calc_check_checksum)(info,
+ sort_param->record);
if ((param->testflag & (T_EXTEND | T_REP)) || searching)
{
if (_mi_rec_check(info, sort_param->record, sort_param->rec_buff,
@@ -3639,11 +3646,11 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
info->packed_length=block_info.rec_len;
if (sort_param->calc_checksum)
param->glob_crc+= (info->checksum=
- mi_checksum(info, sort_param->record));
+ (*info->s->calc_check_checksum)(info,
+ sort_param->
+ record));
DBUG_RETURN(0);
}
- case BLOCK_RECORD:
- assert(0); /* Impossible */
}
DBUG_RETURN(1); /* Impossible */
}
@@ -3671,8 +3678,8 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
ulong block_length,reclength;
uchar *from;
uchar block_buff[8];
- SORT_INFO *sort_info=sort_param->sort_info;
- MI_CHECK *param=sort_info->param;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
MI_INFO *info=sort_info->info;
MYISAM_SHARE *share=info->s;
DBUG_ENTER("sort_write_record");
@@ -3680,6 +3687,9 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
if (sort_param->fix_datafile)
{
switch (sort_info->new_data_file_type) {
+ case BLOCK_RECORD:
+ DBUG_ASSERT(0); /* Impossible */
+ break;
case STATIC_RECORD:
if (my_b_write(&info->rec_cache,sort_param->record,
share->base.pack_reclength))
@@ -3689,7 +3699,6 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
}
sort_param->filepos+=share->base.pack_reclength;
info->s->state.split++;
- /* sort_info->param->glob_crc+=mi_static_checksum(info, sort_param->record); */
break;
case DYNAMIC_RECORD:
if (! info->blobs)
@@ -3698,7 +3707,7 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
{
/* must be sure that local buffer is big enough */
reclength=info->s->base.pack_reclength+
- _my_calc_total_blob_length(info,sort_param->record)+
+ _mi_calc_total_blob_length(info,sort_param->record)+
ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
MI_DYN_DELETE_BLOCK_HEADER;
if (sort_info->buff_length < reclength)
@@ -3712,10 +3721,9 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
from= sort_info->buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER);
}
/* We can use info->checksum here as only one thread calls this. */
- info->checksum=mi_checksum(info,sort_param->record);
+ info->checksum= (*info->s->calc_check_checksum)(info,sort_param->record);
reclength=_mi_rec_pack(info,from,sort_param->record);
flag=0;
- /* sort_info->param->glob_crc+=info->checksum; */
do
{
@@ -3755,8 +3763,6 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
sort_param->filepos+=reclength+length;
info->s->state.split++;
break;
- case BLOCK_RECORD:
- assert(0); /* Impossible */
}
}
if (sort_param->master)
@@ -3789,24 +3795,26 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
{
uint diff_pos[2];
char llbuff[22],llbuff2[22];
- SORT_INFO *sort_info=sort_param->sort_info;
- MI_CHECK *param= sort_info->param;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param= sort_info->param;
int cmp;
if (sort_info->key_block->inited)
{
- cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
- (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
+ cmp=ha_key_cmp(sort_param->seg, (uchar*) sort_info->key_block->lastkey,
+ (uchar*) a, USE_WHOLE_KEY,
+ SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT,
diff_pos);
if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
- ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
+ ha_key_cmp(sort_param->seg, (uchar*) sort_info->key_block->lastkey,
(uchar*) a, USE_WHOLE_KEY,
SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, diff_pos);
else if (param->stats_method == MI_STATS_METHOD_IGNORE_NULLS)
{
diff_pos[0]= mi_collect_stats_nonulls_next(sort_param->seg,
sort_param->notnull,
- sort_info->key_block->lastkey,
+ (uchar*) sort_info->
+ key_block->lastkey,
(uchar*)a);
}
sort_param->unique[diff_pos[0]-1]++;
@@ -3829,8 +3837,8 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
llstr(sort_info->info->lastpos,llbuff),
llstr(get_record_for_key(sort_info->info,
sort_param->keyinfo,
- sort_info->key_block->
- lastkey),
+ (uchar*) sort_info->
+ key_block->lastkey),
llbuff2));
param->testflag|=T_RETRY_WITHOUT_QUICK;
if (sort_info->param->testflag & T_VERBOSE)
@@ -3851,7 +3859,7 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
int sort_ft_buf_flush(MI_SORT_PARAM *sort_param)
{
- SORT_INFO *sort_info=sort_param->sort_info;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
SORT_KEY_BLOCKS *key_block=sort_info->key_block;
MYISAM_SHARE *share=sort_info->info->s;
uint val_off, val_len;
@@ -3861,19 +3869,19 @@ int sort_ft_buf_flush(MI_SORT_PARAM *sort_param)
val_len=share->ft2_keyinfo.keylength;
get_key_full_length_rdonly(val_off, ft_buf->lastkey);
- to=ft_buf->lastkey+val_off;
+ to= (uchar*) ft_buf->lastkey+val_off;
if (ft_buf->buf)
{
/* flushing first-level tree */
- error=sort_insert_key(sort_param,key_block,ft_buf->lastkey,
+ error=sort_insert_key(sort_param,key_block, (uchar*) ft_buf->lastkey,
HA_OFFSET_ERROR);
for (from=to+val_len;
- !error && from < ft_buf->buf;
+ !error && from < (uchar*) ft_buf->buf;
from+= val_len)
{
memcpy(to, from, val_len);
- error=sort_insert_key(sort_param,key_block,ft_buf->lastkey,
+ error=sort_insert_key(sort_param,key_block, (uchar*) ft_buf->lastkey,
HA_OFFSET_ERROR);
}
return error;
@@ -3882,8 +3890,8 @@ int sort_ft_buf_flush(MI_SORT_PARAM *sort_param)
error=flush_pending_blocks(sort_param);
/* updating lastkey with second-level tree info */
ft_intXstore(ft_buf->lastkey+val_off, -ft_buf->count);
- _mi_dpointer(sort_info->info, ft_buf->lastkey+val_off+HA_FT_WLEN,
- share->state.key_root[sort_param->key]);
+ _mi_dpointer(sort_info->info, (uchar*) ft_buf->lastkey+val_off+HA_FT_WLEN,
+ share->state.key_root[sort_param->key]);
/* restoring first level tree data in sort_info/sort_param */
sort_info->key_block=sort_info->key_block_end- sort_info->param->sort_key_blocks;
sort_param->keyinfo=share->keyinfo+sort_param->key;
@@ -3891,14 +3899,14 @@ int sort_ft_buf_flush(MI_SORT_PARAM *sort_param)
/* writing lastkey in first-level tree */
return error ? error :
sort_insert_key(sort_param,sort_info->key_block,
- ft_buf->lastkey,HA_OFFSET_ERROR);
+ (uchar*) ft_buf->lastkey,HA_OFFSET_ERROR);
}
static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a)
{
uint a_len, val_off, val_len, error;
uchar *p;
- SORT_INFO *sort_info=sort_param->sort_info;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
SORT_FT_BUF *ft_buf=sort_info->ft_buf;
SORT_KEY_BLOCKS *key_block=sort_info->key_block;
@@ -3930,7 +3938,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a)
if (ha_compare_text(sort_param->seg->charset,
((uchar *)a)+1,a_len-1,
- ft_buf->lastkey+1,val_off-1, 0, 0)==0)
+ (uchar*) ft_buf->lastkey+1,val_off-1, 0, 0)==0)
{
if (!ft_buf->buf) /* store in second-level tree */
{
@@ -3946,16 +3954,16 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a)
return 0;
/* converting to two-level tree */
- p=ft_buf->lastkey+val_off;
+ p= (uchar*) ft_buf->lastkey+val_off;
while (key_block->inited)
key_block++;
sort_info->key_block=key_block;
sort_param->keyinfo=& sort_info->info->s->ft2_keyinfo;
- ft_buf->count=(ft_buf->buf - p)/val_len;
+ ft_buf->count=((uchar*) ft_buf->buf - p)/val_len;
/* flushing buffer to second-level tree */
- for (error=0; !error && p < ft_buf->buf; p+= val_len)
+ for (error=0; !error && p < (uchar*) ft_buf->buf; p+= val_len)
error=sort_insert_key(sort_param,key_block,p,HA_OFFSET_ERROR);
ft_buf->buf=0;
return error;
@@ -4003,13 +4011,13 @@ static int sort_insert_key(MI_SORT_PARAM *sort_param,
MI_KEY_PARAM s_temp;
MI_INFO *info;
MI_KEYDEF *keyinfo=sort_param->keyinfo;
- SORT_INFO *sort_info= sort_param->sort_info;
- MI_CHECK *param=sort_info->param;
+ MI_SORT_INFO *sort_info= sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
DBUG_ENTER("sort_insert_key");
- anc_buff=key_block->buff;
+ anc_buff= (uchar*) key_block->buff;
info=sort_info->info;
- lastkey=key_block->lastkey;
+ lastkey= (uchar*) key_block->lastkey;
nod_flag= (key_block == sort_info->key_block ? 0 :
info->s->base.key_reflength);
@@ -4022,7 +4030,7 @@ static int sort_insert_key(MI_SORT_PARAM *sort_param,
DBUG_RETURN(1);
}
a_length=2+nod_flag;
- key_block->end_pos=anc_buff+2;
+ key_block->end_pos= anc_buff+2;
lastkey=0; /* No previous key in block */
}
else
@@ -4030,18 +4038,18 @@ static int sort_insert_key(MI_SORT_PARAM *sort_param,
/* Save pointer to previous block */
if (nod_flag)
- _mi_kpointer(info,key_block->end_pos,prev_block);
+ _mi_kpointer(info,(uchar*) key_block->end_pos,prev_block);
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
(uchar*) 0,lastkey,lastkey,key,
&s_temp);
- (*keyinfo->store_key)(keyinfo, key_block->end_pos+nod_flag,&s_temp);
+ (*keyinfo->store_key)(keyinfo, (uchar*) key_block->end_pos+nod_flag,&s_temp);
a_length+=t_length;
mi_putint(anc_buff,a_length,nod_flag);
key_block->end_pos+=t_length;
if (a_length <= keyinfo->block_length)
{
- VOID(_mi_move_key(keyinfo,key_block->lastkey,key));
+ VOID(_mi_move_key(keyinfo,(uchar*) key_block->lastkey,key));
key_block->last_length=a_length-t_length;
DBUG_RETURN(0);
}
@@ -4066,7 +4074,8 @@ static int sort_insert_key(MI_SORT_PARAM *sort_param,
DBUG_DUMP("buff",(uchar*) anc_buff,mi_getint(anc_buff));
/* Write separator-key to block in next level */
- if (sort_insert_key(sort_param,key_block+1,key_block->lastkey,filepos))
+ if (sort_insert_key(sort_param,key_block+1,(uchar*) key_block->lastkey,
+ filepos))
DBUG_RETURN(1);
/* clear old block and write new key in it */
@@ -4082,8 +4091,8 @@ static int sort_delete_record(MI_SORT_PARAM *sort_param)
uint i;
int old_file,error;
uchar *key;
- SORT_INFO *sort_info=sort_param->sort_info;
- MI_CHECK *param=sort_info->param;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
MI_INFO *info=sort_info->info;
DBUG_ENTER("sort_delete_record");
@@ -4139,7 +4148,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param)
uint nod_flag,length;
my_off_t filepos,key_file_length;
SORT_KEY_BLOCKS *key_block;
- SORT_INFO *sort_info= sort_param->sort_info;
+ MI_SORT_INFO *sort_info= sort_param->sort_info;
myf myf_rw=sort_info->param->myf_rw;
MI_INFO *info=sort_info->info;
MI_KEYDEF *keyinfo=sort_param->keyinfo;
@@ -4152,7 +4161,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param)
key_block->inited=0;
length=mi_getint(key_block->buff);
if (nod_flag)
- _mi_kpointer(info,key_block->end_pos,filepos);
+ _mi_kpointer(info,(uchar*) key_block->end_pos,filepos);
key_file_length=info->state->key_file_length;
bzero((uchar*) key_block->buff+length, keyinfo->block_length-length);
if ((filepos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
@@ -4162,7 +4171,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param)
if (key_file_length == info->state->key_file_length)
{
if (_mi_write_keypage(info, keyinfo, filepos,
- DFLT_INIT_HITS, key_block->buff))
+ DFLT_INIT_HITS, (uchar*) key_block->buff))
DBUG_RETURN(1);
}
else if (my_pwrite(info->s->kfile,(uchar*) key_block->buff,
@@ -4177,7 +4186,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param)
/* alloc space and pointers for key_blocks */
-static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks,
+static SORT_KEY_BLOCKS *alloc_key_blocks(HA_CHECK *param, uint blocks,
uint buffer_length)
{
reg1 uint i;
@@ -4214,7 +4223,7 @@ int test_if_almost_full(MI_INFO *info)
/* Recreate table with bigger more alloced record-data */
-int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename)
+int recreate_table(HA_CHECK *param, MI_INFO **org_info, char *filename)
{
int error;
MI_INFO info;
@@ -4387,7 +4396,7 @@ end:
/* write suffix to data file if neaded */
-int write_data_suffix(SORT_INFO *sort_info, my_bool fix_datafile)
+int write_data_suffix(MI_SORT_INFO *sort_info, my_bool fix_datafile)
{
MI_INFO *info=sort_info->info;
@@ -4408,7 +4417,7 @@ int write_data_suffix(SORT_INFO *sort_info, my_bool fix_datafile)
/* Update state and myisamchk_time of indexfile */
-int update_state_info(MI_CHECK *param, MI_INFO *info,uint update)
+int update_state_info(HA_CHECK *param, MI_INFO *info,uint update)
{
MYISAM_SHARE *share=info->s;
@@ -4480,7 +4489,7 @@ err:
param->auto_increment is bigger than the biggest key.
*/
-void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
+void update_auto_increment_key(HA_CHECK *param, MI_INFO *info,
my_bool repair_only)
{
uchar *record= 0;
@@ -4712,7 +4721,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows,
static void
-set_data_file_type(SORT_INFO *sort_info, MYISAM_SHARE *share)
+set_data_file_type(MI_SORT_INFO *sort_info, MYISAM_SHARE *share)
{
if ((sort_info->new_data_file_type=share->data_file_type) ==
COMPRESSED_RECORD && sort_info->param->testflag & T_UNPACK)
diff --git a/storage/myisam/mi_checksum.c b/storage/myisam/mi_checksum.c
index 1aa56e571e3..8c408ef7ff5 100644
--- a/storage/myisam/mi_checksum.c
+++ b/storage/myisam/mi_checksum.c
@@ -19,27 +19,34 @@
ha_checksum mi_checksum(MI_INFO *info, const uchar *buf)
{
- uint i;
ha_checksum crc=0;
- MI_COLUMNDEF *rec=info->s->rec;
+ const uchar *record= buf;
+ MI_COLUMNDEF *column= info->s->rec;
+ MI_COLUMNDEF *column_end= column+ info->s->base.fields;
+ my_bool skip_null_bits= test(info->s->options & HA_OPTION_NULL_FIELDS);
- for (i=info->s->base.fields ; i-- ; buf+=(rec++)->length)
+ for ( ; column != column_end ; buf+= column++->length)
{
const uchar *pos;
ulong length;
- switch (rec->type) {
+
+ if ((record[column->null_pos] & column->null_bit) &&
+ skip_null_bits)
+ continue; /* Null field */
+
+ switch (column->type) {
case FIELD_BLOB:
{
- length=_mi_calc_blob_length(rec->length-
- portable_sizeof_char_ptr,
- buf);
- memcpy((char*) &pos, buf+rec->length- portable_sizeof_char_ptr,
+ length=_mi_calc_blob_length(column->length-
+ portable_sizeof_char_ptr,
+ buf);
+ memcpy((char*) &pos, buf+column->length- portable_sizeof_char_ptr,
sizeof(char*));
break;
}
case FIELD_VARCHAR:
{
- uint pack_length= HA_VARCHAR_PACKLENGTH(rec->length-1);
+ uint pack_length= HA_VARCHAR_PACKLENGTH(column->length-1);
if (pack_length == 1)
length= (ulong) *(uchar*) buf;
else
@@ -48,7 +55,7 @@ ha_checksum mi_checksum(MI_INFO *info, const uchar *buf)
break;
}
default:
- length=rec->length;
+ length=column->length;
pos=buf;
break;
}
diff --git a/storage/myisam/mi_close.c b/storage/myisam/mi_close.c
index 07105aea88d..747555dbdfb 100644
--- a/storage/myisam/mi_close.c
+++ b/storage/myisam/mi_close.c
@@ -75,6 +75,7 @@ int mi_close(register MI_INFO *info)
not change the crashed state.
We can NOT write the state in other cases as other threads
may be using the file at this point
+ IF using --external-locking.
*/
if (share->mode != O_RDONLY && mi_is_crashed(info))
mi_state_info_write(share->kfile, &share->state, 1);
diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c
index 448e1b3c6f8..1ad58bee3e3 100644
--- a/storage/myisam/mi_create.c
+++ b/storage/myisam/mi_create.c
@@ -41,11 +41,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
File dfile,file;
int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
myf create_flag;
- uint fields,length,max_key_length,packed,pointer,real_length_diff,
+ uint fields,length,max_key_length,packed,pack_bytes,pointer,real_length_diff,
key_length,info_length,key_segs,options,min_key_length_skip,
base_pos,long_varchar_count,varchar_length,
max_key_block_length,unique_key_parts,fulltext_keys,offset;
- uint aligned_key_start, block_length;
+ uint aligned_key_start, block_length, res;
ulong reclength, real_reclength,min_pack_length;
char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
ulong pack_reclength;
@@ -95,7 +95,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
ci->reloc_rows=ci->max_rows; /* Check if wrong parameter */
if (!(rec_per_key_part=
- (ulong*) my_malloc((keys + uniques)*MI_MAX_KEY_SEG*sizeof(long),
+ (ulong*) my_malloc((keys + uniques)*HA_MAX_KEY_SEG*sizeof(long),
MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(my_errno);
@@ -108,6 +108,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
rec++,fields++)
{
reclength+=rec->length;
+ if (rec->null_bit)
+ options|= HA_OPTION_NULL_FIELDS;
+
if ((type=(enum en_fieldtype) rec->type) != FIELD_NORMAL &&
type != FIELD_CHECK)
{
@@ -142,6 +145,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
long_varchar_count++;
pack_reclength+= 2; /* May be packed on 3 bytes */
}
+ options|= HA_OPTION_NULL_FIELDS; /* Use of mi_checksum() */
}
else if (type != FIELD_SKIP_ZERO)
{
@@ -181,7 +185,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (flags & HA_CREATE_TMP_TABLE)
{
options|= HA_OPTION_TMP_TABLE;
- create_mode|= O_EXCL | O_NOFOLLOW;
+ create_mode|= O_NOFOLLOW;
}
if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
{
@@ -193,11 +197,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (flags & HA_CREATE_RELIES_ON_SQL_LAYER)
options|= HA_OPTION_RELIES_ON_SQL_LAYER;
- packed=(packed+7)/8;
+ pack_bytes= (packed+7)/8;
if (pack_reclength != INT_MAX32)
pack_reclength+= reclength+packed +
test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_OPTION_PACK_RECORD));
- min_pack_length+=packed;
+ min_pack_length+= pack_bytes;
if (!ci->data_file_length && ci->max_rows)
{
@@ -274,7 +278,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
keyseg->type != HA_KEYTYPE_VARBINARY2)
{
my_errno=HA_WRONG_CREATE_OPTION;
- goto err;
+ goto err_no_lock;
}
}
keydef->keysegs+=sp_segs;
@@ -283,7 +287,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
min_key_length_skip+=SPLEN*2*SPDIMS;
#else
my_errno= HA_ERR_UNSUPPORTED;
- goto err;
+ goto err_no_lock;
#endif /*HAVE_SPATIAL*/
}
else if (keydef->flag & HA_FULLTEXT)
@@ -299,7 +303,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
keyseg->type != HA_KEYTYPE_VARTEXT2)
{
my_errno=HA_WRONG_CREATE_OPTION;
- goto err;
+ goto err_no_lock;
}
if (!(keyseg->flag & HA_BLOB_PART) &&
(keyseg->type == HA_KEYTYPE_VARTEXT1 ||
@@ -421,10 +425,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
}
} /* if HA_FULLTEXT */
key_segs+=keydef->keysegs;
- if (keydef->keysegs > MI_MAX_KEY_SEG)
+ if (keydef->keysegs > HA_MAX_KEY_SEG)
{
my_errno=HA_WRONG_CREATE_OPTION;
- goto err;
+ goto err_no_lock;
}
/*
key_segs may be 0 in the case when we only want to be able to
@@ -436,7 +440,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
share.state.rec_per_key_part[key_segs-1]=1L;
length+=key_length;
/* Get block length for key, if defined by user */
- block_length= (keydef->block_length ?
+ block_length= (keydef->block_length ?
my_round_up_to_next_power(keydef->block_length) :
myisam_block_size);
block_length= max(block_length, MI_MIN_KEY_BLOCK_LENGTH);
@@ -446,10 +450,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
pointer,MI_MAX_KEYPTR_SIZE,
block_length);
if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH ||
- length >= MI_MAX_KEY_BUFF)
+ length >= HA_MAX_KEY_BUFF)
{
my_errno=HA_WRONG_CREATE_OPTION;
- goto err;
+ goto err_no_lock;
}
set_if_bigger(max_key_block_length,keydef->block_length);
keydef->keylength= (uint16) key_length;
@@ -492,11 +496,12 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
/* There are only 16 bits for the total header length. */
if (info_length > 65535)
{
- my_printf_error(0, "MyISAM table '%s' has too many columns and/or "
+ my_printf_error(HA_WRONG_CREATE_OPTION,
+ "MyISAM table '%s' has too many columns and/or "
"indexes and/or unique constraints.",
MYF(0), name + dirname_length(name));
my_errno= HA_WRONG_CREATE_OPTION;
- goto err;
+ goto err_no_lock;
}
bmove(share.state.header.file_version,(uchar*) myisam_file_magic,4);
@@ -551,9 +556,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM);
share.base.max_pack_length=pack_reclength;
share.base.min_pack_length=min_pack_length;
- share.base.pack_bits=packed;
+ share.base.pack_bits= pack_bytes;
share.base.fields=fields;
- share.base.pack_fields=packed;
+ share.base.pack_fields= packed;
#ifdef USE_RAID
share.base.raid_type=ci->raid_type;
share.base.raid_chunks=ci->raid_chunks;
@@ -828,13 +833,16 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
}
errpos=0;
pthread_mutex_unlock(&THR_LOCK_myisam);
+ res= 0;
if (my_close(file,MYF(0)))
- goto err;
+ res= my_errno;
my_free((char*) rec_per_key_part,MYF(0));
- DBUG_RETURN(0);
+ DBUG_RETURN(res);
err:
pthread_mutex_unlock(&THR_LOCK_myisam);
+err_no_lock:
+
save_errno=my_errno;
switch (errpos) {
case 3:
diff --git a/storage/myisam/mi_dbug.c b/storage/myisam/mi_dbug.c
index 07c314c43e6..659abdce131 100644
--- a/storage/myisam/mi_dbug.c
+++ b/storage/myisam/mi_dbug.c
@@ -45,6 +45,7 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg,
fprintf(stream,"NULL");
continue;
}
+ end++;
}
switch (keyseg->type) {
@@ -91,7 +92,7 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg,
key=end;
break;
case HA_KEYTYPE_ULONG_INT:
- l_1=mi_sint4korr(key);
+ l_1=mi_uint4korr(key);
VOID(fprintf(stream,"%lu",(ulong) l_1));
key=end;
break;
diff --git a/storage/myisam/mi_delete.c b/storage/myisam/mi_delete.c
index 6fe31f30c19..8ebdb477183 100644
--- a/storage/myisam/mi_delete.c
+++ b/storage/myisam/mi_delete.c
@@ -159,7 +159,7 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo,
DBUG_RETURN(my_errno=HA_ERR_CRASHED);
}
if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
- MI_MAX_KEY_BUFF*2)))
+ HA_MAX_KEY_BUFF*2)))
{
DBUG_PRINT("error",("Couldn't allocate memory"));
DBUG_RETURN(my_errno=ENOMEM);
@@ -171,8 +171,9 @@ static int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo,
goto err;
}
if ((error=d_search(info,keyinfo,
- (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND | SEARCH_UPDATE
- : SEARCH_SAME),
+ (keyinfo->flag & HA_FULLTEXT ?
+ SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT :
+ SEARCH_SAME),
key,key_length,old_root,root_buff)) >0)
{
if (error == 2)
@@ -221,7 +222,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
my_bool last_key;
uchar *leaf_buff,*keypos;
my_off_t leaf_page,next_block;
- uchar lastkey[MI_MAX_KEY_BUFF];
+ uchar lastkey[HA_MAX_KEY_BUFF];
DBUG_ENTER("d_search");
DBUG_DUMP("page",(uchar*) anc_buff,mi_getint(anc_buff));
@@ -306,7 +307,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{
leaf_page=_mi_kpos(nod_flag,keypos);
if (!(leaf_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
- MI_MAX_KEY_BUFF*2)))
+ HA_MAX_KEY_BUFF*2)))
{
DBUG_PRINT("error",("Couldn't allocate memory"));
my_errno=ENOMEM;
@@ -365,9 +366,7 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{ /* This happens only with packed keys */
DBUG_PRINT("test",("Enlarging of key when deleting"));
if (!_mi_get_last_key(info,keyinfo,anc_buff,lastkey,keypos,&length))
- {
goto err;
- }
ret_value=_mi_insert(info,keyinfo,key,anc_buff,keypos,lastkey,
(uchar*) 0,(uchar*) 0,(my_off_t) 0,(my_bool) 0);
}
@@ -405,7 +404,7 @@ static int del(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *key,
int ret_value,length;
uint a_length,nod_flag,tmp;
my_off_t next_page;
- uchar keybuff[MI_MAX_KEY_BUFF],*endpos,*next_buff,*key_start, *prev_key;
+ uchar keybuff[HA_MAX_KEY_BUFF],*endpos,*next_buff,*key_start, *prev_key;
MYISAM_SHARE *share=info->s;
MI_KEY_PARAM s_temp;
DBUG_ENTER("del");
@@ -422,7 +421,7 @@ static int del(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *key,
{
next_page= _mi_kpos(nod_flag,endpos);
if (!(next_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
- MI_MAX_KEY_BUFF*2)))
+ HA_MAX_KEY_BUFF*2)))
DBUG_RETURN(-1);
if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,next_buff,0))
ret_value= -1;
@@ -509,7 +508,7 @@ static int underflow(register MI_INFO *info, register MI_KEYDEF *keyinfo,
uint length,anc_length,buff_length,leaf_length,p_length,s_length,nod_flag,
key_reflength,key_length;
my_off_t next_page;
- uchar anc_key[MI_MAX_KEY_BUFF],leaf_key[MI_MAX_KEY_BUFF],
+ uchar anc_key[HA_MAX_KEY_BUFF],leaf_key[HA_MAX_KEY_BUFF],
*buff,*endpos,*next_keypos,*anc_pos,*half_pos,*temp_pos,*prev_key,
*after_key;
MI_KEY_PARAM s_temp;
diff --git a/storage/myisam/mi_dynrec.c b/storage/myisam/mi_dynrec.c
index 3433c26f98b..3a5956abb7e 100644
--- a/storage/myisam/mi_dynrec.c
+++ b/storage/myisam/mi_dynrec.c
@@ -252,7 +252,7 @@ int _mi_write_blob_record(MI_INFO *info, const uchar *record)
extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
MI_DYN_DELETE_BLOCK_HEADER+1);
reclength= (info->s->base.pack_reclength +
- _my_calc_total_blob_length(info,record)+ extra);
+ _mi_calc_total_blob_length(info,record)+ extra);
#ifdef NOT_USED /* We now support big rows */
if (reclength > MI_DYN_MAX_ROW_LENGTH)
{
@@ -286,7 +286,7 @@ int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const uchar *record)
extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
MI_DYN_DELETE_BLOCK_HEADER);
reclength= (info->s->base.pack_reclength+
- _my_calc_total_blob_length(info,record)+ extra);
+ _mi_calc_total_blob_length(info,record)+ extra);
#ifdef NOT_USED /* We now support big rows */
if (reclength > MI_DYN_MAX_ROW_LENGTH)
{
@@ -1329,7 +1329,7 @@ err:
/* Calc length of blob. Update info in blobs->length */
-ulong _my_calc_total_blob_length(MI_INFO *info, const uchar *record)
+ulong _mi_calc_total_blob_length(MI_INFO *info, const uchar *record)
{
ulong length;
MI_BLOB *blob,*end;
@@ -1363,7 +1363,7 @@ ulong _mi_calc_blob_length(uint length, const uchar *pos)
}
-void _my_store_blob_length(uchar *pos,uint pack_length,uint length)
+void _mi_store_blob_length(uchar *pos,uint pack_length,uint length)
{
switch (pack_length) {
case 1:
@@ -1576,7 +1576,7 @@ int _mi_cmp_dynamic_record(register MI_INFO *info, register const uchar *record)
if (info->s->base.blobs)
{
if (!(buffer=(uchar*) my_alloca(info->s->base.pack_reclength+
- _my_calc_total_blob_length(info,record))))
+ _mi_calc_total_blob_length(info,record))))
DBUG_RETURN(-1);
}
reclength=_mi_rec_pack(info,buffer,record);
@@ -1834,7 +1834,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, uchar *buf,
/* VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); */
if (my_read(info->dfile,(uchar*) to,block_info.data_len,MYF(MY_NABP)))
{
- if (my_errno == -1)
+ if (my_errno == HA_ERR_FILE_TOO_SHORT)
my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
goto err;
}
diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c
index f0ddc15b325..d798ef50d7e 100644
--- a/storage/myisam/mi_extra.c
+++ b/storage/myisam/mi_extra.c
@@ -216,7 +216,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
info->lock_wait=0;
break;
case HA_EXTRA_NO_WAIT_LOCK:
- info->lock_wait=MY_DONT_WAIT;
+ info->lock_wait= MY_SHORT_WAIT;
break;
case HA_EXTRA_NO_KEYS:
if (info->lock_type == F_UNLCK)
@@ -256,6 +256,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
share->last_version= 0L; /* Impossible version */
pthread_mutex_unlock(&THR_LOCK_myisam);
break;
+ case HA_EXTRA_PREPARE_FOR_RENAME:
case HA_EXTRA_PREPARE_FOR_DROP:
pthread_mutex_lock(&THR_LOCK_myisam);
share->last_version= 0L; /* Impossible version */
@@ -263,8 +264,8 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
/* Close the isam and data files as Win32 can't drop an open table */
pthread_mutex_lock(&share->intern_lock);
if (flush_key_blocks(share->key_cache, share->kfile,
- (function == HA_EXTRA_FORCE_REOPEN ?
- FLUSH_RELEASE : FLUSH_IGNORE_CHANGED)))
+ (function == HA_EXTRA_PREPARE_FOR_DROP ?
+ FLUSH_IGNORE_CHANGED : FLUSH_RELEASE)))
{
error=my_errno;
share->changed=1;
diff --git a/storage/myisam/mi_key.c b/storage/myisam/mi_key.c
index 3f445ebf44d..94f3f34ec58 100644
--- a/storage/myisam/mi_key.c
+++ b/storage/myisam/mi_key.c
@@ -426,7 +426,7 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
/* The above changed info->lastkey2. Inform mi_rnext_same(). */
info->update&= ~HA_STATE_RNEXT_SAME;
- _my_store_blob_length(record+keyseg->start,
+ _mi_store_blob_length(record+keyseg->start,
(uint) keyseg->bit_start,length);
key+=length;
}
diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c
index ec359d13a14..2edeefad45f 100644
--- a/storage/myisam/mi_locking.c
+++ b/storage/myisam/mi_locking.c
@@ -56,9 +56,15 @@ int mi_lock_database(MI_INFO *info, int lock_type)
case F_UNLCK:
ftparser_call_deinitializer(info);
if (info->lock_type == F_RDLCK)
+ {
count= --share->r_locks;
+ mi_restore_status(info);
+ }
else
+ {
count= --share->w_locks;
+ mi_update_status(info);
+ }
--share->tot_locks;
if (info->lock_type == F_WRLCK && !share->w_locks &&
!share->delay_key_write && flush_key_blocks(share->key_cache,
@@ -84,16 +90,16 @@ int mi_lock_database(MI_INFO *info, int lock_type)
if (share->changed && !share->w_locks)
{
#ifdef HAVE_MMAP
- if ((info->s->mmaped_length != info->s->state.state.data_file_length) &&
- (info->s->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
- {
- if (info->s->concurrent_insert)
- rw_wrlock(&info->s->mmap_lock);
- mi_remap_file(info, info->s->state.state.data_file_length);
- info->s->nonmmaped_inserts= 0;
- if (info->s->concurrent_insert)
- rw_unlock(&info->s->mmap_lock);
- }
+ if ((info->s->mmaped_length != info->s->state.state.data_file_length) &&
+ (info->s->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
+ {
+ if (info->s->concurrent_insert)
+ rw_wrlock(&info->s->mmap_lock);
+ mi_remap_file(info, info->s->state.state.data_file_length);
+ info->s->nonmmaped_inserts= 0;
+ if (info->s->concurrent_insert)
+ rw_unlock(&info->s->mmap_lock);
+ }
#endif
share->state.process= share->last_process=share->this_process;
share->state.unique= info->last_unique= info->this_unique;
@@ -275,7 +281,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
(THR_WRITE_CONCURRENT_INSERT was used)
*/
-void mi_get_status(void* param, int concurrent_insert)
+void mi_get_status(void* param, my_bool concurrent_insert)
{
MI_INFO *info=(MI_INFO*) param;
DBUG_ENTER("mi_get_status");
@@ -300,6 +306,7 @@ void mi_get_status(void* param, int concurrent_insert)
void mi_update_status(void* param)
{
MI_INFO *info=(MI_INFO*) param;
+ DBUG_ENTER("mi_update_status");
/*
Because someone may have closed the table we point at, we only
update the state if its our own state. This isn't a problem as
@@ -336,20 +343,32 @@ void mi_update_status(void* param)
}
info->opt_flag&= ~WRITE_CACHE_USED;
}
+ DBUG_VOID_RETURN;
}
void mi_restore_status(void *param)
{
MI_INFO *info= (MI_INFO*) param;
+ DBUG_ENTER("mi_restore_status");
+ DBUG_PRINT("info",("key_file: %ld data_file: %ld",
+ (long) info->s->state.state.key_file_length,
+ (long) info->s->state.state.data_file_length));
info->state= &info->s->state.state;
info->append_insert_at_end= 0;
+ DBUG_VOID_RETURN;
}
void mi_copy_status(void* to,void *from)
{
- ((MI_INFO*) to)->state= &((MI_INFO*) from)->save_state;
+ MI_INFO *info= (MI_INFO*) to;
+ DBUG_ENTER("mi_copy_status");
+ info->state= &((MI_INFO*) from)->save_state;
+ DBUG_PRINT("info",("key_file: %ld data_file: %ld",
+ (long) info->state->key_file_length,
+ (long) info->state->data_file_length));
+ DBUG_VOID_RETURN;
}
@@ -377,17 +396,18 @@ void mi_copy_status(void* to,void *from)
my_bool mi_check_status(void *param)
{
MI_INFO *info=(MI_INFO*) param;
+ DBUG_ENTER("mi_check_status");
+ DBUG_PRINT("info",("dellink: %ld r_locks: %u w_locks: %u",
+ (long) info->s->state.dellink, (uint) info->s->r_locks,
+ (uint) info->s->w_locks));
/*
The test for w_locks == 1 is here because this thread has already done an
external lock (in other words: w_locks == 1 means no other threads has
a write lock)
*/
- DBUG_PRINT("info",("dellink: %ld r_locks: %u w_locks: %u",
- (long) info->s->state.dellink, (uint) info->s->r_locks,
- (uint) info->s->w_locks));
- return (my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR ||
+ DBUG_RETURN((my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR ||
(myisam_concurrent_insert == 2 && info->s->r_locks &&
- info->s->w_locks == 1));
+ info->s->w_locks == 1)));
}
@@ -409,10 +429,10 @@ int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
DBUG_RETURN(1);
if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
{
- int error=my_errno ? my_errno : -1;
+ int error= my_errno ? my_errno : HA_ERR_FILE_TOO_SHORT;
VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
MYF(MY_SEEK_NOT_DONE)));
- my_errno=error;
+ my_errno= error;
DBUG_RETURN(1);
}
}
diff --git a/storage/myisam/mi_log.c b/storage/myisam/mi_log.c
index 8b9ca038fec..982ba8b4367 100644
--- a/storage/myisam/mi_log.c
+++ b/storage/myisam/mi_log.c
@@ -133,7 +133,7 @@ void _myisam_log_record(enum myisam_log_commands command, MI_INFO *info,
if (!info->s->base.blobs)
length=info->s->base.reclength;
else
- length=info->s->base.reclength+ _my_calc_total_blob_length(info,record);
+ length=info->s->base.reclength+ _mi_calc_total_blob_length(info,record);
buff[0]=(uchar) command;
mi_int2store(buff+1,info->dfile);
mi_int4store(buff+3,pid);
diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c
index 78749d50fe5..d569c7dd5c8 100644
--- a/storage/myisam/mi_open.c
+++ b/storage/myisam/mi_open.c
@@ -19,6 +19,7 @@
#include "sp_defs.h"
#include "rt_index.h"
#include <m_ctype.h>
+#include <mysql_version.h>
#if defined(MSDOS) || defined(__WIN__)
#ifdef __WIN__
@@ -82,7 +83,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
uchar *disk_cache, *disk_pos, *end_pos;
MI_INFO info,*m_info,*old_info;
MYISAM_SHARE share_buff,*share;
- ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG];
+ ulong rec_per_key_part[HA_MAX_POSSIBLE_KEY*HA_MAX_KEY_SEG];
my_off_t key_root[HA_MAX_POSSIBLE_KEY],key_del[MI_MAX_KEY_BLOCK_SIZE];
ulonglong max_key_file_length, max_data_file_length;
DBUG_ENTER("mi_open");
@@ -95,7 +96,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
bzero((uchar*) &info,sizeof(info));
realpath_err= my_realpath(name_buff,
- fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
+ fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0));
if (my_is_symlink(org_name) &&
(realpath_err || (*myisam_test_invalid_symlink)(name_buff)))
{
@@ -112,7 +113,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share_buff.state.key_root=key_root;
share_buff.state.key_del=key_del;
share_buff.key_cache= multi_key_cache_search((uchar*) name_buff,
- strlen(name_buff));
+ strlen(name_buff),
+ dflt_key_cache);
DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
if (strstr(name, "/t1"))
@@ -139,8 +141,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
(uchar*) myisam_file_magic, 4))
{
DBUG_PRINT("error",("Wrong header in %s",name_buff));
- DBUG_DUMP("error_dump",(char*) share->state.header.file_version,
- head_length);
+ DBUG_DUMP("error_dump", share->state.header.file_version,
+ (size_t) head_length);
my_errno=HA_ERR_NOT_A_TABLE;
goto err;
}
@@ -150,7 +152,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA |
HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE |
- HA_OPTION_RELIES_ON_SQL_LAYER))
+ HA_OPTION_RELIES_ON_SQL_LAYER | HA_OPTION_NULL_FIELDS))
{
DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
my_errno=HA_ERR_OLD_FILE;
@@ -186,7 +188,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
{
if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF,
MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ?
- 0 : MY_DONT_WAIT))) &&
+ 0 : MY_SHORT_WAIT))) &&
!(open_flags & HA_OPEN_IGNORE_IF_LOCKED))
goto err;
}
@@ -217,7 +219,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
DBUG_PRINT("warning",("saved_base_info_length: %d base_info_length: %d",
len,MI_BASE_INFO_SIZE));
}
- disk_pos= my_n_base_info_read(disk_cache + base_pos, &share->base);
+ disk_pos= mi_n_base_info_read(disk_cache + base_pos, &share->base);
share->state.state_length=base_pos;
if (!(open_flags & HA_OPEN_FOR_REPAIR) &&
@@ -242,8 +244,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
}
key_parts+=fulltext_keys*FT_SEGS;
- if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
- key_parts > MI_MAX_KEY * MI_MAX_KEY_SEG)
+ if (share->base.max_key_length > HA_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
+ key_parts > MI_MAX_KEY * HA_MAX_KEY_SEG)
{
DBUG_PRINT("error",("Wrong key info: Max_key_length: %d keys: %d key_parts: %d", share->base.max_key_length, keys, key_parts));
my_errno=HA_ERR_UNSUPPORTED;
@@ -462,13 +464,20 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
share->rec[i].pack_type=0;
share->rec[i].huff_tree=0;
share->rec[i].offset=offset;
- if (share->rec[i].type == (int) FIELD_BLOB)
+ if (share->rec[i].type == FIELD_BLOB)
{
share->blobs[j].pack_length=
- share->rec[i].length-portable_sizeof_char_ptr;
+ share->rec[i].length - portable_sizeof_char_ptr;
share->blobs[j].offset=offset;
j++;
}
+#if MYSQL_VERSION_ID <= 60100
+ /* This is to detect old checksum option */
+ if (share->rec[i].null_bit)
+ share->has_null_fields= 1;
+ if (share->rec[i].type == FIELD_VARCHAR)
+ share->has_varchar_fields= 1;
+#endif
offset+=share->rec[i].length;
}
share->rec[i].type=(int) FIELD_LAST; /* End marker */
@@ -752,12 +761,14 @@ void mi_setup_functions(register MYISAM_SHARE *share)
{
share->read_record=_mi_read_pack_record;
share->read_rnd=_mi_read_rnd_pack_record;
- if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD))
- share->calc_checksum=0; /* No checksum */
- else if (share->options & HA_OPTION_PACK_RECORD)
+ if ((share->options &
+ (HA_OPTION_PACK_RECORD | HA_OPTION_NULL_FIELDS)))
share->calc_checksum= mi_checksum;
else
share->calc_checksum= mi_static_checksum;
+ share->calc_check_checksum= share->calc_checksum;
+ if (!(share->options & HA_OPTION_TEMP_COMPRESS_RECORD))
+ share->calc_checksum=0; /* No checksum */
}
else if (share->options & HA_OPTION_PACK_RECORD)
{
@@ -767,6 +778,7 @@ void mi_setup_functions(register MYISAM_SHARE *share)
share->compare_record=_mi_cmp_dynamic_record;
share->compare_unique=_mi_cmp_dynamic_unique;
share->calc_checksum= mi_checksum;
+ share->calc_check_checksum= share->calc_checksum;
/* add bits used to pack data to pack_reclength for faster allocation */
share->base.pack_reclength+= share->base.pack_bits;
@@ -790,7 +802,11 @@ void mi_setup_functions(register MYISAM_SHARE *share)
share->update_record=_mi_update_static_record;
share->write_record=_mi_write_static_record;
share->compare_unique=_mi_cmp_static_unique;
- share->calc_checksum= mi_static_checksum;
+ if (share->options & HA_OPTION_NULL_FIELDS)
+ share->calc_checksum= mi_checksum;
+ else
+ share->calc_checksum= mi_static_checksum;
+ share->calc_check_checksum= share->calc_checksum;
}
share->file_read= mi_nommap_pread;
share->file_write= mi_nommap_pwrite;
@@ -1042,7 +1058,7 @@ uint mi_base_info_write(File file, MI_BASE_INFO *base)
}
-uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base)
+uchar *mi_n_base_info_read(uchar *ptr, MI_BASE_INFO *base)
{
base->keystart = mi_sizekorr(ptr); ptr +=8;
base->max_data_file_length = mi_sizekorr(ptr); ptr +=8;
diff --git a/storage/myisam/mi_packrec.c b/storage/myisam/mi_packrec.c
index 2c4444d67c6..387b82de5ee 100644
--- a/storage/myisam/mi_packrec.c
+++ b/storage/myisam/mi_packrec.c
@@ -105,6 +105,7 @@ static void init_bit_buffer(MI_BIT_BUFF *bit_buff,uchar *buffer,uint length);
static uint fill_and_get_bits(MI_BIT_BUFF *bit_buff,uint count);
static void fill_buffer(MI_BIT_BUFF *bit_buff);
static uint max_bit(uint value);
+static uint read_pack_length(uint version, const uchar *buf, ulong *length);
#ifdef HAVE_MMAP
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam, MI_BIT_BUFF *bit_buff,
MI_BLOCK_INFO *info, uchar **rec_buff_p,
@@ -1043,7 +1044,7 @@ static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
return;
}
decode_bytes(rec,bit_buff,bit_buff->blob_pos,bit_buff->blob_pos+length);
- _my_store_blob_length((uchar*) to,pack_length,length);
+ _mi_store_blob_length((uchar*) to,pack_length,length);
memcpy_fixed((char*) to+pack_length,(char*) &bit_buff->blob_pos,
sizeof(char*));
bit_buff->blob_pos+=length;
@@ -1624,7 +1625,7 @@ uint save_pack_length(uint version, uchar *block_buff, ulong length)
}
-uint read_pack_length(uint version, const uchar *buf, ulong *length)
+static uint read_pack_length(uint version, const uchar *buf, ulong *length)
{
if (buf[0] < 254)
{
diff --git a/storage/myisam/mi_page.c b/storage/myisam/mi_page.c
index 23a2526f756..3ea00fa44db 100644
--- a/storage/myisam/mi_page.c
+++ b/storage/myisam/mi_page.c
@@ -49,7 +49,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo,
{
DBUG_PRINT("error",("page %lu had wrong page length: %u",
(ulong) page, page_size));
- DBUG_DUMP("page", (char*) tmp, keyinfo->block_length);
+ DBUG_DUMP("page",tmp, keyinfo->block_length);
info->last_keypage = HA_OFFSET_ERROR;
mi_print_error(info->s, HA_ERR_CRASHED);
my_errno = HA_ERR_CRASHED;
diff --git a/storage/myisam/mi_range.c b/storage/myisam/mi_range.c
index dc6dc9d62b7..aabbe1277c4 100644
--- a/storage/myisam/mi_range.c
+++ b/storage/myisam/mi_range.c
@@ -152,7 +152,7 @@ static ha_rows _mi_record_pos(MI_INFO *info, const uchar *key,
operations with a comment like "Not real duplicates", whatever this
means. From the condition above we can see that 'skip_end_space' is
always false for these operations. The result is that trailing space
- counts in key comparison and hence, emtpy strings ('', string length
+ counts in key comparison and hence, empty strings ('', string length
zero, but not NULL) compare less that strings starting with control
characters and these in turn compare less than strings starting with
blanks.
@@ -166,7 +166,7 @@ static ha_rows _mi_record_pos(MI_INFO *info, const uchar *key,
This is the reason that we add the SEARCH_UPDATE flag here. It makes
the key estimation compare in the same way like key write operations
- do. Olny so we will find the keys where they have been inserted.
+ do. Only so we will find the keys where they have been inserted.
Adding the flag unconditionally does not hurt as it is used in the
above mentioned condition only. So it can safely be used together
@@ -260,7 +260,7 @@ static uint _mi_keynr(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
uchar *keypos, uint *ret_max_key)
{
uint nod_flag,keynr,max_key;
- uchar t_buff[MI_MAX_KEY_BUFF],*end;
+ uchar t_buff[HA_MAX_KEY_BUFF],*end;
end= page+mi_getint(page);
nod_flag=mi_test_if_nod(page);
diff --git a/storage/myisam/mi_rkey.c b/storage/myisam/mi_rkey.c
index f1d35810d36..f20b0366683 100644
--- a/storage/myisam/mi_rkey.c
+++ b/storage/myisam/mi_rkey.c
@@ -85,6 +85,8 @@ int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
{
mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
+ if (share->concurrent_insert)
+ rw_unlock(&share->key_root_lock[inx]);
goto err;
}
break;
diff --git a/storage/myisam/mi_search.c b/storage/myisam/mi_search.c
index 89fabfa46d0..2c346ea18f7 100644
--- a/storage/myisam/mi_search.c
+++ b/storage/myisam/mi_search.c
@@ -60,7 +60,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
int error,flag;
uint nod_flag;
uchar *keypos,*maxpos;
- uchar lastkey[MI_MAX_KEY_BUFF],*buff;
+ uchar lastkey[HA_MAX_KEY_BUFF],*buff;
DBUG_ENTER("_mi_search");
DBUG_PRINT("enter",("pos: %lu nextflag: %u lastpos: %lu",
(ulong) pos, nextflag, (ulong) info->lastpos));
@@ -242,7 +242,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
{
int flag;
uint nod_flag,length,not_used[2];
- uchar t_buff[MI_MAX_KEY_BUFF],*end;
+ uchar t_buff[HA_MAX_KEY_BUFF],*end;
DBUG_ENTER("_mi_seq_search");
LINT_INIT(flag); LINT_INIT(length);
@@ -296,7 +296,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
int key_len_skip, seg_len_pack, key_len_left;
uchar *end, *kseg, *vseg;
uchar *sort_order=keyinfo->seg->charset->sort_order;
- uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
+ uchar tt_buff[HA_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
uchar *saved_from, *saved_to, *saved_vseg;
uint saved_length=0, saved_prefix_len=0;
uint length_pack;
@@ -409,7 +409,7 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
}
from+=keyseg->length;
page=from+nod_flag;
- length=from-vseg;
+ length= (uint) (from-vseg);
}
if (page > end)
@@ -816,7 +816,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
DBUG_PRINT("error",
("Found too long null packed key: %u of %u at 0x%lx",
length, keyseg->length, (long) *page_pos));
- DBUG_DUMP("key",(char*) *page_pos,16);
+ DBUG_DUMP("key",*page_pos,16);
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return 0;
@@ -873,7 +873,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
{
DBUG_PRINT("error",("Found too long packed key: %u of %u at 0x%lx",
length, keyseg->length, (long) *page_pos));
- DBUG_DUMP("key",(char*) *page_pos,16);
+ DBUG_DUMP("key",*page_pos,16);
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return 0; /* Error */
@@ -920,7 +920,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
DBUG_ENTER("_mi_get_binary_pack_key");
page= *page_pos;
- page_end=page+MI_MAX_KEY_BUFF+1;
+ page_end=page+HA_MAX_KEY_BUFF+1;
start_key=key;
/*
@@ -945,7 +945,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
DBUG_PRINT("error",
("Found too long binary packed key: %u of %u at 0x%lx",
length, keyinfo->maxlength, (long) *page_pos));
- DBUG_DUMP("key",(char*) *page_pos,16);
+ DBUG_DUMP("key",*page_pos,16);
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
DBUG_RETURN(0); /* Wrong key */
@@ -1238,7 +1238,7 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
{
int error;
uint nod_flag;
- uchar lastkey[MI_MAX_KEY_BUFF];
+ uchar lastkey[HA_MAX_KEY_BUFF];
DBUG_ENTER("_mi_search_next");
DBUG_PRINT("enter",("nextflag: %u lastpos: %lu int_keypos: %lu",
nextflag, (ulong) info->lastpos,
@@ -1802,13 +1802,13 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
}
/* Check how many characters are identical to next key */
key= s_temp->key+next_length;
+ s_temp->prev_length= 0;
while (*key++ == *next_key++) ;
if ((ref_length= (uint) (key - s_temp->key)-1) == next_length)
{
s_temp->next_key_pos=0;
return length; /* can't pack next key */
}
- s_temp->prev_length=0;
s_temp->n_ref_length=ref_length;
return (int) (length-(ref_length - next_length) - next_length_pack +
get_pack_length(ref_length));
diff --git a/storage/myisam/mi_test1.c b/storage/myisam/mi_test1.c
index f218bf4e77f..8e491823939 100644
--- a/storage/myisam/mi_test1.c
+++ b/storage/myisam/mi_test1.c
@@ -79,6 +79,8 @@ static int run_test(const char *filename)
recinfo[2].length= (extra_field == FIELD_BLOB ? 4 + portable_sizeof_char_ptr : 24);
if (extra_field == FIELD_VARCHAR)
recinfo[2].length+= HA_VARCHAR_PACKLENGTH(recinfo[2].length);
+ recinfo[1].null_bit= null_fields ? 2 : 0;
+
if (opt_unique)
{
recinfo[3].type=FIELD_CHECK;
@@ -630,7 +632,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
key_type= HA_KEYTYPE_VARTEXT1;
break;
case 'k':
- if (key_length < 4 || key_length > MI_MAX_KEY_LENGTH)
+ if (key_length < 4 || key_length > HA_MAX_KEY_LENGTH)
{
fprintf(stderr,"Wrong key length\n");
exit(1);
diff --git a/storage/myisam/mi_test2.c b/storage/myisam/mi_test2.c
index 23c58638166..9844126e7dd 100644
--- a/storage/myisam/mi_test2.c
+++ b/storage/myisam/mi_test2.c
@@ -18,12 +18,6 @@
#ifndef USE_MY_FUNC /* We want to be able to dbug this !! */
#define USE_MY_FUNC
#endif
-#ifdef DBUG_OFF
-#undef DBUG_OFF
-#endif
-#ifndef SAFEMALLOC
-#define SAFEMALLOC
-#endif
#include "myisamdef.h"
#include <m_ctype.h>
#include <my_bit.h>
@@ -43,7 +37,7 @@ static void copy_key(struct st_myisam_info *info,uint inx,
uchar *record,uchar *key);
static int verbose=0,testflag=0,
- first_key=0,async_io=0,key_cacheing=0,write_cacheing=0,locking=0,
+ first_key=0,async_io=0,key_cacheing=0,write_cacheing=0,do_locking=0,
rec_pointer_size=0,pack_fields=1,use_log=0,silent=0,
opt_quick_mode=0;
static int pack_seg=HA_SPACE_PACK,pack_type=HA_PACK_KEY,remove_count=-1,
@@ -222,7 +216,7 @@ int main(int argc, char *argv[])
printf("- Writing key:s\n");
if (key_cacheing)
init_key_cache(dflt_key_cache,key_cache_block_size,key_cache_size,0,0);
- if (locking)
+ if (do_locking)
mi_lock_database(file,F_WRLCK);
if (write_cacheing)
mi_extra(file,HA_EXTRA_WRITE_CACHE,0);
@@ -334,9 +328,9 @@ int main(int argc, char *argv[])
if (use_blob)
{
if (i & 1)
- put_blob_in_record(record+blob_pos,&blob_buffer);
+ put_blob_in_record(record2+blob_pos,&blob_buffer);
else
- bmove(record+blob_pos,read_record+blob_pos,8);
+ bmove(record2+blob_pos,read_record+blob_pos,8);
}
if (mi_update(file,read_record,record2))
{
@@ -606,7 +600,7 @@ int main(int argc, char *argv[])
if (mi_rsame(file,read_record2,(int) i)) goto err;
if (bcmp(read_record,read_record2,reclength) != 0)
{
- printf("is_rsame didn't find same record\n");
+ printf("mi_rsame didn't find same record\n");
goto end;
}
}
@@ -657,10 +651,10 @@ int main(int argc, char *argv[])
sprintf((char*) key2,"%6d",k);
min_key.key= key;
- min_key.length= USE_WHOLE_KEY;
+ min_key.keypart_map= HA_WHOLE_KEY;
min_key.flag= HA_READ_AFTER_KEY;
max_key.key= key2;
- max_key.length= USE_WHOLE_KEY;
+ max_key.keypart_map= HA_WHOLE_KEY;
max_key.flag= HA_READ_BEFORE_KEY;
range_records= mi_records_in_range(file, 0, &min_key, &max_key);
records=0;
@@ -713,7 +707,7 @@ int main(int argc, char *argv[])
printf("- mi_extra(CACHE) + mi_rrnd.... + mi_extra(NO_CACHE)\n");
if (mi_reset(file) || mi_extra(file,HA_EXTRA_CACHE,0))
{
- if (locking || (!use_blob && !pack_fields))
+ if (do_locking || (!use_blob && !pack_fields))
{
puts("got error from mi_extra(HA_EXTRA_CACHE)");
goto end;
@@ -780,9 +774,8 @@ int main(int argc, char *argv[])
{
ulong blob_length,pos;
uchar *ptr;
- longget(blob_length,read_record+blob_pos+4);
- ptr=(uchar*) blob_length;
- longget(blob_length,read_record+blob_pos);
+ memcpy_fixed(&ptr, read_record+blob_pos+4, sizeof(ptr));
+ blob_length= uint4korr(read_record+blob_pos);
for (pos=0 ; pos < blob_length ; pos++)
{
if (ptr[pos] != (uchar) (blob_length+pos))
@@ -834,9 +827,9 @@ end:
puts("Write cacheing used");
if (write_cacheing)
puts("quick mode");
- if (async_io && locking)
+ if (async_io && do_locking)
puts("Asyncron io with locking used");
- else if (locking)
+ else if (do_locking)
puts("Locking used");
if (use_blob)
puts("blobs used");
@@ -905,7 +898,7 @@ static void get_options(int argc, char **argv)
use_log=1;
break;
case 'L':
- locking=1;
+ do_locking=1;
break;
case 'A': /* use asyncron io */
async_io=1;
diff --git a/storage/myisam/mi_test3.c b/storage/myisam/mi_test3.c
index 5bdc33b8518..93f2b10fd3e 100644
--- a/storage/myisam/mi_test3.c
+++ b/storage/myisam/mi_test3.c
@@ -15,7 +15,7 @@
/* Test av locking */
-#ifndef __NETWARE__
+#if !(defined (__NETWARE_) || defined (_WIN32)) /*no fork() in Windows*/
#include "myisam.h"
#include <sys/types.h>
@@ -488,14 +488,14 @@ int test_update(MI_INFO *file,int id,int lock_type)
return 0;
}
-#else /* __NETWARE__ */
+#else /* __NETWARE__ || __WIN__*/
#include <stdio.h>
-main()
+int main()
{
- fprintf(stderr,"this test has not been ported to NetWare\n");
+ fprintf(stderr,"this test has not been ported to NetWare or Windows\n");
return 0;
}
-#endif /* __NETWARE__ */
+#endif /* __NETWARE__ || __WIN__ */
diff --git a/storage/myisam/mi_update.c b/storage/myisam/mi_update.c
index 2ac405dd785..b252892a96d 100644
--- a/storage/myisam/mi_update.c
+++ b/storage/myisam/mi_update.c
@@ -23,7 +23,7 @@ int mi_update(register MI_INFO *info, const uchar *oldrec, uchar *newrec)
int flag,key_changed,save_errno;
reg3 my_off_t pos;
uint i;
- uchar old_key[MI_MAX_KEY_BUFF],*new_key;
+ uchar old_key[HA_MAX_KEY_BUFF],*new_key;
my_bool auto_key_changed=0;
ulonglong changed;
MYISAM_SHARE *share=info->s;
diff --git a/storage/myisam/mi_write.c b/storage/myisam/mi_write.c
index be67b7a5982..6d9dea51177 100644
--- a/storage/myisam/mi_write.c
+++ b/storage/myisam/mi_write.c
@@ -272,7 +272,7 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
comp_flag=SEARCH_BIGGER; /* Put after same key */
else if (keyinfo->flag & (HA_NOSAME|HA_FULLTEXT))
{
- comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */
+ comp_flag=SEARCH_FIND | SEARCH_UPDATE | SEARCH_INSERT; /* No duplicates */
if (keyinfo->flag & HA_NULL_ARE_EQUAL)
comp_flag|= SEARCH_NULL_ARE_EQUAL;
}
@@ -346,7 +346,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
int error,flag;
uint nod_flag, search_key_length;
uchar *temp_buff,*keypos;
- uchar keybuff[MI_MAX_KEY_BUFF];
+ uchar keybuff[HA_MAX_KEY_BUFF];
my_bool was_last_key;
my_off_t next_page, dupp_key_pos;
DBUG_ENTER("w_search");
@@ -354,7 +354,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
- MI_MAX_KEY_BUFF*2)))
+ HA_MAX_KEY_BUFF*2)))
DBUG_RETURN(-1);
if (!_mi_fetch_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff,0))
goto err;
@@ -707,7 +707,7 @@ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
{
uint keys,length,last_length,key_ref_length;
uchar *end,*lastpos,*prevpos;
- uchar key_buff[MI_MAX_KEY_BUFF];
+ uchar key_buff[HA_MAX_KEY_BUFF];
DBUG_ENTER("_mi_find_last_pos");
key_ref_length=2;
@@ -764,7 +764,7 @@ static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
length,keys;
uchar *pos,*buff,*extra_buff;
my_off_t next_page,new_pos;
- uchar tmp_part_key[MI_MAX_KEY_BUFF];
+ uchar tmp_part_key[HA_MAX_KEY_BUFF];
DBUG_ENTER("_mi_balance_page");
k_length=keyinfo->keylength;
@@ -930,7 +930,7 @@ static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
Probably I can use info->lastkey here, but I'm not sure,
and to be safe I'd better use local lastkey.
*/
- uchar lastkey[MI_MAX_KEY_BUFF];
+ uchar lastkey[HA_MAX_KEY_BUFF];
uint keylen;
MI_KEYDEF *keyinfo;
diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c
index f8fcdcb6fab..6fbc67dbc70 100644
--- a/storage/myisam/myisamchk.c
+++ b/storage/myisam/myisamchk.c
@@ -16,7 +16,6 @@
/* Describe, check and repair of MyISAM tables */
#include "fulltext.h"
-
#include <m_ctype.h>
#include <stdarg.h>
#include <my_getopt.h>
@@ -41,7 +40,6 @@ static const char *set_collation_name, *opt_tmpdir;
static CHARSET_INFO *set_collation;
static long opt_myisam_block_size;
static long opt_key_cache_block_size;
-static const char *my_progname_short;
static int stopwords_inited= 0;
static MY_TMPDIR myisamchk_tmpdir;
@@ -68,9 +66,9 @@ static const char *myisam_stats_method_str="nulls_unequal";
static void get_options(int *argc,char * * *argv);
static void print_version(void);
static void usage(void);
-static int myisamchk(MI_CHECK *param, char *filename);
-static void descript(MI_CHECK *param, register MI_INFO *info, char * name);
-static int mi_sort_records(MI_CHECK *param, register MI_INFO *info,
+static int myisamchk(HA_CHECK *param, char *filename);
+static void descript(HA_CHECK *param, register MI_INFO *info, char * name);
+static int mi_sort_records(HA_CHECK *param, register MI_INFO *info,
char * name, uint sort_key,
my_bool write_info, my_bool update_index);
static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
@@ -78,7 +76,7 @@ static int sort_record_index(MI_SORT_PARAM *sort_param, MI_INFO *info,
my_off_t page,uchar *buff,uint sortkey,
File new_file, my_bool update_index);
-MI_CHECK check_param;
+HA_CHECK check_param;
/* Main program */
@@ -86,7 +84,6 @@ int main(int argc, char **argv)
{
int error;
MY_INIT(argv[0]);
- my_progname_short= my_progname+dirname_length(my_progname);
myisamchk_init(&check_param);
check_param.opt_lock_memory=1; /* Lock memory if possible */
@@ -106,7 +103,7 @@ int main(int argc, char **argv)
(!(check_param.testflag & (T_REP | T_REP_BY_SORT | T_SORT_RECORDS |
T_SORT_INDEX))))
{
- uint old_testflag=check_param.testflag;
+ ulonglong old_testflag=check_param.testflag;
if (!(check_param.testflag & T_REP))
check_param.testflag|= T_REP_BY_SORT;
check_param.testflag&= ~T_EXTEND; /* Don't needed */
@@ -696,7 +693,7 @@ get_one_option(int optid,
case OPT_STATS_METHOD:
{
int method;
- enum_mi_stats_method method_conv;
+ enum_handler_stats_method method_conv;
LINT_INIT(method_conv);
myisam_stats_method_str= argument;
if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
@@ -795,10 +792,10 @@ static void get_options(register int *argc,register char ***argv)
/* Check table */
-static int myisamchk(MI_CHECK *param, char * filename)
+static int myisamchk(HA_CHECK *param, char * filename)
{
int error,lock_type,recreate;
- int rep_quick= param->testflag & (T_QUICK | T_FORCE_UNIQUENESS);
+ int rep_quick= test(param->testflag & (T_QUICK | T_FORCE_UNIQUENESS));
uint raid_chunks;
MI_INFO *info;
File datafile;
@@ -938,7 +935,7 @@ static int myisamchk(MI_CHECK *param, char * filename)
param->testflag|=T_REP_BY_SORT; /* if only STATISTICS */
if (!(param->testflag & T_SILENT))
printf("- '%s' has old table-format. Recreating index\n",filename);
- rep_quick|=T_QUICK;
+ rep_quick= 1;
}
share=info->s;
share->tot_locks-= share->r_locks;
@@ -1114,7 +1111,7 @@ static int myisamchk(MI_CHECK *param, char * filename)
if ((info->s->options & (HA_OPTION_PACK_RECORD |
HA_OPTION_COMPRESS_RECORD)) ||
(param->testflag & (T_EXTEND | T_MEDIUM)))
- error|=chk_data_link(param, info, param->testflag & T_EXTEND);
+ error|=chk_data_link(param, info, test(param->testflag & T_EXTEND));
error|=flush_blocks(param, share->key_cache, share->kfile);
VOID(end_io_cache(&param->read_cache));
}
@@ -1200,7 +1197,7 @@ end2:
/* Write info about table */
-static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
+static void descript(HA_CHECK *param, register MI_INFO *info, char * name)
{
uint key,keyseg_nr,field,start;
reg3 MI_KEYDEF *keyinfo;
@@ -1465,7 +1462,7 @@ static void descript(MI_CHECK *param, register MI_INFO *info, char * name)
/* Sort records according to one key */
-static int mi_sort_records(MI_CHECK *param,
+static int mi_sort_records(HA_CHECK *param,
register MI_INFO *info, char * name,
uint sort_key,
my_bool write_info,
@@ -1479,7 +1476,7 @@ static int mi_sort_records(MI_CHECK *param,
ha_rows old_record_count;
MYISAM_SHARE *share=info->s;
char llbuff[22],llbuff2[22];
- SORT_INFO sort_info;
+ MI_SORT_INFO sort_info;
MI_SORT_PARAM sort_param;
DBUG_ENTER("sort_records");
@@ -1655,10 +1652,10 @@ static int sort_record_index(MI_SORT_PARAM *sort_param,MI_INFO *info,
uint nod_flag,used_length,key_length;
uchar *temp_buff,*keypos,*endpos;
my_off_t next_page,rec_pos;
- uchar lastkey[MI_MAX_KEY_BUFF];
+ uchar lastkey[HA_MAX_KEY_BUFF];
char llbuff[22];
- SORT_INFO *sort_info= sort_param->sort_info;
- MI_CHECK *param=sort_info->param;
+ MI_SORT_INFO *sort_info= sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
DBUG_ENTER("sort_record_index");
nod_flag=mi_test_if_nod(buff);
@@ -1746,7 +1743,7 @@ err:
static int not_killed= 0;
-volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
+volatile int *killed_ptr(HA_CHECK *param __attribute__((unused)))
{
return &not_killed; /* always NULL */
}
@@ -1754,7 +1751,7 @@ volatile int *killed_ptr(MI_CHECK *param __attribute__((unused)))
/* print warnings and errors */
/* VARARGS */
-void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
+void mi_check_print_info(HA_CHECK *param __attribute__((unused)),
const char *fmt,...)
{
va_list args;
@@ -1767,7 +1764,7 @@ void mi_check_print_info(MI_CHECK *param __attribute__((unused)),
/* VARARGS */
-void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
+void mi_check_print_warning(HA_CHECK *param, const char *fmt,...)
{
va_list args;
DBUG_ENTER("mi_check_print_warning");
@@ -1792,7 +1789,7 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
/* VARARGS */
-void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
+void mi_check_print_error(HA_CHECK *param, const char *fmt,...)
{
va_list args;
DBUG_ENTER("mi_check_print_error");
diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h
index 9af3f652c5f..6ab7451196a 100644
--- a/storage/myisam/myisamdef.h
+++ b/storage/myisam/myisamdef.h
@@ -15,8 +15,8 @@
/* This file is included by all internal myisam files */
-#include "myisam.h" /* Structs & some defines */
-#include "myisampack.h" /* packing of keys */
+#include "myisam.h" /* Structs & some defines */
+#include "myisampack.h" /* packing of keys */
#include <my_tree.h>
#ifdef THREAD
#include <my_pthread.h>
@@ -26,15 +26,16 @@
#endif
#if defined(my_write) && !defined(MAP_TO_USE_RAID)
-#undef my_write /* undef map from my_nosys; We need test-if-disk full */
+/* undef map from my_nosys; We need test-if-disk full */
+#undef my_write
#endif
typedef struct st_mi_status_info
{
- ha_rows records; /* Rows in table */
- ha_rows del; /* Removed rows */
- my_off_t empty; /* lost space in datafile */
- my_off_t key_empty; /* lost space in indexfile */
+ ha_rows records; /* Rows in table */
+ ha_rows del; /* Removed rows */
+ my_off_t empty; /* lost space in datafile */
+ my_off_t key_empty; /* lost space in indexfile */
my_off_t key_file_length;
my_off_t data_file_length;
ha_checksum checksum;
@@ -42,153 +43,158 @@ typedef struct st_mi_status_info
typedef struct st_mi_state_info
{
- struct { /* Fileheader */
+ struct
+ { /* Fileheader */
uchar file_version[4];
uchar options[2];
uchar header_length[2];
uchar state_info_length[2];
uchar base_info_length[2];
uchar base_pos[2];
- uchar key_parts[2]; /* Key parts */
- uchar unique_key_parts[2]; /* Key parts + unique parts */
- uchar keys; /* number of keys in file */
- uchar uniques; /* number of UNIQUE definitions */
- uchar language; /* Language for indexes */
- uchar max_block_size_index; /* max keyblock size */
+ uchar key_parts[2]; /* Key parts */
+ uchar unique_key_parts[2]; /* Key parts + unique parts */
+ uchar keys; /* number of keys in file */
+ uchar uniques; /* number of UNIQUE definitions */
+ uchar language; /* Language for indexes */
+ uchar max_block_size_index; /* max keyblock size */
uchar fulltext_keys;
uchar not_used; /* To align to 8 */
} header;
MI_STATUS_INFO state;
- ha_rows split; /* number of split blocks */
- my_off_t dellink; /* Link to next removed block */
+ ha_rows split; /* number of split blocks */
+ my_off_t dellink; /* Link to next removed block */
ulonglong auto_increment;
- ulong process; /* process that updated table last */
- ulong unique; /* Unique number for this process */
- ulong update_count; /* Updated for each write lock */
+ ulong process; /* process that updated table last */
+ ulong unique; /* Unique number for this process */
+ ulong update_count; /* Updated for each write lock */
ulong status;
ulong *rec_per_key_part;
- my_off_t *key_root; /* Start of key trees */
- my_off_t *key_del; /* delete links for trees */
- my_off_t rec_per_key_rows; /* Rows when calculating rec_per_key */
-
- ulong sec_index_changed; /* Updated when new sec_index */
- ulong sec_index_used; /* which extra index are in use */
- ulonglong key_map; /* Which keys are in use */
ha_checksum checksum; /* Table checksum */
- ulong version; /* timestamp of create */
- time_t create_time; /* Time when created database */
- time_t recover_time; /* Time for last recover */
- time_t check_time; /* Time for last check */
- uint sortkey; /* sorted by this key (not used) */
+ my_off_t *key_root; /* Start of key trees */
+ my_off_t *key_del; /* delete links for trees */
+ my_off_t rec_per_key_rows; /* Rows when calculating rec_per_key */
+
+ ulong sec_index_changed; /* Updated when new sec_index */
+ ulong sec_index_used; /* which extra index are in use */
+ ulonglong key_map; /* Which keys are in use */
+ ulong version; /* timestamp of create */
+ time_t create_time; /* Time when created database */
+ time_t recover_time; /* Time for last recover */
+ time_t check_time; /* Time for last check */
+ uint sortkey; /* sorted by this key (not used) */
uint open_count;
- uint8 changed; /* Changed since myisamchk */
+ uint8 changed; /* Changed since myisamchk */
/* the following isn't saved on disk */
- uint state_diff_length; /* Should be 0 */
- uint state_length; /* Length of state header in file */
+ uint state_diff_length; /* Should be 0 */
+ uint state_length; /* Length of state header in file */
ulong *key_info;
} MI_STATE_INFO;
-#define MI_STATE_INFO_SIZE (24+14*8+7*4+2*2+8)
-#define MI_STATE_KEY_SIZE 8
+#define MI_STATE_INFO_SIZE (24+14*8+7*4+2*2+8)
+#define MI_STATE_KEY_SIZE 8
#define MI_STATE_KEYBLOCK_SIZE 8
-#define MI_STATE_KEYSEG_SIZE 4
-#define MI_STATE_EXTRA_SIZE ((MI_MAX_KEY+MI_MAX_KEY_BLOCK_SIZE)*MI_STATE_KEY_SIZE + MI_MAX_KEY*MI_MAX_KEY_SEG*MI_STATE_KEYSEG_SIZE)
-#define MI_KEYDEF_SIZE (2+ 5*2)
-#define MI_UNIQUEDEF_SIZE (2+1+1)
-#define HA_KEYSEG_SIZE (6+ 2*2 + 4*2)
-#define MI_COLUMNDEF_SIZE (2*3+1)
-#define MI_BASE_INFO_SIZE (5*8 + 8*4 + 4 + 4*2 + 16)
-#define MI_INDEX_BLOCK_MARGIN 16 /* Safety margin for .MYI tables */
+#define MI_STATE_KEYSEG_SIZE 4
+#define MI_STATE_EXTRA_SIZE ((MI_MAX_KEY+MI_MAX_KEY_BLOCK_SIZE)*MI_STATE_KEY_SIZE + MI_MAX_KEY*HA_MAX_KEY_SEG*MI_STATE_KEYSEG_SIZE)
+#define MI_KEYDEF_SIZE (2+ 5*2)
+#define MI_UNIQUEDEF_SIZE (2+1+1)
+#define HA_KEYSEG_SIZE (6+ 2*2 + 4*2)
+#define MI_COLUMNDEF_SIZE (2*3+1)
+#define MI_BASE_INFO_SIZE (5*8 + 8*4 + 4 + 4*2 + 16)
+#define MI_INDEX_BLOCK_MARGIN 16 /* Safety margin for .MYI tables */
typedef struct st_mi_base_info
{
- my_off_t keystart; /* Start of keys */
+ my_off_t keystart; /* Start of keys */
my_off_t max_data_file_length;
my_off_t max_key_file_length;
my_off_t margin_key_file_length;
- ha_rows records,reloc; /* Create information */
- ulong mean_row_length; /* Create information */
- ulong reclength; /* length of unpacked record */
- ulong pack_reclength; /* Length of full packed rec. */
+ ha_rows records, reloc; /* Create information */
+ ulong mean_row_length; /* Create information */
+ ulong reclength; /* length of unpacked record */
+ ulong pack_reclength; /* Length of full packed rec. */
ulong min_pack_length;
- ulong max_pack_length; /* Max possibly length of packed rec.*/
+ ulong max_pack_length; /* Max possibly length of packed rec.*/
ulong min_block_length;
- ulong fields, /* fields in table */
- pack_fields; /* packed fields in table */
- uint rec_reflength; /* = 2-8 */
- uint key_reflength; /* = 2-8 */
- uint keys; /* same as in state.header */
- uint auto_key; /* Which key-1 is a auto key */
- uint blobs; /* Number of blobs */
- uint pack_bits; /* Length of packed bits */
- uint max_key_block_length; /* Max block length */
- uint max_key_length; /* Max key length */
+ ulong fields, /* fields in table */
+ pack_fields; /* packed fields in table */
+ uint rec_reflength; /* = 2-8 */
+ uint key_reflength; /* = 2-8 */
+ uint keys; /* same as in state.header */
+ uint auto_key; /* Which key-1 is a auto key */
+ uint blobs; /* Number of blobs */
+ uint pack_bits; /* Length of packed bits */
+ uint max_key_block_length; /* Max block length */
+ uint max_key_length; /* Max key length */
/* Extra allocation when using dynamic record format */
uint extra_alloc_bytes;
uint extra_alloc_procent;
/* Info about raid */
- uint raid_type,raid_chunks;
+ uint raid_type, raid_chunks;
ulong raid_chunksize;
/* The following are from the header */
- uint key_parts,all_key_parts;
+ uint key_parts, all_key_parts;
} MI_BASE_INFO;
- /* Structs used intern in database */
+ /* Structs used intern in database */
-typedef struct st_mi_blob /* Info of record */
+typedef struct st_mi_blob /* Info of record */
{
- ulong offset; /* Offset to blob in record */
- uint pack_length; /* Type of packed length */
- ulong length; /* Calc:ed for each record */
+ ulong offset; /* Offset to blob in record */
+ uint pack_length; /* Type of packed length */
+ ulong length; /* Calc:ed for each record */
} MI_BLOB;
-typedef struct st_mi_isam_pack {
+typedef struct st_mi_isam_pack
+{
ulong header_length;
uint ref_length;
uchar version;
} MI_PACK;
-#define MAX_NONMAPPED_INSERTS 1000
+#define MAX_NONMAPPED_INSERTS 1000
-typedef struct st_mi_isam_share { /* Shared between opens */
+typedef struct st_mi_isam_share
+{ /* Shared between opens */
MI_STATE_INFO state;
MI_BASE_INFO base;
- MI_KEYDEF ft2_keyinfo; /* Second-level ft-key definition */
- MI_KEYDEF *keyinfo; /* Key definitions */
- MI_UNIQUEDEF *uniqueinfo; /* unique definitions */
- HA_KEYSEG *keyparts; /* key part info */
- MI_COLUMNDEF *rec; /* Pointer to field information */
- MI_PACK pack; /* Data about packed records */
- MI_BLOB *blobs; /* Pointer to blobs */
- char *unique_file_name; /* realpath() of index file */
- char *data_file_name, /* Resolved path names from symlinks */
- *index_file_name;
- uchar *file_map; /* mem-map of file if possible */
- KEY_CACHE *key_cache; /* ref to the current key cache */
+ MI_KEYDEF ft2_keyinfo; /* Second-level ft-key definition */
+ MI_KEYDEF *keyinfo; /* Key definitions */
+ MI_UNIQUEDEF *uniqueinfo; /* unique definitions */
+ HA_KEYSEG *keyparts; /* key part info */
+ MI_COLUMNDEF *rec; /* Pointer to field information */
+ MI_PACK pack; /* Data about packed records */
+ MI_BLOB *blobs; /* Pointer to blobs */
+ char *unique_file_name; /* realpath() of index file */
+ char *data_file_name, /* Resolved path names from symlinks */
+ *index_file_name;
+ uchar *file_map; /* mem-map of file if possible */
+ KEY_CACHE *key_cache; /* ref to the current key cache */
MI_DECODE_TREE *decode_trees;
uint16 *decode_tables;
- int (*read_record)(struct st_myisam_info*, my_off_t, uchar*);
- int (*write_record)(struct st_myisam_info*, const uchar*);
- int (*update_record)(struct st_myisam_info*, my_off_t, const uchar*);
- int (*delete_record)(struct st_myisam_info*);
- int (*read_rnd)(struct st_myisam_info*, uchar*, my_off_t, my_bool);
- int (*compare_record)(struct st_myisam_info*, const uchar *);
/* Function to use for a row checksum. */
- ha_checksum (*calc_checksum)(struct st_myisam_info*, const uchar *);
- int (*compare_unique)(struct st_myisam_info*, MI_UNIQUEDEF *,
- const uchar *record, my_off_t pos);
- size_t (*file_read)(MI_INFO *, uchar *, size_t, my_off_t, myf);
- size_t (*file_write)(MI_INFO *, const uchar *, size_t, my_off_t, myf);
+ int(*read_record) (struct st_myisam_info *, my_off_t, uchar*);
+ int(*write_record) (struct st_myisam_info *, const uchar*);
+ int(*update_record) (struct st_myisam_info *, my_off_t, const uchar*);
+ int(*delete_record) (struct st_myisam_info *);
+ int(*read_rnd) (struct st_myisam_info *, uchar*, my_off_t, my_bool);
+ int(*compare_record) (struct st_myisam_info *, const uchar*);
+ ha_checksum(*calc_checksum) (struct st_myisam_info *, const uchar*);
+ /* calculate checksum for a row during check table */
+ ha_checksum(*calc_check_checksum)(struct st_myisam_info *, const uchar *);
+ int(*compare_unique) (struct st_myisam_info *, MI_UNIQUEDEF *,
+ const uchar *record, my_off_t pos);
+ size_t (*file_read) (MI_INFO *, uchar *, size_t, my_off_t, myf);
+ size_t (*file_write) (MI_INFO *, const uchar *, size_t, my_off_t, myf);
invalidator_by_filename invalidator; /* query cache invalidator */
- ulong this_process; /* processid */
- ulong last_process; /* For table-change-check */
- ulong last_version; /* Version on start */
- ulong options; /* Options used */
- ulong min_pack_length; /* Theese are used by packed data */
+ ulong this_process; /* processid */
+ ulong last_process; /* For table-change-check */
+ ulong last_version; /* Version on start */
+ ulong options; /* Options used */
+ ulong min_pack_length; /* Theese are used by packed data */
ulong max_pack_length;
ulong state_diff_length;
uint rec_reflength; /* rec_reflength in use now */
@@ -204,185 +210,130 @@ typedef struct st_mi_isam_share { /* Shared between opens */
enum data_file_type data_file_type;
/* Below flag is needed to make log tables work with concurrent insert */
my_bool is_log_table;
+ /* This is 1 if they table checksum is of old type */
+ my_bool has_null_fields;
+ my_bool has_varchar_fields;
- my_bool changed, /* If changed since lock */
- global_changed, /* If changed since open */
- not_flushed,
- temporary,delay_key_write,
- concurrent_insert;
+ my_bool changed, /* If changed since lock */
+ global_changed, /* If changed since open */
+ not_flushed, temporary, delay_key_write, concurrent_insert;
#ifdef THREAD
THR_LOCK lock;
- pthread_mutex_t intern_lock; /* Locking for use with _locking */
+ pthread_mutex_t intern_lock; /* Locking for use with _locking */
rw_lock_t *key_root_lock;
#endif
my_off_t mmaped_length;
- uint nonmmaped_inserts; /* counter of writing in non-mmaped
- area */
+ /* counter of writing in non-mmaped area */
+ uint nonmmaped_inserts;
rw_lock_t mmap_lock;
} MYISAM_SHARE;
-typedef uint mi_bit_type;
-
-typedef struct st_mi_bit_buff { /* Used for packing of record */
- mi_bit_type current_byte;
- uint bits;
- uchar *pos,*end,*blob_pos,*blob_end;
- uint error;
-} MI_BIT_BUFF;
-
-struct st_myisam_info {
- MYISAM_SHARE *s; /* Shared between open:s */
- MI_STATUS_INFO *state,save_state;
- MI_BLOB *blobs; /* Pointer to blobs */
- MI_BIT_BUFF bit_buff;
+struct st_myisam_info
+{
+ MYISAM_SHARE *s; /* Shared between open:s */
+ MI_STATUS_INFO *state, save_state;
+ MI_BLOB *blobs; /* Pointer to blobs */
+ MI_BIT_BUFF bit_buff;
/* accumulate indexfile changes between write's */
- TREE *bulk_insert;
+ TREE *bulk_insert;
DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
MEM_ROOT ft_memroot; /* used by the parser */
- MYSQL_FTPARSER_PARAM *ftparser_param; /* share info between init/deinit */
- char *filename; /* parameter to open filename */
- uchar *buff, /* Temp area for key */
- *lastkey,*lastkey2; /* Last used search key */
- uchar *first_mbr_key; /* Searhed spatial key */
- uchar *rec_buff; /* Tempbuff for recordpack */
- uchar *int_keypos, /* Save position for next/previous */
- *int_maxpos; /* -""- */
- uint int_nod_flag; /* -""- */
- uint32 int_keytree_version; /* -""- */
- int (*read_record)(struct st_myisam_info*, my_off_t, uchar*);
+ MYSQL_FTPARSER_PARAM *ftparser_param; /* share info between init/deinit */
+ char *filename; /* parameter to open filename */
+ uchar *buff, /* Temp area for key */
+ *lastkey, *lastkey2; /* Last used search key */
+ uchar *first_mbr_key; /* Searhed spatial key */
+ uchar *rec_buff; /* Tempbuff for recordpack */
+ uchar *int_keypos, /* Save position for next/previous */
+ *int_maxpos; /* -""- */
+ uint int_nod_flag; /* -""- */
+ uint32 int_keytree_version; /* -""- */
+ int(*read_record) (struct st_myisam_info *, my_off_t, uchar *);
invalidator_by_filename invalidator; /* query cache invalidator */
- ulong this_unique; /* uniq filenumber or thread */
- ulong last_unique; /* last unique number */
- ulong this_loop; /* counter for this open */
- ulong last_loop; /* last used counter */
- my_off_t lastpos, /* Last record position */
- nextpos; /* Position to next record */
+ ulong this_unique; /* uniq filenumber or thread */
+ ulong last_unique; /* last unique number */
+ ulong this_loop; /* counter for this open */
+ ulong last_loop; /* last used counter */
+ my_off_t lastpos, /* Last record position */
+ nextpos; /* Position to next record */
my_off_t save_lastpos;
- my_off_t pos; /* Intern variable */
- my_off_t last_keypage; /* Last key page read */
- my_off_t last_search_keypage; /* Last keypage when searching */
+ my_off_t pos; /* Intern variable */
+ my_off_t last_keypage; /* Last key page read */
+ my_off_t last_search_keypage; /* Last keypage when searching */
my_off_t dupp_key_pos;
ha_checksum checksum; /* Temp storage for row checksum */
- /* QQ: the folloing two xxx_length fields should be removed,
- as they are not compatible with parallel repair */
- ulong packed_length,blob_length; /* Length of found, packed record */
- int dfile; /* The datafile */
- uint opt_flag; /* Optim. for space/speed */
- uint update; /* If file changed since open */
- int lastinx; /* Last used index */
- uint lastkey_length; /* Length of key in lastkey */
- uint last_rkey_length; /* Last length in mi_rkey() */
+ /*
+ QQ: the folloing two xxx_length fields should be removed,
+ as they are not compatible with parallel repair
+ */
+ ulong packed_length, blob_length; /* Length of found, packed record */
+ int dfile; /* The datafile */
+ uint opt_flag; /* Optim. for space/speed */
+ uint update; /* If file changed since open */
+ int lastinx; /* Last used index */
+ uint lastkey_length; /* Length of key in lastkey */
+ uint last_rkey_length; /* Last length in mi_rkey() */
enum ha_rkey_function last_key_func; /* CONTAIN, OVERLAP, etc */
- uint save_lastkey_length;
- uint pack_key_length; /* For MYISAMMRG */
+ uint save_lastkey_length;
+ uint pack_key_length; /* For MYISAMMRG */
uint16 last_used_keyseg; /* For MyISAMMRG */
- int errkey; /* Got last error on this key */
- int lock_type; /* How database was locked */
- int tmp_lock_type; /* When locked by readinfo */
- uint data_changed; /* Somebody has changed data */
- uint save_update; /* When using KEY_READ */
- int save_lastinx;
- LIST open_list;
- IO_CACHE rec_cache; /* When cacheing records */
- uint preload_buff_size; /* When preloading indexes */
- myf lock_wait; /* is 0 or MY_DONT_WAIT */
- my_bool was_locked; /* Was locked in panic */
- my_bool append_insert_at_end; /* Set if concurrent insert */
+ int errkey; /* Got last error on this key */
+ int lock_type; /* How database was locked */
+ int tmp_lock_type; /* When locked by readinfo */
+ uint data_changed; /* Somebody has changed data */
+ uint save_update; /* When using KEY_READ */
+ int save_lastinx;
+ LIST open_list;
+ IO_CACHE rec_cache; /* When cacheing records */
+ uint preload_buff_size; /* When preloading indexes */
+ myf lock_wait; /* is 0 or MY_SHORT_WAIT */
+ my_bool was_locked; /* Was locked in panic */
+ my_bool append_insert_at_end; /* Set if concurrent insert */
my_bool quick_mode;
- my_bool page_changed; /* If info->buff can't be used for rnext */
- my_bool buff_used; /* If info->buff has to be reread for rnext */
- my_bool once_flags; /* For MYISAMMRG */
+ /* If info->buff can't be used for rnext */
+ my_bool page_changed;
+ /* If info->buff has to be reread for rnext */
+ my_bool buff_used;
+ my_bool once_flags; /* For MYISAMMRG */
#ifdef __WIN__
my_bool owned_by_merge; /* This MyISAM table is part of a merge union */
#endif
#ifdef THREAD
THR_LOCK_DATA lock;
#endif
- uchar *rtree_recursion_state; /* For RTREE */
- int rtree_recursion_depth;
+ uchar *rtree_recursion_state; /* For RTREE */
+ int rtree_recursion_depth;
};
-typedef struct st_buffpek {
- my_off_t file_pos; /* Where we are in the sort file */
- uchar *base,*key; /* Key pointers */
- ha_rows count; /* Number of rows in table */
- ulong mem_count; /* numbers of keys in memory */
- ulong max_keys; /* Max keys in buffert */
-} BUFFPEK;
-
-typedef struct st_mi_sort_param
-{
- pthread_t thr;
- IO_CACHE read_cache, tempfile, tempfile_for_exceptions;
- DYNAMIC_ARRAY buffpek;
- MI_BIT_BUFF bit_buff; /* For parallel repair of packrec. */
-
- /*
- The next two are used to collect statistics, see update_key_parts for
- description.
- */
- ulonglong unique[MI_MAX_KEY_SEG+1];
- ulonglong notnull[MI_MAX_KEY_SEG+1];
-
- my_off_t pos,max_pos,filepos,start_recpos;
- uint key, key_length,real_key_length,sortbuff_size;
- uint maxbuffers, keys, find_length, sort_keys_length;
- my_bool fix_datafile, master;
- my_bool calc_checksum; /* calculate table checksum */
- MI_KEYDEF *keyinfo;
- HA_KEYSEG *seg;
- SORT_INFO *sort_info;
- uchar **sort_keys;
- uchar *rec_buff;
- void *wordlist, *wordptr;
- MEM_ROOT wordroot;
- uchar *record;
- MY_TMPDIR *tmpdir;
- int (*key_cmp)(struct st_mi_sort_param *, const void *, const void *);
- int (*key_read)(struct st_mi_sort_param *,void *);
- int (*key_write)(struct st_mi_sort_param *, const void *);
- void (*lock_in_memory)(MI_CHECK *);
- NEAR int (*write_keys)(struct st_mi_sort_param *, register uchar **,
- uint , struct st_buffpek *, IO_CACHE *);
- NEAR uint (*read_to_buffer)(IO_CACHE *,struct st_buffpek *, uint);
- NEAR int (*write_key)(struct st_mi_sort_param *, IO_CACHE *,uchar *,
- uint, uint);
-} MI_SORT_PARAM;
-
- /* Some defines used by isam-funktions */
-
-#define USE_WHOLE_KEY MI_MAX_KEY_BUFF*2 /* Use whole key in _mi_search() */
-#define F_EXTRA_LCK -1
-
- /* bits in opt_flag */
-#define MEMMAP_USED 32
+#define USE_WHOLE_KEY HA_MAX_KEY_BUFF*2 /* Use whole key in _mi_search() */
+#define F_EXTRA_LCK -1
+/* bits in opt_flag */
+#define MEMMAP_USED 32
#define REMEMBER_OLD_POS 64
-#define WRITEINFO_UPDATE_KEYFILE 1
-#define WRITEINFO_NO_UNLOCK 2
+#define WRITEINFO_UPDATE_KEYFILE 1
+#define WRITEINFO_NO_UNLOCK 2
- /* once_flags */
+/* once_flags */
#define USE_PACKED_KEYS 1
#define RRND_PRESERVE_LASTINX 2
- /* bits in state.changed */
-
-#define STATE_CHANGED 1
-#define STATE_CRASHED 2
+/* bits in state.changed */
+#define STATE_CHANGED 1
+#define STATE_CRASHED 2
#define STATE_CRASHED_ON_REPAIR 4
-#define STATE_NOT_ANALYZED 8
+#define STATE_NOT_ANALYZED 8
#define STATE_NOT_OPTIMIZED_KEYS 16
-#define STATE_NOT_SORTED_PAGES 32
+#define STATE_NOT_SORTED_PAGES 32
- /* options to mi_read_cache */
+/* options to mi_read_cache */
+#define READING_NEXT 1
+#define READING_HEADER 2
-#define READING_NEXT 1
-#define READING_HEADER 2
-
-#define mi_getint(x) ((uint) mi_uint2korr(x) & 32767)
+#define mi_getint(x) ((uint) mi_uint2korr(x) & 32767)
#define mi_putint(x,y,nod) { uint16 boh=(nod ? (uint16) 32768 : 0) + (uint16) (y);\
- mi_int2store(x,boh); }
+ mi_int2store(x,boh); }
#define mi_test_if_nod(x) (x[0] & 128 ? info->s->base.key_reflength : 0)
#define mi_mark_crashed(x) do{(x)->s->state.changed|= STATE_CRASHED; \
DBUG_PRINT("error", ("Marked table crashed")); \
@@ -423,39 +374,39 @@ typedef struct st_mi_sort_param
#define get_pack_length(length) ((length) >= 255 ? 3 : 1)
-#define MI_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
-#define MI_EXTEND_BLOCK_LENGTH 20 /* Don't use to small record-blocks */
-#define MI_SPLIT_LENGTH ((MI_EXTEND_BLOCK_LENGTH+4)*2)
-#define MI_MAX_DYN_BLOCK_HEADER 20 /* Max prefix of record-block */
+#define MI_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
+#define MI_EXTEND_BLOCK_LENGTH 20 /* Don't use to small record-blocks */
+#define MI_SPLIT_LENGTH ((MI_EXTEND_BLOCK_LENGTH+4)*2)
+#define MI_MAX_DYN_BLOCK_HEADER 20 /* Max prefix of record-block */
#define MI_BLOCK_INFO_HEADER_LENGTH 20
-#define MI_DYN_DELETE_BLOCK_HEADER 20 /* length of delete-block-header */
-#define MI_DYN_MAX_BLOCK_LENGTH ((1L << 24)-4L)
-#define MI_DYN_MAX_ROW_LENGTH (MI_DYN_MAX_BLOCK_LENGTH - MI_SPLIT_LENGTH)
-#define MI_DYN_ALIGN_SIZE 4 /* Align blocks on this */
-#define MI_MAX_DYN_HEADER_BYTE 13 /* max header byte for dynamic rows */
-#define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1)))
+#define MI_DYN_DELETE_BLOCK_HEADER 20 /* length of delete-block-header */
+#define MI_DYN_MAX_BLOCK_LENGTH ((1L << 24)-4L)
+#define MI_DYN_MAX_ROW_LENGTH (MI_DYN_MAX_BLOCK_LENGTH - MI_SPLIT_LENGTH)
+#define MI_DYN_ALIGN_SIZE 4 /* Align blocks on this */
+#define MI_MAX_DYN_HEADER_BYTE 13 /* max header byte for dynamic rows */
+#define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1)))
#define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint32))
-#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
+#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
-#define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */
-#define PACK_TYPE_SPACE_FIELDS 2
-#define PACK_TYPE_ZERO_FILL 4
-#define MI_FOUND_WRONG_KEY 32738 /* Impossible value from ha_key_cmp */
+#define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */
+#define PACK_TYPE_SPACE_FIELDS 2
+#define PACK_TYPE_ZERO_FILL 4
+#define MI_FOUND_WRONG_KEY 32738 /* Impossible value from ha_key_cmp */
-#define MI_MAX_KEY_BLOCK_SIZE (MI_MAX_KEY_BLOCK_LENGTH/MI_MIN_KEY_BLOCK_LENGTH)
+#define MI_MAX_KEY_BLOCK_SIZE (MI_MAX_KEY_BLOCK_LENGTH/MI_MIN_KEY_BLOCK_LENGTH)
#define MI_BLOCK_SIZE(key_length,data_pointer,key_pointer,block_size) (((((key_length)+(data_pointer)+(key_pointer))*4+(key_pointer)+2)/(block_size)+1)*(block_size))
-#define MI_MAX_KEYPTR_SIZE 5 /* For calculating block lengths */
-#define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */
+#define MI_MAX_KEYPTR_SIZE 5 /* For calculating block lengths */
+#define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */
-#define MI_MIN_SIZE_BULK_INSERT_TREE 16384 /* this is per key */
+#define MI_MIN_SIZE_BULK_INSERT_TREE 16384 /* this is per key */
#define MI_MIN_ROWS_TO_USE_BULK_INSERT 100
#define MI_MIN_ROWS_TO_DISABLE_INDEXES 100
#define MI_MIN_ROWS_TO_USE_WRITE_CACHE 10
/* The UNIQUE check is done with a hashed long key */
-#define MI_UNIQUE_HASH_TYPE HA_KEYTYPE_ULONG_INT
+#define MI_UNIQUE_HASH_TYPE HA_KEYTYPE_ULONG_INT
#define mi_unique_store(A,B) mi_int4store((A),(B))
#ifdef THREAD
@@ -467,175 +418,180 @@ extern pthread_mutex_t THR_LOCK_myisam;
#define rw_unlock(A) {}
#endif
- /* Some extern variables */
+/* Some extern variables */
extern LIST *myisam_open_list;
-extern uchar NEAR myisam_file_magic[],NEAR myisam_pack_file_magic[];
-extern uint NEAR myisam_read_vec[],NEAR myisam_readnext_vec[];
+extern uchar NEAR myisam_file_magic[], NEAR myisam_pack_file_magic[];
+extern uint NEAR myisam_read_vec[], NEAR myisam_readnext_vec[];
extern uint myisam_quick_table_bits;
extern File myisam_log_file;
extern ulong myisam_pid;
- /* This is used by _mi_calc_xxx_key_length och _mi_store_key */
+/* This is used by _mi_calc_xxx_key_length och _mi_store_key */
typedef struct st_mi_s_param
{
- uint ref_length,key_length,
- n_ref_length,
- n_length,
- totlength,
- part_of_prev_key,prev_length,pack_marker;
- uchar *key, *prev_key,*next_key_pos;
+ uint ref_length, key_length,
+ n_ref_length,
+ n_length, totlength, part_of_prev_key, prev_length, pack_marker;
+ uchar *key, *prev_key, *next_key_pos;
my_bool store_not_null;
} MI_KEY_PARAM;
- /* Prototypes for intern functions */
+/* Prototypes for intern functions */
-extern int _mi_read_dynamic_record(MI_INFO *info,my_off_t filepos,uchar *buf);
-extern int _mi_write_dynamic_record(MI_INFO*, const uchar*);
-extern int _mi_update_dynamic_record(MI_INFO*, my_off_t, const uchar*);
+extern int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, uchar *buf);
+extern int _mi_write_dynamic_record(MI_INFO *, const uchar *);
+extern int _mi_update_dynamic_record(MI_INFO *, my_off_t, const uchar *);
extern int _mi_delete_dynamic_record(MI_INFO *info);
-extern int _mi_cmp_dynamic_record(MI_INFO *info,const uchar *record);
-extern int _mi_read_rnd_dynamic_record(MI_INFO *, uchar *,my_off_t, my_bool);
-extern int _mi_write_blob_record(MI_INFO*, const uchar*);
-extern int _mi_update_blob_record(MI_INFO*, my_off_t, const uchar*);
-extern int _mi_read_static_record(MI_INFO *info, my_off_t filepos,uchar *buf);
-extern int _mi_write_static_record(MI_INFO*, const uchar*);
-extern int _mi_update_static_record(MI_INFO*, my_off_t, const uchar*);
+extern int _mi_cmp_dynamic_record(MI_INFO *info, const uchar *record);
+extern int _mi_read_rnd_dynamic_record(MI_INFO *, uchar *, my_off_t, my_bool);
+extern int _mi_write_blob_record(MI_INFO *, const uchar *);
+extern int _mi_update_blob_record(MI_INFO *, my_off_t, const uchar *);
+extern int _mi_read_static_record(MI_INFO *info, my_off_t filepos, uchar *buf);
+extern int _mi_write_static_record(MI_INFO *, const uchar *);
+extern int _mi_update_static_record(MI_INFO *, my_off_t, const uchar *);
extern int _mi_delete_static_record(MI_INFO *info);
-extern int _mi_cmp_static_record(MI_INFO *info,const uchar *record);
-extern int _mi_read_rnd_static_record(MI_INFO*, uchar *,my_off_t, my_bool);
-extern int _mi_ck_write(MI_INFO *info,uint keynr,uchar *key,uint length);
+extern int _mi_cmp_static_record(MI_INFO *info, const uchar *record);
+extern int _mi_read_rnd_static_record(MI_INFO *, uchar *, my_off_t, my_bool);
+extern int _mi_ck_write(MI_INFO *info, uint keynr, uchar *key, uint length);
extern int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
uchar *key, uint key_length,
my_off_t *root, uint comp_flag);
-extern int _mi_enlarge_root(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, my_off_t *root);
-extern int _mi_insert(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
- uchar *anc_buff,uchar *key_pos,uchar *key_buff,
- uchar *father_buff, uchar *father_keypos,
- my_off_t father_page, my_bool insert_last);
-extern int _mi_split_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
- uchar *buff,uchar *key_buff, my_bool insert_last);
-extern uchar *_mi_find_half_pos(uint nod_flag,MI_KEYDEF *keyinfo,uchar *page,
- uchar *key,uint *return_key_length,
- uchar **after_key);
-extern int _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *key_pos, uchar *org_key,
- uchar *key_buff,
- uchar *key, MI_KEY_PARAM *s_temp);
-extern int _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *key_pos, uchar *org_key,
- uchar *key_buff,
- uchar *key, MI_KEY_PARAM *s_temp);
-extern int _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *key_pos, uchar *org_key,
- uchar *prev_key,
- uchar *key, MI_KEY_PARAM *s_temp);
-extern int _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
- uchar *key_pos,uchar *org_key,
- uchar *prev_key,
- uchar *key, MI_KEY_PARAM *s_temp);
-void _mi_store_static_key(MI_KEYDEF *keyinfo, uchar *key_pos,
- MI_KEY_PARAM *s_temp);
-void _mi_store_var_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
- MI_KEY_PARAM *s_temp);
+extern int _mi_enlarge_root(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
+ my_off_t *root);
+extern int _mi_insert(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
+ uchar *anc_buff, uchar *key_pos, uchar *key_buff,
+ uchar *father_buff, uchar *father_keypos,
+ my_off_t father_page, my_bool insert_last);
+extern int _mi_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
+ uchar *buff, uchar *key_buff, my_bool insert_last);
+extern uchar *_mi_find_half_pos(uint nod_flag, MI_KEYDEF *keyinfo,
+ uchar *page, uchar *key,
+ uint *return_key_length, uchar ** after_key);
+extern int _mi_calc_static_key_length(MI_KEYDEF *keyinfo, uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *key_buff, uchar *key,
+ MI_KEY_PARAM *s_temp);
+extern int _mi_calc_var_key_length(MI_KEYDEF *keyinfo, uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *key_buff, uchar *key,
+ MI_KEY_PARAM *s_temp);
+extern int _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo, uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *prev_key, uchar *key,
+ MI_KEY_PARAM *s_temp);
+extern int _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo, uint nod_flag,
+ uchar *key_pos, uchar *org_key,
+ uchar *prev_key, uchar *key,
+ MI_KEY_PARAM *s_temp);
+void _mi_store_static_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
+void _mi_store_var_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
#ifdef NOT_USED
-void _mi_store_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
- MI_KEY_PARAM *s_temp);
+void _mi_store_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
#endif
-void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
- MI_KEY_PARAM *s_temp);
+void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo, uchar *key_pos,
+ MI_KEY_PARAM *s_temp);
-extern int _mi_ck_delete(MI_INFO *info,uint keynr,uchar *key,uint key_length);
-extern int _mi_readinfo(MI_INFO *info,int lock_flag,int check_keybuffer);
-extern int _mi_writeinfo(MI_INFO *info,uint options);
+extern int _mi_ck_delete(MI_INFO *info, uint keynr, uchar *key,
+ uint key_length);
+extern int _mi_readinfo(MI_INFO *info, int lock_flag, int check_keybuffer);
+extern int _mi_writeinfo(MI_INFO *info, uint options);
extern int _mi_test_if_changed(MI_INFO *info);
extern int _mi_mark_file_changed(MI_INFO *info);
extern int _mi_decrement_open_count(MI_INFO *info);
-extern int _mi_check_index(MI_INFO *info,int inx);
-extern int _mi_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,uint key_len,
- uint nextflag,my_off_t pos);
-extern int _mi_bin_search(struct st_myisam_info *info,MI_KEYDEF *keyinfo,
- uchar *page,uchar *key,uint key_len,uint comp_flag,
- uchar * *ret_pos,uchar *buff, my_bool *was_last_key);
-extern int _mi_seq_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
- uchar *key,uint key_len,uint comp_flag,
- uchar **ret_pos,uchar *buff, my_bool *was_last_key);
-extern int _mi_prefix_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
- uchar *key,uint key_len,uint comp_flag,
- uchar **ret_pos,uchar *buff, my_bool *was_last_key);
-extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key);
-extern void _mi_kpointer(MI_INFO *info,uchar *buff,my_off_t pos);
-extern my_off_t _mi_dpos(MI_INFO *info, uint nod_flag,uchar *after_key);
+extern int _mi_check_index(MI_INFO *info, int inx);
+extern int _mi_search(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
+ uint key_len, uint nextflag, my_off_t pos);
+extern int _mi_bin_search(struct st_myisam_info *info, MI_KEYDEF *keyinfo,
+ uchar *page, uchar *key, uint key_len,
+ uint comp_flag, uchar **ret_pos, uchar *buff,
+ my_bool *was_last_key);
+extern int _mi_seq_search(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint key_len, uint comp_flag,
+ uchar ** ret_pos, uchar *buff,
+ my_bool *was_last_key);
+extern int _mi_prefix_search(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
+ uchar *key, uint key_len, uint comp_flag,
+ uchar ** ret_pos, uchar *buff,
+ my_bool *was_last_key);
+extern my_off_t _mi_kpos(uint nod_flag, uchar *after_key);
+extern void _mi_kpointer(MI_INFO *info, uchar *buff, my_off_t pos);
+extern my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key);
extern my_off_t _mi_rec_pos(MYISAM_SHARE *info, uchar *ptr);
-extern void _mi_dpointer(MI_INFO *info, uchar *buff,my_off_t pos);
-extern int ha_key_cmp(HA_KEYSEG *keyseg, uchar *a,uchar *b,
- uint key_length,uint nextflag,uint *diff_length);
-extern uint _mi_get_static_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar * *page,
- uchar *key);
-extern uint _mi_get_pack_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar * *page,
- uchar *key);
+extern void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos);
+extern uint _mi_get_static_key(MI_KEYDEF *keyinfo, uint nod_flag,
+ uchar **page, uchar *key);
+extern uint _mi_get_pack_key(MI_KEYDEF *keyinfo, uint nod_flag, uchar **page,
+ uchar *key);
extern uint _mi_get_binary_pack_key(MI_KEYDEF *keyinfo, uint nod_flag,
- uchar **page_pos, uchar *key);
-extern uchar *_mi_get_last_key(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *keypos,
- uchar *lastkey,uchar *endpos,
- uint *return_key_length);
+ uchar ** page_pos, uchar *key);
+extern uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo,
+ uchar *keypos, uchar *lastkey, uchar *endpos,
+ uint *return_key_length);
extern uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
- uchar *key, uchar *keypos, uint *return_key_length);
-extern uint _mi_keylength(MI_KEYDEF *keyinfo,uchar *key);
+ uchar *key, uchar *keypos,
+ uint *return_key_length);
+extern uint _mi_keylength(MI_KEYDEF *keyinfo, uchar *key);
extern uint _mi_keylength_part(MI_KEYDEF *keyinfo, register uchar *key,
- HA_KEYSEG *end);
-extern uchar *_mi_move_key(MI_KEYDEF *keyinfo,uchar *to,uchar *from);
-extern int _mi_search_next(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
- uint key_length,uint nextflag,my_off_t pos);
-extern int _mi_search_first(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos);
-extern int _mi_search_last(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos);
-extern uchar *_mi_fetch_keypage(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t page,
- int level,uchar *buff,int return_buffer);
-extern int _mi_write_keypage(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t page,
- int level, uchar *buff);
-extern int _mi_dispose(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos,
- int level);
-extern my_off_t _mi_new(MI_INFO *info,MI_KEYDEF *keyinfo,int level);
-extern uint _mi_make_key(MI_INFO *info,uint keynr,uchar *key,
- const uchar *record,my_off_t filepos);
-extern uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key,
+ HA_KEYSEG *end);
+extern uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from);
+extern int _mi_search_next(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
+ uint key_length, uint nextflag, my_off_t pos);
+extern int _mi_search_first(MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos);
+extern int _mi_search_last(MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos);
+extern uchar *_mi_fetch_keypage(MI_INFO *info, MI_KEYDEF *keyinfo,
+ my_off_t page, int level, uchar *buff,
+ int return_buffer);
+extern int _mi_write_keypage(MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t page,
+ int level, uchar *buff);
+extern int _mi_dispose(MI_INFO *info, MI_KEYDEF *keyinfo, my_off_t pos,
+ int level);
+extern my_off_t _mi_new(MI_INFO *info, MI_KEYDEF *keyinfo, int level);
+extern uint _mi_make_key(MI_INFO *info, uint keynr, uchar *key,
+ const uchar *record, my_off_t filepos);
+extern uint _mi_pack_key(MI_INFO *info, uint keynr, uchar *key,
uchar *old, key_part_map keypart_map,
- HA_KEYSEG **last_used_keyseg);
-extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,uchar *buf);
-extern int _mi_read_cache(IO_CACHE *info,uchar *buff,my_off_t pos,
- uint length,int re_read_if_possibly);
-extern ulonglong retrieve_auto_increment(MI_INFO *info,const uchar *record);
+ HA_KEYSEG ** last_used_keyseg);
+extern int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf);
+extern int _mi_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos,
+ uint length, int re_read_if_possibly);
+extern ulonglong retrieve_auto_increment(MI_INFO *info, const uchar *record);
-extern uchar *mi_alloc_rec_buff(MI_INFO *,ulong, uchar**);
+extern uchar *mi_alloc_rec_buff(MI_INFO *, ulong, uchar **);
#define mi_get_rec_buff_ptr(info,buf) \
((((info)->s->options & HA_OPTION_PACK_RECORD) && (buf)) ? \
(buf) - MI_REC_BUFF_OFFSET : (buf))
#define mi_get_rec_buff_len(info,buf) \
(*((uint32 *)(mi_get_rec_buff_ptr(info,buf))))
-extern ulong _mi_rec_unpack(MI_INFO *info,uchar *to,uchar *from,
- ulong reclength);
+extern ulong _mi_rec_unpack(MI_INFO *info, uchar *to, uchar *from,
+ ulong reclength);
extern my_bool _mi_rec_check(MI_INFO *info,const uchar *record, uchar *packpos,
ulong packed_length, my_bool with_checkum);
-extern int _mi_write_part_record(MI_INFO *info,my_off_t filepos,ulong length,
- my_off_t next_filepos,uchar **record,
- ulong *reclength,int *flag);
-extern void _mi_print_key(FILE *stream,HA_KEYSEG *keyseg,const uchar *key,
- uint length);
-extern my_bool _mi_read_pack_info(MI_INFO *info,pbool fix_keys);
-extern int _mi_read_pack_record(MI_INFO *info,my_off_t filepos,uchar *buf);
-extern int _mi_read_rnd_pack_record(MI_INFO*, uchar *,my_off_t, my_bool);
+extern int _mi_write_part_record(MI_INFO *info, my_off_t filepos, ulong length,
+ my_off_t next_filepos, uchar ** record,
+ ulong *reclength, int *flag);
+extern void _mi_print_key(FILE *stream, HA_KEYSEG *keyseg, const uchar *key,
+ uint length);
+extern my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys);
+extern int _mi_read_pack_record(MI_INFO *info, my_off_t filepos, uchar *buf);
+extern int _mi_read_rnd_pack_record(MI_INFO *, uchar *, my_off_t, my_bool);
extern int _mi_pack_rec_unpack(MI_INFO *info, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *from, ulong reclength);
-extern ulonglong mi_safe_mul(ulonglong a,ulonglong b);
+extern ulonglong mi_safe_mul(ulonglong a, ulonglong b);
extern int _mi_ft_update(MI_INFO *info, uint keynr, uchar *keybuf,
- const uchar *oldrec, const uchar *newrec, my_off_t pos);
+ const uchar *oldrec, const uchar *newrec,
+ my_off_t pos);
struct st_sort_info;
-typedef struct st_mi_block_info { /* Parameter to _mi_get_block_info */
+typedef struct st_mi_block_info /* Parameter to _mi_get_block_info */
+{
uchar header[MI_BLOCK_INFO_HEADER_LENGTH];
ulong rec_len;
ulong data_len;
@@ -648,35 +604,37 @@ typedef struct st_mi_block_info { /* Parameter to _mi_get_block_info */
uint offset;
} MI_BLOCK_INFO;
- /* bits in return from _mi_get_block_info */
-
-#define BLOCK_FIRST 1
-#define BLOCK_LAST 2
-#define BLOCK_DELETED 4
-#define BLOCK_ERROR 8 /* Wrong data */
-#define BLOCK_SYNC_ERROR 16 /* Right data at wrong place */
-#define BLOCK_FATAL_ERROR 32 /* hardware-error */
-
-#define NEED_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
-#define MAXERR 20
-#define BUFFERS_WHEN_SORTING 16 /* Alloc for sort-key-tree */
-#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
-#define INDEX_TMP_EXT ".TMM"
-#define DATA_TMP_EXT ".TMD"
-
-#define UPDATE_TIME 1
-#define UPDATE_STAT 2
-#define UPDATE_SORT 4
-#define UPDATE_AUTO_INC 8
-#define UPDATE_OPEN_COUNT 16
-
-#define USE_BUFFER_INIT (((1024L*512L-MALLOC_OVERHEAD)/IO_SIZE)*IO_SIZE)
-#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
-#define SORT_BUFFER_INIT (2048L*1024L-MALLOC_OVERHEAD)
-#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
-
-enum myisam_log_commands {
- MI_LOG_OPEN,MI_LOG_WRITE,MI_LOG_UPDATE,MI_LOG_DELETE,MI_LOG_CLOSE,MI_LOG_EXTRA,MI_LOG_LOCK,MI_LOG_DELETE_ALL
+ /* bits in return from _mi_get_block_info */
+
+#define BLOCK_FIRST 1
+#define BLOCK_LAST 2
+#define BLOCK_DELETED 4
+#define BLOCK_ERROR 8 /* Wrong data */
+#define BLOCK_SYNC_ERROR 16 /* Right data at wrong place */
+#define BLOCK_FATAL_ERROR 32 /* hardware-error */
+
+#define NEED_MEM ((uint) 10*4*(IO_SIZE+32)+32) /* Nead for recursion */
+#define MAXERR 20
+#define BUFFERS_WHEN_SORTING 16 /* Alloc for sort-key-tree */
+#define WRITE_COUNT MY_HOW_OFTEN_TO_WRITE
+#define INDEX_TMP_EXT ".TMM"
+#define DATA_TMP_EXT ".TMD"
+
+#define UPDATE_TIME 1
+#define UPDATE_STAT 2
+#define UPDATE_SORT 4
+#define UPDATE_AUTO_INC 8
+#define UPDATE_OPEN_COUNT 16
+
+#define USE_BUFFER_INIT (((1024L*512L-MALLOC_OVERHEAD)/IO_SIZE)*IO_SIZE)
+#define READ_BUFFER_INIT (1024L*256L-MALLOC_OVERHEAD)
+#define SORT_BUFFER_INIT (2048L*1024L-MALLOC_OVERHEAD)
+#define MIN_SORT_BUFFER (4096-MALLOC_OVERHEAD)
+
+enum myisam_log_commands
+{
+ MI_LOG_OPEN, MI_LOG_WRITE, MI_LOG_UPDATE, MI_LOG_DELETE, MI_LOG_CLOSE,
+ MI_LOG_EXTRA, MI_LOG_LOCK, MI_LOG_DELETE_ALL
};
#define myisam_log(a,b,c,d) if (myisam_log_file >= 0) _myisam_log(a,b,c,d)
@@ -686,29 +644,27 @@ enum myisam_log_commands {
#define fast_mi_writeinfo(INFO) if (!(INFO)->s->tot_locks) (void) _mi_writeinfo((INFO),0)
#define fast_mi_readinfo(INFO) ((INFO)->lock_type == F_UNLCK) && _mi_readinfo((INFO),F_RDLCK,1)
-#ifdef __cplusplus
+#ifdef __cplusplus
extern "C" {
#endif
-
-extern uint _mi_get_block_info(MI_BLOCK_INFO *,File, my_off_t);
-extern uint _mi_rec_pack(MI_INFO *info,uchar *to,const uchar *from);
+ extern uint _mi_get_block_info(MI_BLOCK_INFO *, File, my_off_t);
+extern uint _mi_rec_pack(MI_INFO *info, uchar *to, const uchar *from);
extern uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BIT_BUFF *bit_buff,
MI_BLOCK_INFO *info, uchar **rec_buff_p,
File file, my_off_t filepos);
-extern void _my_store_blob_length(uchar *pos,uint pack_length,uint length);
-extern void _myisam_log(enum myisam_log_commands command,MI_INFO *info,
- const uchar *buffert,uint length);
+extern void _mi_store_blob_length(uchar *pos, uint pack_length, uint length);
+extern void _myisam_log(enum myisam_log_commands command, MI_INFO *info,
+ const uchar *buffert, uint length);
extern void _myisam_log_command(enum myisam_log_commands command,
- MI_INFO *info, const uchar *buffert,
- uint length, int result);
-extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info,
- const uchar *record,my_off_t filepos,
- int result);
+ MI_INFO *info, const uchar *buffert,
+ uint length, int result);
+extern void _myisam_log_record(enum myisam_log_commands command, MI_INFO *info,
+ const uchar *record, my_off_t filepos,
+ int result);
extern void mi_report_error(int errcode, const char *file_name);
extern my_bool _mi_memmap_file(MI_INFO *info);
extern void _mi_unmap_file(MI_INFO *info);
extern uint save_pack_length(uint version, uchar *block_buff, ulong length);
-extern uint read_pack_length(uint version, const uchar *buf, ulong *length);
extern uint calc_pack_length(uint version, ulong length);
extern size_t mi_mmap_pread(MI_INFO *info, uchar *Buffer,
size_t Count, my_off_t offset, myf MyFlags);
@@ -723,7 +679,7 @@ uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite);
uchar *mi_state_info_read(uchar *ptr, MI_STATE_INFO *state);
uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead);
uint mi_base_info_write(File file, MI_BASE_INFO *base);
-uchar *my_n_base_info_read(uchar *ptr, MI_BASE_INFO *base);
+uchar *mi_n_base_info_read(uchar *ptr, MI_BASE_INFO *base);
int mi_keyseg_write(File file, const HA_KEYSEG *keyseg);
uchar *mi_keyseg_read(uchar *ptr, HA_KEYSEG *keyseg);
uint mi_keydef_write(File file, MI_KEYDEF *keydef);
@@ -735,23 +691,23 @@ uchar *mi_recinfo_read(uchar *ptr, MI_COLUMNDEF *recinfo);
extern int mi_disable_indexes(MI_INFO *info);
extern int mi_enable_indexes(MI_INFO *info);
extern int mi_indexes_are_disabled(MI_INFO *info);
-ulong _my_calc_total_blob_length(MI_INFO *info, const uchar *record);
+ulong _mi_calc_total_blob_length(MI_INFO *info, const uchar *record);
ha_checksum mi_checksum(MI_INFO *info, const uchar *buf);
ha_checksum mi_static_checksum(MI_INFO *info, const uchar *buf);
my_bool mi_check_unique(MI_INFO *info, MI_UNIQUEDEF *def, uchar *record,
- ha_checksum unique_hash, my_off_t pos);
+ ha_checksum unique_hash, my_off_t pos);
ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const uchar *buf);
int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def,
- const uchar *record, my_off_t pos);
+ const uchar *record, my_off_t pos);
int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
- const uchar *record, my_off_t pos);
+ const uchar *record, my_off_t pos);
int mi_unique_comp(MI_UNIQUEDEF *def, const uchar *a, const uchar *b,
- my_bool null_are_equal);
-void mi_get_status(void* param, int concurrent_insert);
-void mi_update_status(void* param);
-void mi_restore_status(void* param);
-void mi_copy_status(void* to,void *from);
-my_bool mi_check_status(void* param);
+ my_bool null_are_equal);
+void mi_get_status(void *param, my_bool concurrent_insert);
+void mi_update_status(void *param);
+void mi_restore_status(void *param);
+void mi_copy_status(void *to, void *from);
+my_bool mi_check_status(void *param);
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
extern MI_INFO *test_if_reopen(char *filename);
@@ -765,22 +721,14 @@ my_bool mi_dynmap_file(MI_INFO *info, my_off_t size);
void mi_remap_file(MI_INFO *info, my_off_t size);
/* Functions needed by mi_check */
-volatile int *killed_ptr(MI_CHECK *param);
-void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));
-void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...));
-void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...));
-int flush_pending_blocks(MI_SORT_PARAM *param);
-int sort_ft_buf_flush(MI_SORT_PARAM *sort_param);
-int thr_write_keys(MI_SORT_PARAM *sort_param);
+volatile int *killed_ptr(HA_CHECK *param);
+void mi_check_print_error _VARARGS((HA_CHECK *param, const char *fmt, ...));
+void mi_check_print_warning _VARARGS((HA_CHECK *param, const char *fmt, ...));
+void mi_check_print_info _VARARGS((HA_CHECK *param, const char *fmt, ...));
#ifdef THREAD
pthread_handler_t thr_find_all_keys(void *arg);
#endif
-int flush_blocks(MI_CHECK *param, KEY_CACHE *key_cache, File file);
-
-int sort_write_record(MI_SORT_PARAM *sort_param);
-int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ulong);
-
+int flush_blocks(HA_CHECK *param, KEY_CACHE *key_cache, File file);
#ifdef __cplusplus
}
#endif
-
diff --git a/storage/myisam/myisamlog.c b/storage/myisam/myisamlog.c
index fafb5140a5e..6e681676c12 100644
--- a/storage/myisam/myisamlog.c
+++ b/storage/myisam/myisamlog.c
@@ -808,7 +808,7 @@ static int find_record_with_key(struct file_info *file_info, uchar *record)
{
uint key;
MI_INFO *info=file_info->isam;
- uchar tmp_key[MI_MAX_KEY_BUFF];
+ uchar tmp_key[HA_MAX_KEY_BUFF];
for (key=0 ; key < info->s->base.keys ; key++)
{
diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c
index 908c32e48d3..3d96dfaafa1 100644
--- a/storage/myisam/myisampack.c
+++ b/storage/myisam/myisampack.c
@@ -305,7 +305,7 @@ static void usage(void)
puts("and you are welcome to modify and redistribute it under the GPL license\n");
puts("Pack a MyISAM-table to take much less space.");
- puts("Keys are not updated, you must run myisamchk -rq on the datafile");
+ puts("Keys are not updated, you must run myisamchk -rq on the index (.MYI) file");
puts("afterwards to update the keys.");
puts("You should give the .MYI file as the filename argument.");
diff --git a/storage/myisam/plug.in b/storage/myisam/plug.in
index 051ec2d54aa..e92b5e56d7f 100644
--- a/storage/myisam/plug.in
+++ b/storage/myisam/plug.in
@@ -1,7 +1,7 @@
-MYSQL_STORAGE_ENGINE(myisam,no, [MyISAM Storage Engine],
- [Traditional non-transactional MySQL tables])
-MYSQL_PLUGIN_DIRECTORY(myisam, [storage/myisam])
-MYSQL_PLUGIN_STATIC(myisam, [libmyisam.a])
-MYSQL_PLUGIN_MANDATORY(myisam) dnl Default
-MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(myisam, [ha_myisam.cc])
+dnl MYSQL_STORAGE_ENGINE(myisam,no, [MyISAM Storage Engine],
+dnl [Traditional non-transactional MySQL tables])
+dnl MYSQL_PLUGIN_DIRECTORY(myisam, [storage/myisam])
+dnl MYSQL_PLUGIN_STATIC(myisam, [libmyisam.a])
+dnl MYSQL_PLUGIN_MANDATORY(myisam) dnl Default
+dnl MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(myisam, [ha_myisam.cc])
diff --git a/storage/myisam/rt_index.c b/storage/myisam/rt_index.c
index 0b472f4fb0e..822983b718c 100644
--- a/storage/myisam/rt_index.c
+++ b/storage/myisam/rt_index.c
@@ -534,7 +534,7 @@ static int rtree_insert_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
DBUG_ENTER("rtree_insert_req");
if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length +
- MI_MAX_KEY_BUFF)))
+ HA_MAX_KEY_BUFF)))
{
my_errno = HA_ERR_OUT_OF_MEM;
DBUG_RETURN(-1); /* purecov: inspected */
@@ -650,7 +650,7 @@ static int rtree_insert_level(MI_INFO *info, uint keynr, uchar *key,
DBUG_PRINT("rtree", ("root was split, grow a new root"));
if (!(new_root_buf = (uchar*)my_alloca((uint)keyinfo->block_length +
- MI_MAX_KEY_BUFF)))
+ HA_MAX_KEY_BUFF)))
{
my_errno = HA_ERR_OUT_OF_MEM;
DBUG_RETURN(-1); /* purecov: inspected */
diff --git a/storage/myisam/rt_test.c b/storage/myisam/rt_test.c
index 7d15afd12ef..6c73c9db13c 100644
--- a/storage/myisam/rt_test.c
+++ b/storage/myisam/rt_test.c
@@ -105,14 +105,20 @@ static int run_test(const char *filename)
int nrecords=sizeof(rt_data)/(sizeof(double)*4);/* 3000;*/
int rec_length=0;
int uniques=0;
- int i;
+ int i, max_i;
int error;
int row_count=0;
uchar record[MAX_REC_LENGTH];
uchar read_record[MAX_REC_LENGTH];
int upd= 10;
ha_rows hrows;
-
+
+ bzero(&uniquedef, sizeof(uniquedef));
+ bzero(&create_info, sizeof(create_info));
+ bzero(recinfo, sizeof(recinfo));
+ bzero(keyinfo, sizeof(keyinfo));
+ bzero(keyseg, sizeof(keyseg));
+
/* Define a column for NULLs and DEL markers*/
recinfo[0].type=FIELD_NORMAL;
@@ -147,7 +153,6 @@ static int run_test(const char *filename)
if (!silent)
printf("- Creating isam-file\n");
- bzero((char*) &create_info,sizeof(create_info));
create_info.max_rows=10000000;
if (mi_create(filename,
@@ -194,7 +199,7 @@ static int run_test(const char *filename)
create_record(record,i);
bzero((char*) read_record,MAX_REC_LENGTH);
- error=mi_rkey(file,read_record,0,record+1,0,HA_READ_MBR_EQUAL);
+ error=mi_rkey(file,read_record,0,record+1,HA_WHOLE_KEY,HA_READ_MBR_EQUAL);
if (error && error!=HA_ERR_KEY_NOT_FOUND)
{
@@ -233,7 +238,8 @@ static int run_test(const char *filename)
if (!silent)
printf("- Updating rows with position\n");
- for (i=0; i < (nrecords - nrecords/4) ; i++)
+ /* We are looking for nrecords-necords/2 non-deleted records */
+ for (i=0, max_i= nrecords - nrecords/2; i < max_i ; i++)
{
my_errno=0;
bzero((char*) read_record,MAX_REC_LENGTH);
@@ -241,7 +247,11 @@ static int run_test(const char *filename)
if (error)
{
if (error==HA_ERR_RECORD_DELETED)
+ {
+ printf("found deleted record\n");
+ max_i++; /* don't count such record */
continue;
+ }
printf("pos: %2d mi_rrnd: %3d errno: %3d\n",i,error,my_errno);
goto err;
}
@@ -266,7 +276,8 @@ static int run_test(const char *filename)
create_record(record, nrecords*4/5);
print_record(record,0," search for\n");
- if ((error=mi_rkey(file,read_record,0,record+1,0,HA_READ_MBR_INTERSECT)))
+ if ((error=mi_rkey(file,read_record,0,record+1,HA_WHOLE_KEY,
+ HA_READ_MBR_INTERSECT)))
{
printf("mi_rkey: %3d errno: %3d\n",error,my_errno);
goto err;
diff --git a/storage/myisam/sort.c b/storage/myisam/sort.c
index d505d2633ce..b2507ad8886 100644
--- a/storage/myisam/sort.c
+++ b/storage/myisam/sort.c
@@ -15,7 +15,7 @@
/*
Creates a index for a database by reading keys, sorting them and outputing
- them in sorted order through SORT_INFO functions.
+ them in sorted order through MI_SORT_INFO functions.
*/
#include "fulltext.h"
@@ -487,8 +487,8 @@ ok:
int thr_write_keys(MI_SORT_PARAM *sort_param)
{
- SORT_INFO *sort_info=sort_param->sort_info;
- MI_CHECK *param=sort_info->param;
+ MI_SORT_INFO *sort_info=sort_param->sort_info;
+ HA_CHECK *param=sort_info->param;
ulong length, keys;
ulong *rec_per_key_part=param->rec_per_key_part;
int got_error=sort_info->got_error;
@@ -920,7 +920,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
{
count+= buffpek->count;
- buffpek->base= strpos;
+ buffpek->base= (uchar*) strpos;
buffpek->max_keys=maxcount;
strpos+= (uint) (error=(int) info->read_to_buffer(from_file,buffpek,
sort_length));
@@ -958,7 +958,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
{
if (!(error=(int) info->read_to_buffer(from_file,buffpek,sort_length)))
{
- uchar *base=buffpek->base;
+ uchar *base= buffpek->base;
uint max_keys=buffpek->max_keys;
VOID(queue_remove(&queue,0));
@@ -990,7 +990,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
}
}
buffpek=(BUFFPEK*) queue_top(&queue);
- buffpek->base=(uchar *) sort_keys;
+ buffpek->base= (uchar*) sort_keys;
buffpek->max_keys=keys;
do
{
@@ -1005,7 +1005,7 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
else
{
register uchar *end;
- strpos= buffpek->key;
+ strpos= (uchar*) buffpek->key;
for (end=strpos+buffpek->mem_count*sort_length;
strpos != end ;
strpos+=sort_length)
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
index 956f0e421cc..392a8600da3 100644
--- a/storage/myisammrg/ha_myisammrg.cc
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -134,9 +134,11 @@ static const char *ha_myisammrg_exts[] = {
};
extern int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
MI_COLUMNDEF **recinfo_out, uint *records_out);
-extern int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
+extern int check_definition(MI_KEYDEF *t1_keyinfo,
+ MI_COLUMNDEF *t1_recinfo,
uint t1_keys, uint t1_recs,
- MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
+ MI_KEYDEF *t2_keyinfo,
+ MI_COLUMNDEF *t2_recinfo,
uint t2_keys, uint t2_recs, bool strict);
static void split_file_name(const char *file_name,
LEX_STRING *db, LEX_STRING *name);
@@ -402,14 +404,14 @@ static MI_INFO *myisammrg_attach_children_callback(void *callback_param)
*/
int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
- uint test_if_locked)
+ uint test_if_locked_arg)
{
DBUG_ENTER("ha_myisammrg::open");
DBUG_PRINT("myrg", ("name: '%s' table: 0x%lx", name, (long) table));
- DBUG_PRINT("myrg", ("test_if_locked: %u", test_if_locked));
+ DBUG_PRINT("myrg", ("test_if_locked: %u", test_if_locked_arg));
/* Save for later use. */
- this->test_if_locked= test_if_locked;
+ test_if_locked= test_if_locked_arg;
/* retrieve children table list. */
my_errno= 0;
@@ -877,7 +879,8 @@ int ha_myisammrg::extra(enum ha_extra_function operation)
/* As this is just a mapping, we don't have to force the underlying
tables to be closed */
if (operation == HA_EXTRA_FORCE_REOPEN ||
- operation == HA_EXTRA_PREPARE_FOR_DROP)
+ operation == HA_EXTRA_PREPARE_FOR_DROP ||
+ operation == HA_EXTRA_PREPARE_FOR_RENAME)
return 0;
return myrg_extra(file,operation,0);
}
diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h
index 4e7ddebb836..13d64588b06 100644
--- a/storage/myisammrg/ha_myisammrg.h
+++ b/storage/myisammrg/ha_myisammrg.h
@@ -52,8 +52,8 @@ class ha_myisammrg: public handler
HA_READ_ORDER | HA_KEYREAD_ONLY);
}
uint max_supported_keys() const { return MI_MAX_KEY; }
- uint max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
- uint max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
+ uint max_supported_key_length() const { return HA_MAX_KEY_LENGTH; }
+ uint max_supported_key_part_length() const { return HA_MAX_KEY_LENGTH; }
double scan_time()
{ return ulonglong2double(stats.data_file_length) / IO_SIZE + file->tables; }
diff --git a/storage/myisammrg/myrg_create.c b/storage/myisammrg/myrg_create.c
index df81b730bfd..eaed470daec 100644
--- a/storage/myisammrg/myrg_create.c
+++ b/storage/myisammrg/myrg_create.c
@@ -46,7 +46,7 @@ int myrg_create(const char *name, const char **table_names,
fn_same(buff,name,4);
*(end=strend(buff))='\n';
end[1]=0;
- if (my_write(file,(char*) buff,(uint) (end-buff+1),
+ if (my_write(file,(uchar*) buff,(uint) (end-buff+1),
MYF(MY_WME | MY_NABP)))
goto err;
}
diff --git a/strings/CMakeLists.txt b/strings/CMakeLists.txt
index 3d9de566670..f57189bd548 100755
--- a/strings/CMakeLists.txt
+++ b/strings/CMakeLists.txt
@@ -25,7 +25,8 @@ SET(STRINGS_SOURCES bchange.c bcmp.c bfill.c bmove512.c bmove_upp.c ctype-big5.c
is_prefix.c llstr.c longlong2str.c my_strtoll10.c my_vsnprintf.c r_strinstr.c
str2int.c str_alloc.c strcend.c strend.c strfill.c strmake.c strmov.c strnmov.c
strtod.c strtol.c strtoll.c strtoul.c strtoull.c strxmov.c strxnmov.c xml.c
- my_strchr.c strcont.c strinstr.c strnlen.c)
+ my_strchr.c strcont.c strinstr.c strnlen.c
+ strappend.c)
IF(NOT SOURCE_SUBLIBS)
ADD_LIBRARY(strings ${STRINGS_SOURCES})
diff --git a/strings/bmove512.c b/strings/bmove512.c
index c3f0446ead6..0ae23d1f42d 100644
--- a/strings/bmove512.c
+++ b/strings/bmove512.c
@@ -33,7 +33,7 @@
#ifdef HAVE_LONG_LONG
#define LONG ulonglong
#else
-#define LONG ulonglong
+#define LONG ulong
#endif
void bmove512(uchar *to, const uchar *from, register size_t length)
diff --git a/strings/ctype.c b/strings/ctype.c
index 2c0fe09c07b..69fe5b6b9dc 100644
--- a/strings/ctype.c
+++ b/strings/ctype.c
@@ -328,7 +328,9 @@ my_string_repertoire(CHARSET_INFO *cs, const char *str, ulong length)
{
my_wc_t wc;
int chlen;
- for (; (chlen= cs->cset->mb_wc(cs, &wc, str, strend)) > 0; str+= chlen)
+ for (;
+ (chlen= cs->cset->mb_wc(cs, &wc, (uchar*) str, (uchar*) strend)) > 0;
+ str+= chlen)
{
if (wc > 0x7F)
return MY_REPERTOIRE_UNICODE30;
diff --git a/strings/llstr.c b/strings/llstr.c
index 643cf36a311..678f8b05f39 100644
--- a/strings/llstr.c
+++ b/strings/llstr.c
@@ -38,3 +38,4 @@ char *ullstr(longlong value,char *buff)
longlong10_to_str(value,buff,10);
return buff;
}
+
diff --git a/strings/strmake.c b/strings/strmake.c
index 2d5fa5e36aa..903a1b83626 100644
--- a/strings/strmake.c
+++ b/strings/strmake.c
@@ -29,26 +29,38 @@
char *strmake(register char *dst, register const char *src, size_t length)
{
-#ifdef EXTRA_DEBUG
- /*
- 'length' is the maximum length of the string; the buffer needs
- to be one character larger to accomodate the terminating '\0'.
- This is easy to get wrong, so we make sure we write to the
- entire length of the buffer to identify incorrect buffer-sizes.
- We only initialise the "unused" part of the buffer here, a) for
- efficiency, and b) because dst==src is allowed, so initialising
- the entire buffer would overwrite the source-string. Also, we
- write a character rather than '\0' as this makes spotting these
- problems in the results easier.
- */
- uint n= 0;
- while (n < length && src[n++]);
- memset(dst + n, (int) 'Z', length - n + 1);
-#endif
-
while (length--)
+ {
if (! (*dst++ = *src++))
+ {
+#ifdef EXTRA_DEBUG
+ /*
+ 'length' is the maximum length of the string; the buffer needs
+ to be one character larger to accommodate the terminating
+ '\0'. This is easy to get wrong, so we make sure we write to
+ the entire length of the buffer to identify incorrect
+ buffer-sizes. We only initialism the "unused" part of the
+ buffer here, a) for efficiency, and b) because dst==src is
+ allowed, so initializing the entire buffer would overwrite the
+ source-string. Also, we write a character rather than '\0' as
+ this makes spotting these problems in the results easier.
+
+ If we are using purify/valgrind, we only set one character at
+ end to be able to detect also wrong accesses after the end of
+ dst.
+ */
+ if (length)
+ {
+#ifdef HAVE_purify
+ dst[length-1]= 'Z';
+#else
+ bfill(dst, length-1, (int) 'Z');
+#endif /* HAVE_purify */
+ }
+#endif /* EXTRA_DEBUG */
return dst-1;
+ }
+ }
*dst=0;
return dst;
}
diff --git a/support-files/compiler_warnings.supp b/support-files/compiler_warnings.supp
index c437748c770..fbe4b3d21c9 100644
--- a/support-files/compiler_warnings.supp
+++ b/support-files/compiler_warnings.supp
@@ -70,6 +70,11 @@ db_vrfy.c : .*comparison is always false due to limited range of data type.*
.*/ndb/.* : .*defined but not used.*
#
+# Maria warning that is ok in debug builds
+#
+storage/maria/ma_pagecache.c: .*'info_check_pin' defined but not used
+
+#
# Unexplanable (?) stuff
#
listener.cc : .*conversion from 'SOCKET' to 'int'.*
@@ -77,6 +82,7 @@ net_serv.cc : .*conversion from 'SOCKET' to 'int'.*
# allow a little moving space for the warning below
mi_packrec.c : .*result of 32-bit shift implicitly converted to 64 bits.* : 560-600
+ma_packrec.c : .*result of 32-bit shift implicitly converted to 64 bits.* : 550-650
#
# Wrong compiler warnings
diff --git a/support-files/magic b/support-files/magic
index 9844142ba93..b3f3b3ea29d 100644
--- a/support-files/magic
+++ b/support-files/magic
@@ -4,12 +4,23 @@
#
0 beshort 0xfe01 MySQL table definition file
>2 byte x Version %d
-0 belong&0xffffff00 0xfefe0300 MySQL MISAM index file
+0 belong&0xffffff00 0xfefe0700 MySQL MyISAM index file
>3 byte x Version %d
-0 belong&0xffffff00 0xfefe0700 MySQL MISAM compressed data file
+0 belong&0xffffff00 0xfefe0800 MySQL MyISAM compressed data file
+>3 byte x Version %d
+0 belong&0xffffff00 0xfefe0900 MySQL Maria index file
+>3 byte x Version %d
+0 belong&0xffffff00 0xfefe0A00 MySQL Maria compressed data file
>3 byte x Version %d
0 belong&0xffffff00 0xfefe0500 MySQL ISAM index file
>3 byte x Version %d
0 belong&0xffffff00 0xfefe0600 MySQL ISAM compressed data file
>3 byte x Version %d
0 string \376bin MySQL replication log
+0 belong&0xffffff00 0xfefe0b00
+>4 string MARIALOG MySQL Maria transaction log file
+>>3 byte x Version %d
+0 belong&0xffffff00 0xfefe0c00
+>4 string MACF MySQL Maria control file
+>>3 byte x Version %d
+
diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh
index 7c08fdf4734..a1a0ad50358 100644
--- a/support-files/mysql.spec.sh
+++ b/support-files/mysql.spec.sh
@@ -36,6 +36,11 @@
%{?_with_cluster:%define CLUSTER_BUILD 1}
%{!?_with_cluster:%define CLUSTER_BUILD 0}
+# use "rpmbuild --with maria" or "rpm --define '_with_maria 1'" (for RPM 3.x)
+# to build with maria support (off by default)
+%{?_with_maria:%define MARIA_BUILD 1}
+%{!?_with_maria:%define MARIA_BUILD 0}
+
%if %{STATIC_BUILD}
%define release 0
%else
@@ -262,6 +267,26 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \
LDFLAGS=\"$MYSQL_BUILD_LDFLAGS\" \
./configure \
$* \
+ --with-innodb \
+%if %{CLUSTER_BUILD}
+ --with-ndbcluster \
+%else
+ --without-ndbcluster \
+%endif
+ --with-archive-storage-engine \
+ --with-csv-storage-engine \
+ --with-blackhole-storage-engine \
+%if %{FEDERATED_BUILD}
+ --with-federated-storage-engine \
+%else
+ --without-federated-storage-engine \
+%endif
+%if %{MARIA_BUILD}
+ --with-plugin-maria \
+ --with-maria-tmp-tables \
+%endif
+ --with-partition \
+ --with-big-tables \
--with-mysqld-ldflags='-static' \
--with-client-ldflags='-static' \
--with-zlib-dir=bundled \
@@ -366,7 +391,12 @@ CFLAGS="$CFLAGS" \
CXXFLAGS="$CXXFLAGS" \
BuildMySQL "\
--with-debug \
- --with-comment=\"MySQL Community Server - Debug (%{license})\"")
+%if %{MARIA_BUILD}
+ --with-comment=\"MySQL Community Server - Debug [Maria] (%{license})\" \
+%else
+ --with-comment=\"MySQL Community Server - Debug (%{license})\" \
+%endif
+")
# We might want to save the config log file
if test -n "$MYSQL_DEBUGCONFLOG_DEST"
@@ -387,7 +417,12 @@ CFLAGS="$CFLAGS" \
CXXFLAGS="$CXXFLAGS" \
BuildMySQL "\
--with-embedded-server \
- --with-comment=\"MySQL Community Server (%{license})\"")
+%if %{MARIA_BUILD}
+ --with-comment=\"MySQL Community Server [Maria] (%{license})\" \
+%else
+ --with-comment=\"MySQL Community Server (%{license})\" \
+%endif
+")
# We might want to save the config log file
if test -n "$MYSQL_CONFLOG_DEST"
then
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 4f30d43f53f..24335702ee3 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -40,7 +40,9 @@
#define MAX_SERVER_ARGS 64
/* set default options */
+#ifdef NOT_USED
static int opt_testcase = 0;
+#endif
static char *opt_db= 0;
static char *opt_user= 0;
static char *opt_password= 0;
@@ -12600,7 +12602,7 @@ static void test_conversion()
const char *stmt_text;
int rc;
MYSQL_BIND my_bind[1];
- char buff[4];
+ uchar buff[4];
ulong length;
myheader("test_conversion");
@@ -12623,7 +12625,7 @@ static void test_conversion()
check_execute(stmt, rc);
bzero((char*) my_bind, sizeof(my_bind));
- my_bind[0].buffer= buff;
+ my_bind[0].buffer= (char*) buff;
my_bind[0].length= &length;
my_bind[0].buffer_type= MYSQL_TYPE_STRING;
@@ -12648,7 +12650,7 @@ static void test_conversion()
rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc == 0);
DIE_UNLESS(length == 1);
- DIE_UNLESS((uchar) buff[0] == 0xE0);
+ DIE_UNLESS(buff[0] == 0xE0);
rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc == MYSQL_NO_DATA);
@@ -15873,11 +15875,10 @@ static void test_bug21206()
static void test_status()
{
- const char *status;
DBUG_ENTER("test_status");
myheader("test_status");
- if (!(status= mysql_stat(mysql)))
+ if (!mysql_stat(mysql))
{
myerror("mysql_stat failed"); /* purecov: inspected */
die(__FILE__, __LINE__, "mysql_stat failed"); /* purecov: inspected */
@@ -18098,7 +18099,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
DBUG_PUSH(argument ? argument : default_dbug_option);
break;
case 'c':
+#ifdef NOT_USED
opt_testcase = 1;
+#endif
break;
case 'p':
if (argument)
diff --git a/unittest/Makefile.am b/unittest/Makefile.am
index 65fa615fb98..f1c4f7bb7dd 100644
--- a/unittest/Makefile.am
+++ b/unittest/Makefile.am
@@ -13,12 +13,12 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-SUBDIRS = mytap . mysys examples
+SUBDIRS = mytap mysys examples
EXTRA_DIST = unit.pl
CLEANFILES = unit
-unittests = mytap mysys @mysql_se_unittest_dirs@ @mysql_pg_unittest_dirs@
+unittests = mytap mysys @mysql_se_unittest_dirs@ @mysql_pg_unittest_dirs@ ../dbug
test:
perl unit.pl run $(unittests)
diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt
new file mode 100644
index 00000000000..e13a55d2e1e
--- /dev/null
+++ b/unittest/mysys/CMakeLists.txt
@@ -0,0 +1,34 @@
+# Copyright (C) 2007 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/unittest/mytap)
+ADD_EXECUTABLE(bitmap-t bitmap-t.c)
+TARGET_LINK_LIBRARIES(bitmap-t mytap mysys dbug strings wsock32)
+
+ADD_EXECUTABLE(base64-t base64-t.c)
+TARGET_LINK_LIBRARIES(base64-t mytap mysys dbug strings wsock32)
+
+ADD_EXECUTABLE(my_atomic-t my_atomic-t.c)
+TARGET_LINK_LIBRARIES(my_atomic-t mytap mysys dbug strings wsock32)
+
+ADD_EXECUTABLE(lf-t lf-t.c)
+TARGET_LINK_LIBRARIES(lf-t mytap mysys dbug strings wsock32)
+
+ADD_EXECUTABLE(waiting_threads-t waiting_threads-t.c)
+TARGET_LINK_LIBRARIES(waiting_threads-t mytap mysys dbug strings wsock32)
diff --git a/unittest/mysys/Makefile.am b/unittest/mysys/Makefile.am
index be91ef31c9d..ab997c79b33 100644
--- a/unittest/mysys/Makefile.am
+++ b/unittest/mysys/Makefile.am
@@ -13,15 +13,19 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include
-AM_CPPFLAGS += -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
+INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \
+ -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap
+
+noinst_HEADERS = thr_template.c
+
+noinst_PROGRAMS = bitmap-t base64-t my_atomic-t lf-t waiting_threads-t
LDADD = $(top_builddir)/unittest/mytap/libmytap.a \
$(top_builddir)/mysys/libmysys.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/strings/libmystrings.a
-noinst_PROGRAMS = bitmap-t base64-t my_atomic-t
+EXTRA_DIST = CMakeLists.txt
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/unittest/mysys/lf-t.c b/unittest/mysys/lf-t.c
new file mode 100644
index 00000000000..61b7ae08cf5
--- /dev/null
+++ b/unittest/mysys/lf-t.c
@@ -0,0 +1,178 @@
+/* Copyright (C) 2008-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/**
+ @file
+
+ Unit tests for lock-free algorithms of mysys
+*/
+
+#include "thr_template.c"
+
+#include <lf.h>
+
+int32 inserts= 0, N;
+LF_ALLOCATOR lf_allocator;
+LF_HASH lf_hash;
+
+/*
+ pin allocator - alloc and release an element in a loop
+*/
+pthread_handler_t test_lf_pinbox(void *arg)
+{
+ int m= *(int *)arg;
+ int32 x= 0;
+ LF_PINS *pins;
+
+ my_thread_init();
+
+ pins= lf_pinbox_get_pins(&lf_allocator.pinbox);
+
+ for (x= ((int)(intptr)(&m)); m ; m--)
+ {
+ lf_pinbox_put_pins(pins);
+ pins= lf_pinbox_get_pins(&lf_allocator.pinbox);
+ }
+ lf_pinbox_put_pins(pins);
+ pthread_mutex_lock(&mutex);
+ if (!--running_threads) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ my_thread_end();
+ return 0;
+}
+
+/*
+ thread local data area, allocated using lf_alloc.
+ union is required to enforce the minimum required element size (sizeof(ptr))
+*/
+typedef union {
+ int32 data;
+ void *not_used;
+} TLA;
+
+pthread_handler_t test_lf_alloc(void *arg)
+{
+ int m= (*(int *)arg)/2;
+ int32 x,y= 0;
+ LF_PINS *pins;
+
+ my_thread_init();
+
+ pins= lf_alloc_get_pins(&lf_allocator);
+
+ for (x= ((int)(intptr)(&m)); m ; m--)
+ {
+ TLA *node1, *node2;
+ x= (x*m+0x87654321) & INT_MAX32;
+ node1= (TLA *)lf_alloc_new(pins);
+ node1->data= x;
+ y+= node1->data;
+ node1->data= 0;
+ node2= (TLA *)lf_alloc_new(pins);
+ node2->data= x;
+ y-= node2->data;
+ node2->data= 0;
+ lf_alloc_free(pins, node1);
+ lf_alloc_free(pins, node2);
+ }
+ lf_alloc_put_pins(pins);
+ pthread_mutex_lock(&mutex);
+ bad+= y;
+
+ if (--N == 0)
+ {
+ diag("%d mallocs, %d pins in stack",
+ lf_allocator.mallocs, lf_allocator.pinbox.pins_in_array);
+#ifdef MY_LF_EXTRA_DEBUG
+ bad|= lf_allocator.mallocs - lf_alloc_pool_count(&lf_allocator);
+#endif
+ }
+ if (!--running_threads) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ my_thread_end();
+ return 0;
+}
+
+#define N_TLH 1000
+pthread_handler_t test_lf_hash(void *arg)
+{
+ int m= (*(int *)arg)/(2*N_TLH);
+ int32 x,y,z,sum= 0, ins= 0;
+ LF_PINS *pins;
+
+ my_thread_init();
+
+ pins= lf_hash_get_pins(&lf_hash);
+
+ for (x= ((int)(intptr)(&m)); m ; m--)
+ {
+ int i;
+ y= x;
+ for (i= 0; i < N_TLH; i++)
+ {
+ x= (x*(m+i)+0x87654321) & INT_MAX32;
+ z= (x<0) ? -x : x;
+ if (lf_hash_insert(&lf_hash, pins, &z))
+ {
+ sum+= z;
+ ins++;
+ }
+ }
+ for (i= 0; i < N_TLH; i++)
+ {
+ y= (y*(m+i)+0x87654321) & INT_MAX32;
+ z= (y<0) ? -y : y;
+ if (lf_hash_delete(&lf_hash, pins, (uchar *)&z, sizeof(z)))
+ sum-= z;
+ }
+ }
+ lf_hash_put_pins(pins);
+ pthread_mutex_lock(&mutex);
+ bad+= sum;
+ inserts+= ins;
+
+ if (--N == 0)
+ {
+ diag("%d mallocs, %d pins in stack, %d hash size, %d inserts",
+ lf_hash.alloc.mallocs, lf_hash.alloc.pinbox.pins_in_array,
+ lf_hash.size, inserts);
+ bad|= lf_hash.count;
+ }
+ if (!--running_threads) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ my_thread_end();
+ return 0;
+}
+
+
+void do_tests()
+{
+ plan(4);
+
+ lf_alloc_init(&lf_allocator, sizeof(TLA), offsetof(TLA, not_used));
+ lf_hash_init(&lf_hash, sizeof(int), LF_HASH_UNIQUE, 0, sizeof(int), 0,
+ &my_charset_bin);
+
+ bad= my_atomic_initialize();
+ ok(!bad, "my_atomic_initialize() returned %d", bad);
+
+ test_concurrently("lf_pinbox", test_lf_pinbox, N= THREADS, CYCLES);
+ test_concurrently("lf_alloc", test_lf_alloc, N= THREADS, CYCLES);
+ test_concurrently("lf_hash", test_lf_hash, N= THREADS, CYCLES/10);
+
+ lf_hash_destroy(&lf_hash);
+ lf_alloc_destroy(&lf_allocator);
+}
+
diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c
index f2bcd360508..b98f3379a4a 100644
--- a/unittest/mysys/my_atomic-t.c
+++ b/unittest/mysys/my_atomic-t.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006 MySQL AB
+/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,10 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <my_global.h>
-#include <my_sys.h>
-#include <my_atomic.h>
-#include <tap.h>
+#include "thr_template.c"
/* at least gcc 3.4.5 and 3.4.6 (but not 3.2.3) on RHEL */
#if __GNUC__ == 3 && __GNUC_MINOR__ == 4
@@ -25,181 +22,125 @@
#define GCC_BUG_WORKAROUND
#endif
-int32 a32,b32,c32;
+volatile uint32 b32;
+volatile int32 c32;
my_atomic_rwlock_t rwl;
-pthread_attr_t thr_attr;
-pthread_mutex_t mutex;
-pthread_cond_t cond;
-int N;
-
/* add and sub a random number in a loop. Must get 0 at the end */
-pthread_handler_t test_atomic_add_handler(void *arg)
+pthread_handler_t test_atomic_add(void *arg)
{
- int m=*(int *)arg;
+ int m= (*(int *)arg)/2;
GCC_BUG_WORKAROUND int32 x;
- for (x=((int)((long)(&m))); m ; m--)
+ for (x= ((int)(intptr)(&m)); m ; m--)
{
- x=x*m+0x87654321;
+ x= (x*m+0x87654321) & INT_MAX32;
my_atomic_rwlock_wrlock(&rwl);
- my_atomic_add32(&a32, x);
+ my_atomic_add32(&bad, x);
my_atomic_rwlock_wrunlock(&rwl);
my_atomic_rwlock_wrlock(&rwl);
- my_atomic_add32(&a32, -x);
+ my_atomic_add32(&bad, -x);
my_atomic_rwlock_wrunlock(&rwl);
}
pthread_mutex_lock(&mutex);
- N--;
- if (!N) pthread_cond_signal(&cond);
+ if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return 0;
}
/*
1. generate thread number 0..N-1 from b32
- 2. add it to a32
+ 2. add it to bad
3. swap thread numbers in c32
4. (optionally) one more swap to avoid 0 as a result
- 5. subtract result from a32
- must get 0 in a32 at the end
+ 5. subtract result from bad
+ must get 0 in bad at the end
*/
-pthread_handler_t test_atomic_swap_handler(void *arg)
+pthread_handler_t test_atomic_fas(void *arg)
{
- int m=*(int *)arg;
- int32 x;
+ int m= *(int *)arg;
+ int32 x;
my_atomic_rwlock_wrlock(&rwl);
- x=my_atomic_add32(&b32, 1);
+ x= my_atomic_add32(&b32, 1);
my_atomic_rwlock_wrunlock(&rwl);
my_atomic_rwlock_wrlock(&rwl);
- my_atomic_add32(&a32, x);
+ my_atomic_add32(&bad, x);
my_atomic_rwlock_wrunlock(&rwl);
for (; m ; m--)
{
my_atomic_rwlock_wrlock(&rwl);
- x=my_atomic_swap32(&c32, x);
+ x= my_atomic_fas32(&c32, x);
my_atomic_rwlock_wrunlock(&rwl);
}
if (!x)
{
my_atomic_rwlock_wrlock(&rwl);
- x=my_atomic_swap32(&c32, x);
+ x= my_atomic_fas32(&c32, x);
my_atomic_rwlock_wrunlock(&rwl);
}
my_atomic_rwlock_wrlock(&rwl);
- my_atomic_add32(&a32, -x);
+ my_atomic_add32(&bad, -x);
my_atomic_rwlock_wrunlock(&rwl);
pthread_mutex_lock(&mutex);
- N--;
- if (!N) pthread_cond_signal(&cond);
+ if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return 0;
}
/*
- same as test_atomic_add_handler, but my_atomic_add32 is emulated with
- (slower) my_atomic_cas32
+ same as test_atomic_add, but my_atomic_add32 is emulated with
+ my_atomic_cas32 - notice that the slowdown is proportional to the
+ number of CPUs
*/
-pthread_handler_t test_atomic_cas_handler(void *arg)
+pthread_handler_t test_atomic_cas(void *arg)
{
- int m=*(int *)arg, ok;
- GCC_BUG_WORKAROUND int32 x,y;
- for (x=((int)((long)(&m))); m ; m--)
+ int m= (*(int *)arg)/2, ok= 0;
+ GCC_BUG_WORKAROUND int32 x, y;
+ for (x= ((int)(intptr)(&m)); m ; m--)
{
my_atomic_rwlock_wrlock(&rwl);
- y=my_atomic_load32(&a32);
+ y= my_atomic_load32(&bad);
my_atomic_rwlock_wrunlock(&rwl);
-
- x=x*m+0x87654321;
+ x= (x*m+0x87654321) & INT_MAX32;
do {
my_atomic_rwlock_wrlock(&rwl);
- ok=my_atomic_cas32(&a32, &y, y+x);
+ ok= my_atomic_cas32(&bad, &y, (uint32)y+x);
my_atomic_rwlock_wrunlock(&rwl);
- } while (!ok);
+ } while (!ok) ;
do {
my_atomic_rwlock_wrlock(&rwl);
- ok=my_atomic_cas32(&a32, &y, y-x);
+ ok= my_atomic_cas32(&bad, &y, y-x);
my_atomic_rwlock_wrunlock(&rwl);
- } while (!ok);
+ } while (!ok) ;
}
pthread_mutex_lock(&mutex);
- N--;
- if (!N) pthread_cond_signal(&cond);
+ if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return 0;
}
-void test_atomic(const char *test, pthread_handler handler, int n, int m)
-{
- pthread_t t;
- ulonglong now=my_getsystime();
-
- a32= 0;
- b32= 0;
- c32= 0;
-
- diag("Testing %s with %d threads, %d iterations... ", test, n, m);
- for (N=n ; n ; n--)
- {
- if (pthread_create(&t, &thr_attr, handler, &m) != 0)
- {
- diag("Could not create thread");
- a32= 1;
- goto err;
- }
- }
-
- pthread_mutex_lock(&mutex);
- while (N)
- pthread_cond_wait(&cond, &mutex);
- pthread_mutex_unlock(&mutex);
- now=my_getsystime()-now;
-err:
- ok(a32 == 0, "tested %s in %g secs", test, ((double)now)/1e7);
-}
-
-int main()
+void do_tests()
{
- int err;
- MY_INIT("my_atomic-t.c");
-
- diag("N CPUs: %d", my_getncpus());
- err= my_atomic_initialize();
-
plan(4);
- ok(err == 0, "my_atomic_initialize() returned %d", err);
- pthread_attr_init(&thr_attr);
- pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
- pthread_mutex_init(&mutex, 0);
- pthread_cond_init(&cond, 0);
+ bad= my_atomic_initialize();
+ ok(!bad, "my_atomic_initialize() returned %d", bad);
+
my_atomic_rwlock_init(&rwl);
-#ifdef HPUX11
-#define CYCLES 1000
-#else
-#define CYCLES 10000
-#endif
-#define THREADS 100
- test_atomic("my_atomic_add32", test_atomic_add_handler, THREADS, CYCLES);
- test_atomic("my_atomic_swap32", test_atomic_swap_handler, THREADS, CYCLES);
- test_atomic("my_atomic_cas32", test_atomic_cas_handler, THREADS, CYCLES);
- /*
- workaround until we know why it crashes randomly on some machine
- (BUG#22320).
- */
- sleep(2);
-
- pthread_mutex_destroy(&mutex);
- pthread_cond_destroy(&cond);
- pthread_attr_destroy(&thr_attr);
+ b32= c32= 0;
+ test_concurrently("my_atomic_add32", test_atomic_add, THREADS, CYCLES);
+ b32= c32= 0;
+ test_concurrently("my_atomic_fas32", test_atomic_fas, THREADS, CYCLES);
+ b32= c32= 0;
+ test_concurrently("my_atomic_cas32", test_atomic_cas, THREADS, CYCLES);
+
my_atomic_rwlock_destroy(&rwl);
- return exit_status();
}
diff --git a/unittest/mysys/thr_template.c b/unittest/mysys/thr_template.c
new file mode 100644
index 00000000000..1ac03e474fd
--- /dev/null
+++ b/unittest/mysys/thr_template.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_atomic.h>
+#include <tap.h>
+
+volatile uint32 bad;
+pthread_attr_t thr_attr;
+pthread_mutex_t mutex;
+pthread_cond_t cond;
+uint running_threads;
+
+void do_tests();
+
+void test_concurrently(const char *test, pthread_handler handler, int n, int m)
+{
+ pthread_t t;
+ ulonglong now= my_getsystime();
+
+ bad= 0;
+
+ diag("Testing %s with %d threads, %d iterations... ", test, n, m);
+ for (running_threads= n ; n ; n--)
+ {
+ if (pthread_create(&t, &thr_attr, handler, &m) != 0)
+ {
+ diag("Could not create thread");
+ abort();
+ }
+ }
+ pthread_mutex_lock(&mutex);
+ while (running_threads)
+ pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+
+ now= my_getsystime()-now;
+ ok(!bad, "tested %s in %g secs (%d)", test, ((double)now)/1e7, bad);
+}
+
+int main(int argc __attribute__((unused)), char **argv)
+{
+ MY_INIT("thd_template");
+
+ if (argv[1] && *argv[1])
+ DBUG_SET_INITIAL(argv[1]);
+
+ pthread_mutex_init(&mutex, 0);
+ pthread_cond_init(&cond, 0);
+ pthread_attr_init(&thr_attr);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+
+#ifdef MY_ATOMIC_MODE_RWLOCKS
+#if defined(HPUX11) || defined(__POWERPC__) /* showed to be very slow (scheduler-related) */
+#define CYCLES 300
+#else
+#define CYCLES 3000
+#endif
+#else
+#define CYCLES 3000
+#endif
+#define THREADS 30
+
+ diag("N CPUs: %d, atomic ops: %s", my_getncpus(), MY_ATOMIC_MODE);
+
+ do_tests();
+
+ /*
+ workaround until we know why it crashes randomly on some machine
+ (BUG#22320).
+ */
+ sleep(2);
+ pthread_mutex_destroy(&mutex);
+ pthread_cond_destroy(&cond);
+ pthread_attr_destroy(&thr_attr);
+ my_end(0);
+ return exit_status();
+}
+
diff --git a/unittest/mysys/waiting_threads-t.c b/unittest/mysys/waiting_threads-t.c
new file mode 100644
index 00000000000..74c18fda7b9
--- /dev/null
+++ b/unittest/mysys/waiting_threads-t.c
@@ -0,0 +1,273 @@
+/* Copyright (C) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "thr_template.c"
+#include <waiting_threads.h>
+#include <m_string.h>
+
+struct test_wt_thd {
+ WT_THD thd;
+ pthread_mutex_t lock;
+} thds[THREADS];
+
+uint i, cnt;
+pthread_mutex_t lock;
+
+ulong wt_timeout_short=100, wt_deadlock_search_depth_short=4;
+ulong wt_timeout_long=10000, wt_deadlock_search_depth_long=15;
+
+#define reset(ARRAY) bzero(ARRAY, sizeof(ARRAY))
+
+/* see explanation of the kill strategies in waiting_threads.h */
+enum { LATEST, RANDOM, YOUNGEST, LOCKS } kill_strategy;
+
+WT_RESOURCE_TYPE restype={ wt_resource_id_memcmp, 0};
+
+#define rnd() ((uint)(my_rnd(&rand) * INT_MAX32))
+
+/*
+ stress test: wait on a random number of random threads.
+ it always succeeds (unless crashes or hangs).
+*/
+pthread_handler_t test_wt(void *arg)
+{
+ int m, n, i, id, res;
+ struct my_rnd_struct rand;
+
+ my_thread_init();
+
+ pthread_mutex_lock(&lock);
+ id= cnt++;
+ pthread_mutex_unlock(&lock);
+
+ my_rnd_init(&rand, (ulong)(intptr)&m, id);
+ if (kill_strategy == YOUNGEST)
+ thds[id].thd.weight= (ulong)~my_getsystime();
+ if (kill_strategy == LOCKS)
+ thds[id].thd.weight= 0;
+
+ for (m= *(int *)arg; m ; m--)
+ {
+ WT_RESOURCE_ID resid;
+ int blockers[THREADS/10], j, k;
+
+ resid.value= id;
+ resid.type= &restype;
+
+ res= 0;
+
+ /* prepare for waiting for a random number of random threads */
+ for (j= n= (rnd() % THREADS)/10; !res && j >= 0; j--)
+ {
+retry:
+ i= rnd() % (THREADS-1); /* pick a random thread */
+ if (i >= id) i++; /* with a number from 0 to THREADS-1 excluding ours */
+
+ for (k=n; k >=j; k--) /* the one we didn't pick before */
+ if (blockers[k] == i)
+ goto retry;
+ blockers[j]= i;
+
+ if (kill_strategy == RANDOM)
+ thds[id].thd.weight= rnd();
+
+ pthread_mutex_lock(& thds[i].lock);
+ res= wt_thd_will_wait_for(& thds[id].thd, & thds[i].thd, &resid);
+ pthread_mutex_unlock(& thds[i].lock);
+ }
+
+ if (!res)
+ {
+ pthread_mutex_lock(&lock);
+ res= wt_thd_cond_timedwait(& thds[id].thd, &lock);
+ pthread_mutex_unlock(&lock);
+ }
+
+ if (res)
+ {
+ pthread_mutex_lock(& thds[id].lock);
+ pthread_mutex_lock(&lock);
+ wt_thd_release_all(& thds[id].thd);
+ pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(& thds[id].lock);
+ if (kill_strategy == LOCKS)
+ thds[id].thd.weight= 0;
+ if (kill_strategy == YOUNGEST)
+ thds[id].thd.weight= (ulong)~my_getsystime();
+ }
+ else if (kill_strategy == LOCKS)
+ thds[id].thd.weight++;
+ }
+
+ pthread_mutex_lock(& thds[id].lock);
+ pthread_mutex_lock(&lock);
+ wt_thd_release_all(& thds[id].thd);
+ pthread_mutex_unlock(&lock);
+ pthread_mutex_unlock(& thds[id].lock);
+
+#ifndef DBUG_OFF
+ {
+#define DEL "(deleted)"
+ char *x=malloc(strlen(thds[id].thd.name)+sizeof(DEL)+1);
+ strxmov(x, thds[id].thd.name, DEL, 0);
+ thds[id].thd.name=x;
+ }
+#endif
+
+ pthread_mutex_lock(&mutex);
+ if (!--running_threads) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ DBUG_PRINT("wt", ("exiting"));
+ my_thread_end();
+ return 0;
+}
+
+void do_one_test()
+{
+ double sum, sum0;
+
+ reset(wt_cycle_stats);
+ reset(wt_wait_stats);
+ wt_success_stats=0;
+ cnt=0;
+ test_concurrently("waiting_threads", test_wt, THREADS, CYCLES);
+
+ sum=sum0=0;
+ for (cnt=0; cnt < WT_CYCLE_STATS; cnt++)
+ sum+= wt_cycle_stats[0][cnt] + wt_cycle_stats[1][cnt];
+ for (cnt=0; cnt < WT_CYCLE_STATS; cnt++)
+ if (wt_cycle_stats[0][cnt] + wt_cycle_stats[1][cnt] > 0)
+ {
+ sum0+=wt_cycle_stats[0][cnt] + wt_cycle_stats[1][cnt];
+ diag("deadlock cycles of length %2u: %4u %4u %8.2f %%", cnt,
+ wt_cycle_stats[0][cnt], wt_cycle_stats[1][cnt], 1e2*sum0/sum);
+ }
+ diag("depth exceeded: %u %u",
+ wt_cycle_stats[0][cnt], wt_cycle_stats[1][cnt]);
+ for (cnt=0; cnt < WT_WAIT_STATS; cnt++)
+ if (wt_wait_stats[cnt]>0)
+ diag("deadlock waits up to %7llu us: %5u",
+ wt_wait_table[cnt], wt_wait_stats[cnt]);
+ diag("timed out: %u", wt_wait_stats[cnt]);
+ diag("successes: %u", wt_success_stats);
+}
+
+void do_tests()
+{
+ plan(14);
+ compile_time_assert(THREADS >= 4);
+
+ DBUG_PRINT("wt", ("================= initialization ==================="));
+
+ bad= my_atomic_initialize();
+ ok(!bad, "my_atomic_initialize() returned %d", bad);
+
+ pthread_mutex_init(&lock, 0);
+ wt_init();
+ for (cnt=0; cnt < THREADS; cnt++)
+ {
+ wt_thd_lazy_init(& thds[cnt].thd,
+ & wt_deadlock_search_depth_short, & wt_timeout_short,
+ & wt_deadlock_search_depth_long, & wt_timeout_long);
+ pthread_mutex_init(& thds[cnt].lock, 0);
+ }
+ {
+ WT_RESOURCE_ID resid[3];
+ for (i=0; i < 3; i++)
+ {
+ resid[i].value= i+1;
+ resid[i].type= &restype;
+ }
+
+ DBUG_PRINT("wt", ("================= manual test ==================="));
+
+#define ok_wait(X,Y, R) \
+ ok(wt_thd_will_wait_for(& thds[X].thd, & thds[Y].thd, &resid[R]) == 0, \
+ "thd[" #X "] will wait for thd[" #Y "]")
+#define ok_deadlock(X,Y,R) \
+ ok(wt_thd_will_wait_for(& thds[X].thd, & thds[Y].thd, &resid[R]) == WT_DEADLOCK, \
+ "thd[" #X "] will wait for thd[" #Y "] - deadlock")
+
+ ok_wait(0,1,0);
+ ok_wait(0,2,0);
+ ok_wait(0,3,0);
+
+ pthread_mutex_lock(&lock);
+ bad= wt_thd_cond_timedwait(& thds[0].thd, &lock);
+ pthread_mutex_unlock(&lock);
+ ok(bad == WT_TIMEOUT, "timeout test returned %d", bad);
+
+ ok_wait(0,1,0);
+ ok_wait(1,2,1);
+ ok_deadlock(2,0,2);
+
+ pthread_mutex_lock(&lock);
+ ok(wt_thd_cond_timedwait(& thds[0].thd, &lock) == WT_TIMEOUT, "as always");
+ ok(wt_thd_cond_timedwait(& thds[1].thd, &lock) == WT_TIMEOUT, "as always");
+ wt_thd_release_all(& thds[0].thd);
+ wt_thd_release_all(& thds[1].thd);
+ wt_thd_release_all(& thds[2].thd);
+ wt_thd_release_all(& thds[3].thd);
+ pthread_mutex_unlock(&lock);
+
+ for (cnt=0; cnt < 4; cnt++)
+ {
+ wt_thd_destroy(& thds[cnt].thd);
+ wt_thd_lazy_init(& thds[cnt].thd,
+ & wt_deadlock_search_depth_short, & wt_timeout_short,
+ & wt_deadlock_search_depth_long, & wt_timeout_long);
+ }
+ }
+
+ wt_deadlock_search_depth_short=6;
+ wt_timeout_short=1000;
+ wt_timeout_long= 100;
+ wt_deadlock_search_depth_long=16;
+ DBUG_PRINT("wt", ("================= stress test ==================="));
+
+ diag("timeout_short=%lu us, deadlock_search_depth_short=%lu",
+ wt_timeout_short, wt_deadlock_search_depth_short);
+ diag("timeout_long=%lu us, deadlock_search_depth_long=%lu",
+ wt_timeout_long, wt_deadlock_search_depth_long);
+
+#define test_kill_strategy(X) \
+ diag("kill strategy: " #X); \
+ kill_strategy=X; \
+ do_one_test();
+
+ test_kill_strategy(LATEST);
+ SKIP_BIG_TESTS(1)
+ {
+ test_kill_strategy(RANDOM);
+ }
+ test_kill_strategy(YOUNGEST);
+ test_kill_strategy(LOCKS);
+
+ DBUG_PRINT("wt", ("================= cleanup ==================="));
+ pthread_mutex_lock(&lock);
+ for (cnt=0; cnt < THREADS; cnt++)
+ {
+ wt_thd_release_all(& thds[cnt].thd);
+ wt_thd_destroy(& thds[cnt].thd);
+ pthread_mutex_destroy(& thds[cnt].lock);
+#ifndef DBUG_OFF
+ free(thds[cnt].thd.name);
+#endif
+ }
+ pthread_mutex_unlock(&lock);
+ wt_end();
+ pthread_mutex_destroy(&lock);
+}
+
diff --git a/unittest/mytap/CMakeLists.txt b/unittest/mytap/CMakeLists.txt
new file mode 100644
index 00000000000..2c0893226fa
--- /dev/null
+++ b/unittest/mytap/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (C) 2007 MySQL AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
+ADD_LIBRARY(mytap tap.c)
diff --git a/unittest/mytap/Makefile.am b/unittest/mytap/Makefile.am
index c02bcd3b49d..8feefb134bb 100644
--- a/unittest/mytap/Makefile.am
+++ b/unittest/mytap/Makefile.am
@@ -20,6 +20,8 @@ noinst_HEADERS = tap.h
libmytap_a_SOURCES = tap.c
+EXTRA_DIST = CMakeLists.txt
+
SUBDIRS = . t
# Don't update the files from bitkeeper
diff --git a/unittest/mytap/tap.c b/unittest/mytap/tap.c
index 4e053e3e745..a7552b15eed 100644
--- a/unittest/mytap/tap.c
+++ b/unittest/mytap/tap.c
@@ -19,7 +19,7 @@
#include "tap.h"
-#include "my_config.h"
+#include "my_global.h"
#include <stdlib.h>
#include <stdarg.h>
@@ -27,6 +27,16 @@
#include <string.h>
#include <signal.h>
+/*
+ Visual Studio 2003 does not know vsnprintf but knows _vsnprintf.
+ We don't put this #define in config-win.h because we prefer
+ my_vsnprintf everywhere instead, except when linking with libmysys
+ is not desirable - the case here.
+*/
+#if defined(_MSC_VER) && ( _MSC_VER == 1310 )
+#define vsnprintf _vsnprintf
+#endif
+
/**
@defgroup MyTAP_Internal MyTAP Internals
@@ -150,8 +160,10 @@ static signal_entry install_signal[]= {
{ SIGILL, handle_core_signal },
{ SIGABRT, handle_core_signal },
{ SIGFPE, handle_core_signal },
- { SIGSEGV, handle_core_signal },
- { SIGBUS, handle_core_signal }
+ { SIGSEGV, handle_core_signal }
+#ifdef SIGBUS
+ , { SIGBUS, handle_core_signal }
+#endif
#ifdef SIGXCPU
, { SIGXCPU, handle_core_signal }
#endif
@@ -166,13 +178,22 @@ static signal_entry install_signal[]= {
#endif
};
+int skip_big_tests= 1;
+
void
-plan(int const count)
+plan(int count)
{
+ char *config= getenv("MYTAP_CONFIG");
+ size_t i;
+
+ if (config)
+ skip_big_tests= strcmp(config, "big");
+
+ setvbuf(tapout, 0, _IONBF, 0); /* provide output at once */
/*
Install signal handler
*/
- size_t i;
+
for (i= 0; i < sizeof(install_signal)/sizeof(*install_signal); ++i)
signal(install_signal[i].signo, install_signal[i].handler);
@@ -201,7 +222,7 @@ skip_all(char const *reason, ...)
}
void
-ok(int const pass, char const *fmt, ...)
+ok(int pass, char const *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@@ -218,7 +239,7 @@ ok(int const pass, char const *fmt, ...)
void
-skip(int how_many, char const *const fmt, ...)
+skip(int how_many, char const *fmt, ...)
{
char reason[80];
if (fmt && *fmt)
diff --git a/unittest/mytap/tap.h b/unittest/mytap/tap.h
index 31ec47d1ef2..f92fad1101f 100644
--- a/unittest/mytap/tap.h
+++ b/unittest/mytap/tap.h
@@ -62,6 +62,24 @@ extern "C" {
#endif
/**
+ Defines whether "big" tests should be skipped.
+
+ This variable is set by plan() function unless MYTAP_CONFIG environment
+ variable is set to the string "big". It is supposed to be used as
+
+ @code
+ if (skip_big_tests) {
+ skip(1, "Big test skipped");
+ } else {
+ ok(life_universe_and_everything() == 42, "The answer is CORRECT");
+ }
+ @endcode
+
+ @see SKIP_BIG_TESTS
+*/
+extern int skip_big_tests;
+
+/**
@defgroup MyTAP_API MyTAP API
MySQL support for performing unit tests according to TAP.
@@ -81,7 +99,12 @@ extern "C" {
that generate a core, so if you want to override these signals, do
it <em>after</em> you have called the plan() function.
- @param count The planned number of tests to run.
+ It will also set skip_big_tests variable if MYTAP_CONFIG environment
+ variable is defined.
+
+ @see skip_big_tests
+
+ @param count The planned number of tests to run.
*/
void plan(int count);
@@ -161,6 +184,24 @@ void skip(int how_many, char const *reason, ...)
/**
+ Helper macro to skip a group of "big" tests. It is used in the following
+ manner:
+
+ @code
+ SKIP_BIG_TESTS(1)
+ {
+ ok(life_universe_and_everything() == 42, "The answer is CORRECT");
+ }
+ @endcode
+
+ @see skip_big_tests
+ */
+
+#define SKIP_BIG_TESTS(COUNT) \
+ if (skip_big_tests) skip((COUNT), "big test"); else
+
+
+/**
Print a diagnostics message.
@param fmt Diagnostics message in printf() format.
diff --git a/unittest/unit.pl b/unittest/unit.pl
index 9d328985012..a1aab376fdf 100644
--- a/unittest/unit.pl
+++ b/unittest/unit.pl
@@ -14,8 +14,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-use Test::Harness qw(&runtests $verbose);
+use Test::Harness;
use File::Find;
+use Getopt::Long;
use strict;
@@ -31,10 +32,19 @@ unit - Run unit tests in directory
=head1 SYNOPSIS
- unit run
+ unit [--[no]big] [--[no]verbose] run [tests to run]
=cut
+my $big= $ENV{'MYTAP_CONFIG'} eq 'big';
+
+my $result = GetOptions (
+ "big!" => \$big,
+ "verbose!" => \$Test::Harness::verbose,
+);
+
+$ENV{'MYTAP_CONFIG'} = $big ? 'big' : '';
+
my $cmd = shift;
if (defined $cmd && exists $dispatch{$cmd}) {
@@ -56,7 +66,7 @@ sub _find_test_files (@) {
my @files;
find sub {
$File::Find::prune = 1 if /^SCCS$/;
- push(@files, $File::Find::name) if -x _ && /-t\z/;
+ push(@files, $File::Find::name) if -x _ && (/-t\z/ || /-t\.exe\z/);
}, @dirs;
return @files;
}
@@ -92,7 +102,7 @@ sub run_cmd (@) {
if (@files > 0) {
# Removing the first './' from the file names
foreach (@files) { s!^\./!! }
- $ENV{'HARNESS_PERL_SWITCHES'} .= q" -e 'exec @ARGV'";
+ $ENV{'HARNESS_PERL_SWITCHES'} .= ' -e "exec @ARGV"';
runtests @files;
}
}
diff --git a/win/configure.js b/win/configure.js
index ac51b15b9f0..9aa7c881d4d 100644
--- a/win/configure.js
+++ b/win/configure.js
@@ -32,6 +32,7 @@ try
var default_comment = "Source distribution";
var default_port = GetValue(configureIn, "MYSQL_TCP_PORT_DEFAULT");
var actual_port = 0;
+ var with_maria_tmp_tables = -1;
var configfile = fso.CreateTextFile("win\\configure.data", true);
for (i=0; i < args.Count(); i++)
@@ -52,6 +53,17 @@ try
case "WITH_EMBEDDED_SERVER":
configfile.WriteLine("SET (" + args.Item(i) + " TRUE)");
break;
+ case "WITH_MARIA_STORAGE_ENGINE":
+ configfile.WriteLine("SET (" + args.Item(i) + " TRUE)");
+ if(with_maria_tmp_tables == -1)
+ {
+ with_maria_tmp_tables = 1;
+ }
+ break;
+ case "WITH_MARIA_TMP_TABLES":
+ with_maria_tmp_tables = ( parts.length == 1 ||
+ parts[1] == "YES" || parts[1] == "TRUE");
+ break;
case "MYSQL_SERVER_SUFFIX":
case "MYSQLD_EXE_SUFFIX":
configfile.WriteLine("SET (" + parts[0] + " \""
@@ -65,6 +77,10 @@ try
break;
}
}
+ if (with_maria_tmp_tables == 1)
+ {
+ configfile.WriteLine("SET (WITH_MARIA_TMP_TABLES TRUE)");
+ }
if (actual_port == 0)
{
// if we actually defaulted (as opposed to the pathological case of